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