1/* 2 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6#include "MimeSnifferAddonManager.h" 7 8#include <new> 9 10#include <Autolock.h> 11#include <MimeType.h> 12 13#include "MimeSnifferAddon.h" 14 15using std::nothrow; 16 17 18// singleton instance 19MimeSnifferAddonManager* MimeSnifferAddonManager::sManager = NULL; 20 21 22// AddonReference 23struct MimeSnifferAddonManager::AddonReference { 24 AddonReference(BMimeSnifferAddon* addon) 25 : fAddon(addon), 26 fReferenceCount(1) 27 { 28 } 29 30 ~AddonReference() 31 { 32 delete fAddon; 33 } 34 35 BMimeSnifferAddon* Addon() const 36 { 37 return fAddon; 38 } 39 40 void GetReference() 41 { 42 atomic_add(&fReferenceCount, 1); 43 } 44 45 void PutReference() 46 { 47 if (atomic_add(&fReferenceCount, -1) == 1) 48 delete this; 49 } 50 51private: 52 BMimeSnifferAddon* fAddon; 53 vint32 fReferenceCount; 54}; 55 56 57// constructor 58MimeSnifferAddonManager::MimeSnifferAddonManager() 59 : fLock("mime sniffer manager"), 60 fAddons(20), 61 fMinimalBufferSize(0) 62{ 63} 64 65// destructor 66MimeSnifferAddonManager::~MimeSnifferAddonManager() 67{ 68} 69 70// Default 71MimeSnifferAddonManager* 72MimeSnifferAddonManager::Default() 73{ 74 return sManager; 75} 76 77// CreateDefault 78status_t 79MimeSnifferAddonManager::CreateDefault() 80{ 81 MimeSnifferAddonManager* manager = new(nothrow) MimeSnifferAddonManager; 82 if (!manager) 83 return B_NO_MEMORY; 84 85 sManager = manager; 86 87 return B_OK; 88} 89 90// DeleteDefault 91void 92MimeSnifferAddonManager::DeleteDefault() 93{ 94 MimeSnifferAddonManager* manager = sManager; 95 sManager = NULL; 96 97 delete manager; 98} 99 100// AddMimeSnifferAddon 101status_t 102MimeSnifferAddonManager::AddMimeSnifferAddon(BMimeSnifferAddon* addon) 103{ 104 if (!addon) 105 return B_BAD_VALUE; 106 107 BAutolock locker(fLock); 108 if (!locker.IsLocked()) 109 return B_ERROR; 110 111 // create a reference for the addon 112 AddonReference* reference = new(nothrow) AddonReference(addon); 113 if (!reference) 114 return B_NO_MEMORY; 115 116 // add the reference 117 if (!fAddons.AddItem(reference)) { 118 delete reference; 119 return B_NO_MEMORY; 120 } 121 122 // update minimal buffer size 123 size_t minBufferSize = addon->MinimalBufferSize(); 124 if (minBufferSize > fMinimalBufferSize) 125 fMinimalBufferSize = minBufferSize; 126 127 return B_OK; 128} 129 130// MinimalBufferSize 131size_t 132MimeSnifferAddonManager::MinimalBufferSize() 133{ 134 return fMinimalBufferSize; 135} 136 137// GuessMimeType 138float 139MimeSnifferAddonManager::GuessMimeType(const char* fileName, BMimeType* type) 140{ 141 // get addons 142 AddonReference** addons = NULL; 143 int32 count = 0; 144 status_t error = _GetAddons(addons, count); 145 if (error != B_OK) 146 return -1; 147 148 // iterate over the addons and find the most fitting type 149 float bestPriority = -1; 150 for (int32 i = 0; i < count; i++) { 151 BMimeType currentType; 152 float priority = addons[i]->Addon()->GuessMimeType(fileName, 153 ¤tType); 154 if (priority > bestPriority) { 155 type->SetTo(currentType.Type()); 156 bestPriority = priority; 157 } 158 } 159 160 // release addons 161 _PutAddons(addons, count); 162 163 return bestPriority; 164} 165 166// GuessMimeType 167float 168MimeSnifferAddonManager::GuessMimeType(BFile* file, const void* buffer, 169 int32 length, BMimeType* type) 170{ 171 // get addons 172 AddonReference** addons = NULL; 173 int32 count = 0; 174 status_t error = _GetAddons(addons, count); 175 if (error != B_OK) 176 return -1; 177 178 // iterate over the addons and find the most fitting type 179 float bestPriority = -1; 180 for (int32 i = 0; i < count; i++) { 181 BMimeType currentType; 182 float priority = addons[i]->Addon()->GuessMimeType(file, buffer, 183 length, ¤tType); 184 if (priority > bestPriority) { 185 type->SetTo(currentType.Type()); 186 bestPriority = priority; 187 } 188 } 189 190 // release addons 191 _PutAddons(addons, count); 192 193 return bestPriority; 194} 195 196// _GetAddons 197status_t 198MimeSnifferAddonManager::_GetAddons(AddonReference**& references, int32& count) 199{ 200 BAutolock locker(fLock); 201 if (!locker.IsLocked()) 202 return B_ERROR; 203 204 count = fAddons.CountItems(); 205 references = new(nothrow) AddonReference*[count]; 206 if (!references) 207 return B_NO_MEMORY; 208 209 for (int32 i = 0; i < count; i++) { 210 references[i] = (AddonReference*)fAddons.ItemAt(i); 211 references[i]->GetReference(); 212 } 213 214 return B_OK; 215} 216 217// _PutAddons 218void 219MimeSnifferAddonManager::_PutAddons(AddonReference** references, int32 count) 220{ 221 for (int32 i = 0; i < count; i++) 222 references[i]->PutReference(); 223 224 delete[] references; 225} 226