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