* Copyright 2006-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <mime/MimeSnifferAddonManager.h>
#include <new>
#include <Autolock.h>
#include <MimeType.h>
#include <MimeSnifferAddon.h>
namespace BPrivate {
namespace Storage {
namespace Mime {
MimeSnifferAddonManager* MimeSnifferAddonManager::sManager = NULL;
struct MimeSnifferAddonManager::AddonReference {
AddonReference(BMimeSnifferAddon* addon)
: fAddon(addon),
fReferenceCount(1)
{
}
~AddonReference()
{
delete fAddon;
}
BMimeSnifferAddon* Addon() const
{
return fAddon;
}
void GetReference()
{
atomic_add(&fReferenceCount, 1);
}
void PutReference()
{
if (atomic_add(&fReferenceCount, -1) == 1)
delete this;
}
private:
BMimeSnifferAddon* fAddon;
int32 fReferenceCount;
};
MimeSnifferAddonManager::MimeSnifferAddonManager()
: fLock("mime sniffer manager"),
fAddons(20),
fMinimalBufferSize(0)
{
}
MimeSnifferAddonManager::~MimeSnifferAddonManager()
{
}
MimeSnifferAddonManager*
MimeSnifferAddonManager::Default()
{
return sManager;
}
status_t
MimeSnifferAddonManager::CreateDefault()
{
MimeSnifferAddonManager* manager
= new(std::nothrow) MimeSnifferAddonManager;
if (!manager)
return B_NO_MEMORY;
sManager = manager;
return B_OK;
}
void
MimeSnifferAddonManager::DeleteDefault()
{
MimeSnifferAddonManager* manager = sManager;
sManager = NULL;
delete manager;
}
status_t
MimeSnifferAddonManager::AddMimeSnifferAddon(BMimeSnifferAddon* addon)
{
if (!addon)
return B_BAD_VALUE;
BAutolock locker(fLock);
if (!locker.IsLocked())
return B_ERROR;
AddonReference* reference = new(std::nothrow) AddonReference(addon);
if (!reference)
return B_NO_MEMORY;
if (!fAddons.AddItem(reference)) {
delete reference;
return B_NO_MEMORY;
}
size_t minBufferSize = addon->MinimalBufferSize();
if (minBufferSize > fMinimalBufferSize)
fMinimalBufferSize = minBufferSize;
return B_OK;
}
size_t
MimeSnifferAddonManager::MinimalBufferSize()
{
return fMinimalBufferSize;
}
float
MimeSnifferAddonManager::GuessMimeType(const char* fileName, BMimeType* type)
{
AddonReference** addons = NULL;
int32 count = 0;
status_t error = _GetAddons(addons, count);
if (error != B_OK)
return -1;
float bestPriority = -1;
for (int32 i = 0; i < count; i++) {
BMimeType currentType;
float priority = addons[i]->Addon()->GuessMimeType(fileName,
¤tType);
if (priority > bestPriority) {
type->SetTo(currentType.Type());
bestPriority = priority;
}
}
_PutAddons(addons, count);
return bestPriority;
}
float
MimeSnifferAddonManager::GuessMimeType(BFile* file, const void* buffer,
int32 length, BMimeType* type)
{
AddonReference** addons = NULL;
int32 count = 0;
status_t error = _GetAddons(addons, count);
if (error != B_OK)
return -1;
float bestPriority = -1;
for (int32 i = 0; i < count; i++) {
BMimeType currentType;
float priority = addons[i]->Addon()->GuessMimeType(file, buffer,
length, ¤tType);
if (priority > bestPriority) {
type->SetTo(currentType.Type());
bestPriority = priority;
}
}
_PutAddons(addons, count);
return bestPriority;
}
status_t
MimeSnifferAddonManager::_GetAddons(AddonReference**& references, int32& count)
{
BAutolock locker(fLock);
if (!locker.IsLocked())
return B_ERROR;
count = fAddons.CountItems();
references = new(std::nothrow) AddonReference*[count];
if (!references)
return B_NO_MEMORY;
for (int32 i = 0; i < count; i++) {
references[i] = (AddonReference*)fAddons.ItemAt(i);
references[i]->GetReference();
}
return B_OK;
}
void
MimeSnifferAddonManager::_PutAddons(AddonReference** references, int32 count)
{
for (int32 i = 0; i < count; i++)
references[i]->PutReference();
delete[] references;
}
}
}
}