xref: /haiku/src/kits/storage/mime/MimeSnifferAddonManager.cpp (revision d0f2d8282f3f59a1af7fe2d340d2af0cb36a9b20)
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 			&currentType);
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, &currentType);
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