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 {
AddonReferenceBPrivate::Storage::Mime::MimeSnifferAddonManager::AddonReference28 AddonReference(BMimeSnifferAddon* addon)
29 : fAddon(addon),
30 fReferenceCount(1)
31 {
32 }
33
~AddonReferenceBPrivate::Storage::Mime::MimeSnifferAddonManager::AddonReference34 ~AddonReference()
35 {
36 delete fAddon;
37 }
38
AddonBPrivate::Storage::Mime::MimeSnifferAddonManager::AddonReference39 BMimeSnifferAddon* Addon() const
40 {
41 return fAddon;
42 }
43
GetReferenceBPrivate::Storage::Mime::MimeSnifferAddonManager::AddonReference44 void GetReference()
45 {
46 atomic_add(&fReferenceCount, 1);
47 }
48
PutReferenceBPrivate::Storage::Mime::MimeSnifferAddonManager::AddonReference49 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
MimeSnifferAddonManager()62 MimeSnifferAddonManager::MimeSnifferAddonManager()
63 : fLock("mime sniffer manager"),
64 fAddons(20),
65 fMinimalBufferSize(0)
66 {
67 }
68
69 // destructor
~MimeSnifferAddonManager()70 MimeSnifferAddonManager::~MimeSnifferAddonManager()
71 {
72 }
73
74 // Default
75 MimeSnifferAddonManager*
Default()76 MimeSnifferAddonManager::Default()
77 {
78 return sManager;
79 }
80
81 // CreateDefault
82 status_t
CreateDefault()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
DeleteDefault()97 MimeSnifferAddonManager::DeleteDefault()
98 {
99 MimeSnifferAddonManager* manager = sManager;
100 sManager = NULL;
101
102 delete manager;
103 }
104
105 // AddMimeSnifferAddon
106 status_t
AddMimeSnifferAddon(BMimeSnifferAddon * addon)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
MinimalBufferSize()137 MimeSnifferAddonManager::MinimalBufferSize()
138 {
139 return fMinimalBufferSize;
140 }
141
142 // GuessMimeType
143 float
GuessMimeType(const char * fileName,BMimeType * type)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
GuessMimeType(BFile * file,const void * buffer,int32 length,BMimeType * type)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
_GetAddons(AddonReference ** & references,int32 & count)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
_PutAddons(AddonReference ** references,int32 count)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