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