Add SetSupportedTypes() and SetIcon[ForType]() versions with an additional bool updateMimeDB parameter. If false, the method doesn't update the MIME DB entries for the type.
1146 lines
26 KiB
C++
1146 lines
26 KiB
C++
/*
|
|
* Copyright 2002-2014, Haiku, Inc.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Ingo Weinhold, [email protected]
|
|
*/
|
|
|
|
|
|
#include <new>
|
|
#include <set>
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
|
|
#include <AppFileInfo.h>
|
|
#include <Bitmap.h>
|
|
#include <File.h>
|
|
#include <fs_attr.h>
|
|
#include <IconUtils.h>
|
|
#include <MimeType.h>
|
|
#include <RegistrarDefs.h>
|
|
#include <Resources.h>
|
|
#include <Roster.h>
|
|
#include <String.h>
|
|
|
|
|
|
// debugging
|
|
//#define DBG(x) x
|
|
#define DBG(x)
|
|
#define OUT printf
|
|
|
|
|
|
// type codes
|
|
enum {
|
|
B_APP_FLAGS_TYPE = 'APPF',
|
|
B_VERSION_INFO_TYPE = 'APPV',
|
|
};
|
|
|
|
|
|
// attributes
|
|
static const char* kTypeAttribute = "BEOS:TYPE";
|
|
static const char* kSignatureAttribute = "BEOS:APP_SIG";
|
|
static const char* kAppFlagsAttribute = "BEOS:APP_FLAGS";
|
|
static const char* kSupportedTypesAttribute = "BEOS:FILE_TYPES";
|
|
static const char* kVersionInfoAttribute = "BEOS:APP_VERSION";
|
|
static const char* kMiniIconAttribute = "BEOS:M:";
|
|
static const char* kLargeIconAttribute = "BEOS:L:";
|
|
static const char* kIconAttribute = "BEOS:";
|
|
static const char* kStandardIconType = "STD_ICON";
|
|
static const char* kIconType = "ICON";
|
|
static const char* kCatalogEntryAttribute = "SYS:NAME";
|
|
|
|
// resource IDs
|
|
static const int32 kTypeResourceID = 2;
|
|
static const int32 kSignatureResourceID = 1;
|
|
static const int32 kAppFlagsResourceID = 1;
|
|
static const int32 kSupportedTypesResourceID = 1;
|
|
static const int32 kMiniIconResourceID = 101;
|
|
static const int32 kLargeIconResourceID = 101;
|
|
static const int32 kIconResourceID = 101;
|
|
static const int32 kVersionInfoResourceID = 1;
|
|
static const int32 kMiniIconForTypeResourceID = 0;
|
|
static const int32 kLargeIconForTypeResourceID = 0;
|
|
static const int32 kIconForTypeResourceID = 0;
|
|
static const int32 kCatalogEntryResourceID = 1;
|
|
|
|
// R5 also exports these (Tracker is using them):
|
|
// (maybe we better want to drop them silently and declare
|
|
// the above in a public Haiku header - and use that one in
|
|
// Tracker when compiled for Haiku)
|
|
extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE;
|
|
const uint32 MINI_ICON_TYPE = 'MICN';
|
|
const uint32 LARGE_ICON_TYPE = 'ICON';
|
|
|
|
|
|
BAppFileInfo::BAppFileInfo()
|
|
:
|
|
fResources(NULL),
|
|
fWhere(B_USE_BOTH_LOCATIONS)
|
|
{
|
|
}
|
|
|
|
|
|
BAppFileInfo::BAppFileInfo(BFile* file)
|
|
:
|
|
fResources(NULL),
|
|
fWhere(B_USE_BOTH_LOCATIONS)
|
|
{
|
|
SetTo(file);
|
|
}
|
|
|
|
|
|
BAppFileInfo::~BAppFileInfo()
|
|
{
|
|
delete fResources;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetTo(BFile* file)
|
|
{
|
|
// unset the old file
|
|
BNodeInfo::SetTo(NULL);
|
|
if (fResources) {
|
|
delete fResources;
|
|
fResources = NULL;
|
|
}
|
|
|
|
// check param
|
|
status_t error
|
|
= file != NULL && file->InitCheck() == B_OK ? B_OK : B_BAD_VALUE;
|
|
|
|
info_location where = B_USE_BOTH_LOCATIONS;
|
|
|
|
// create resources
|
|
if (error == B_OK) {
|
|
fResources = new(std::nothrow) BResources();
|
|
if (fResources) {
|
|
error = fResources->SetTo(file);
|
|
if (error != B_OK) {
|
|
// no resources - this is no critical error, we'll just use
|
|
// attributes only, then
|
|
where = B_USE_ATTRIBUTES;
|
|
error = B_OK;
|
|
}
|
|
} else
|
|
error = B_NO_MEMORY;
|
|
}
|
|
|
|
// set node info
|
|
if (error == B_OK)
|
|
error = BNodeInfo::SetTo(file);
|
|
|
|
if (error != B_OK || (where & B_USE_RESOURCES) == 0) {
|
|
delete fResources;
|
|
fResources = NULL;
|
|
}
|
|
|
|
// clean up on error
|
|
if (error != B_OK) {
|
|
if (InitCheck() == B_OK)
|
|
BNodeInfo::SetTo(NULL);
|
|
}
|
|
|
|
// set data location
|
|
if (error == B_OK)
|
|
SetInfoLocation(where);
|
|
|
|
// set error
|
|
fCStatus = error;
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetType(char* type) const
|
|
{
|
|
// check param and initialization
|
|
status_t error = type != NULL ? B_OK : B_BAD_VALUE;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
// read the data
|
|
size_t read = 0;
|
|
if (error == B_OK) {
|
|
error = _ReadData(kTypeAttribute, kTypeResourceID, B_MIME_STRING_TYPE,
|
|
type, B_MIME_TYPE_LENGTH, read);
|
|
}
|
|
// check the read data -- null terminate the string
|
|
if (error == B_OK && type[read - 1] != '\0') {
|
|
if (read == B_MIME_TYPE_LENGTH)
|
|
error = B_ERROR;
|
|
else
|
|
type[read] = '\0';
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetType(const char* type)
|
|
{
|
|
// check initialization
|
|
status_t error = B_OK;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
if (error == B_OK) {
|
|
if (type != NULL) {
|
|
// check param
|
|
size_t typeLen = strlen(type);
|
|
if (error == B_OK && typeLen >= B_MIME_TYPE_LENGTH)
|
|
error = B_BAD_VALUE;
|
|
// write the data
|
|
if (error == B_OK) {
|
|
error = _WriteData(kTypeAttribute, kTypeResourceID,
|
|
B_MIME_STRING_TYPE, type, typeLen + 1);
|
|
}
|
|
} else
|
|
error = _RemoveData(kTypeAttribute, B_MIME_STRING_TYPE);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetSignature(char* signature) const
|
|
{
|
|
// check param and initialization
|
|
status_t error = (signature ? B_OK : B_BAD_VALUE);
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
// read the data
|
|
size_t read = 0;
|
|
if (error == B_OK) {
|
|
error = _ReadData(kSignatureAttribute, kSignatureResourceID,
|
|
B_MIME_STRING_TYPE, signature, B_MIME_TYPE_LENGTH, read);
|
|
}
|
|
// check the read data -- null terminate the string
|
|
if (error == B_OK && signature[read - 1] != '\0') {
|
|
if (read == B_MIME_TYPE_LENGTH)
|
|
error = B_ERROR;
|
|
else
|
|
signature[read] = '\0';
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetSignature(const char* signature)
|
|
{
|
|
// check initialization
|
|
status_t error = B_OK;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
if (error == B_OK) {
|
|
if (signature) {
|
|
// check param
|
|
size_t signatureLen = strlen(signature);
|
|
if (error == B_OK && signatureLen >= B_MIME_TYPE_LENGTH)
|
|
error = B_BAD_VALUE;
|
|
// write the data
|
|
if (error == B_OK) {
|
|
error = _WriteData(kSignatureAttribute, kSignatureResourceID,
|
|
B_MIME_STRING_TYPE, signature, signatureLen + 1);
|
|
}
|
|
} else
|
|
error = _RemoveData(kSignatureAttribute, B_MIME_STRING_TYPE);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetCatalogEntry(char* catalogEntry) const
|
|
{
|
|
if (catalogEntry == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
if (InitCheck() != B_OK)
|
|
return B_NO_INIT;
|
|
|
|
size_t read = 0;
|
|
status_t error = _ReadData(kCatalogEntryAttribute, kCatalogEntryResourceID,
|
|
B_STRING_TYPE, catalogEntry, B_MIME_TYPE_LENGTH * 3, read);
|
|
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
if (read >= B_MIME_TYPE_LENGTH * 3)
|
|
return B_ERROR;
|
|
|
|
catalogEntry[read] = '\0';
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetCatalogEntry(const char* catalogEntry)
|
|
{
|
|
if (InitCheck() != B_OK)
|
|
return B_NO_INIT;
|
|
|
|
if (catalogEntry == NULL)
|
|
return _RemoveData(kCatalogEntryAttribute, B_STRING_TYPE);
|
|
|
|
size_t nameLength = strlen(catalogEntry);
|
|
if (nameLength > B_MIME_TYPE_LENGTH * 3)
|
|
return B_BAD_VALUE;
|
|
|
|
return _WriteData(kCatalogEntryAttribute, kCatalogEntryResourceID,
|
|
B_STRING_TYPE, catalogEntry, nameLength + 1);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetAppFlags(uint32* flags) const
|
|
{
|
|
// check param and initialization
|
|
status_t error = flags != NULL ? B_OK : B_BAD_VALUE;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
// read the data
|
|
size_t read = 0;
|
|
if (error == B_OK) {
|
|
error = _ReadData(kAppFlagsAttribute, kAppFlagsResourceID,
|
|
B_APP_FLAGS_TYPE, flags, sizeof(uint32), read);
|
|
}
|
|
// check the read data
|
|
if (error == B_OK && read != sizeof(uint32))
|
|
error = B_ERROR;
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetAppFlags(uint32 flags)
|
|
{
|
|
// check initialization
|
|
status_t error = B_OK;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
if (error == B_OK) {
|
|
// write the data
|
|
error = _WriteData(kAppFlagsAttribute, kAppFlagsResourceID,
|
|
B_APP_FLAGS_TYPE, &flags, sizeof(uint32));
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::RemoveAppFlags()
|
|
{
|
|
// check initialization
|
|
status_t error = B_OK;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
if (error == B_OK) {
|
|
// remove the data
|
|
error = _RemoveData(kAppFlagsAttribute, B_APP_FLAGS_TYPE);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetSupportedTypes(BMessage* types) const
|
|
{
|
|
// check param and initialization
|
|
status_t error = types != NULL ? B_OK : B_BAD_VALUE;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
// read the data
|
|
size_t read = 0;
|
|
void* buffer = NULL;
|
|
if (error == B_OK) {
|
|
error = _ReadData(kSupportedTypesAttribute, kSupportedTypesResourceID,
|
|
B_MESSAGE_TYPE, NULL, 0, read, &buffer);
|
|
}
|
|
// unflatten the buffer
|
|
if (error == B_OK)
|
|
error = types->Unflatten((const char*)buffer);
|
|
// clean up
|
|
free(buffer);
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetSupportedTypes(const BMessage* types, bool updateMimeDB,
|
|
bool syncAll)
|
|
{
|
|
// check initialization
|
|
status_t error = B_OK;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
|
|
BMimeType mimeType;
|
|
if (error == B_OK)
|
|
error = GetMetaMime(&mimeType);
|
|
|
|
if (error == B_OK || error == B_ENTRY_NOT_FOUND) {
|
|
error = B_OK;
|
|
if (types) {
|
|
// check param -- supported types must be valid
|
|
const char* type;
|
|
for (int32 i = 0;
|
|
error == B_OK && types->FindString("types", i, &type) == B_OK;
|
|
i++) {
|
|
if (!BMimeType::IsValid(type))
|
|
error = B_BAD_VALUE;
|
|
}
|
|
|
|
// get flattened size
|
|
ssize_t size = 0;
|
|
if (error == B_OK) {
|
|
size = types->FlattenedSize();
|
|
if (size < 0)
|
|
error = size;
|
|
}
|
|
|
|
// allocate a buffer for the flattened data
|
|
char* buffer = NULL;
|
|
if (error == B_OK) {
|
|
buffer = new(std::nothrow) char[size];
|
|
if (!buffer)
|
|
error = B_NO_MEMORY;
|
|
}
|
|
|
|
// flatten the message
|
|
if (error == B_OK)
|
|
error = types->Flatten(buffer, size);
|
|
|
|
// write the data
|
|
if (error == B_OK) {
|
|
error = _WriteData(kSupportedTypesAttribute,
|
|
kSupportedTypesResourceID, B_MESSAGE_TYPE, buffer, size);
|
|
}
|
|
|
|
delete[] buffer;
|
|
} else
|
|
error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE);
|
|
|
|
// update the MIME database, if the app signature is installed
|
|
if (updateMimeDB && error == B_OK && mimeType.IsInstalled())
|
|
error = mimeType.SetSupportedTypes(types, syncAll);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll)
|
|
{
|
|
return SetSupportedTypes(types, true, syncAll);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetSupportedTypes(const BMessage* types)
|
|
{
|
|
return SetSupportedTypes(types, true, false);
|
|
}
|
|
|
|
|
|
bool
|
|
BAppFileInfo::IsSupportedType(const char* type) const
|
|
{
|
|
status_t error = type != NULL ? B_OK : B_BAD_VALUE;
|
|
// get the supported types
|
|
BMessage types;
|
|
if (error == B_OK)
|
|
error = GetSupportedTypes(&types);
|
|
// turn type into a BMimeType
|
|
BMimeType mimeType;
|
|
if (error == B_OK)
|
|
error = mimeType.SetTo(type);
|
|
// iterate through the supported types
|
|
bool found = false;
|
|
if (error == B_OK) {
|
|
const char* supportedType;
|
|
for (int32 i = 0;
|
|
!found && types.FindString("types", i, &supportedType) == B_OK;
|
|
i++) {
|
|
found = strcmp(supportedType, "application/octet-stream") == 0
|
|
|| BMimeType(supportedType).Contains(&mimeType);
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
|
|
bool
|
|
BAppFileInfo::Supports(BMimeType* type) const
|
|
{
|
|
status_t error
|
|
= type != NULL && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE;
|
|
// get the supported types
|
|
BMessage types;
|
|
if (error == B_OK)
|
|
error = GetSupportedTypes(&types);
|
|
// iterate through the supported types
|
|
bool found = false;
|
|
if (error == B_OK) {
|
|
const char* supportedType;
|
|
for (int32 i = 0;
|
|
!found && types.FindString("types", i, &supportedType) == B_OK;
|
|
i++) {
|
|
found = BMimeType(supportedType).Contains(type);
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const
|
|
{
|
|
return GetIconForType(NULL, icon, which);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetIcon(uint8** data, size_t* size) const
|
|
{
|
|
return GetIconForType(NULL, data, size);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB)
|
|
{
|
|
return SetIconForType(NULL, icon, which, updateMimeDB);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which)
|
|
{
|
|
return SetIconForType(NULL, icon, which, true);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB)
|
|
{
|
|
return SetIconForType(NULL, data, size, updateMimeDB);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIcon(const uint8* data, size_t size)
|
|
{
|
|
return SetIconForType(NULL, data, size, true);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetVersionInfo(version_info* info, version_kind kind) const
|
|
{
|
|
// check params and initialization
|
|
if (info == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
int32 index = 0;
|
|
switch (kind) {
|
|
case B_APP_VERSION_KIND:
|
|
index = 0;
|
|
break;
|
|
case B_SYSTEM_VERSION_KIND:
|
|
index = 1;
|
|
break;
|
|
default:
|
|
return B_BAD_VALUE;
|
|
}
|
|
|
|
if (InitCheck() != B_OK)
|
|
return B_NO_INIT;
|
|
|
|
// read the data
|
|
size_t read = 0;
|
|
version_info infos[2];
|
|
status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
|
|
B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// check the read data
|
|
if (read == sizeof(version_info)) {
|
|
// only the app version info is there -- return a cleared system info
|
|
if (index == 0)
|
|
*info = infos[index];
|
|
else if (index == 1)
|
|
memset(info, 0, sizeof(version_info));
|
|
} else if (read == 2 * sizeof(version_info)) {
|
|
*info = infos[index];
|
|
} else
|
|
return B_ERROR;
|
|
|
|
// return result
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind)
|
|
{
|
|
// check initialization
|
|
status_t error = B_OK;
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
if (error == B_OK) {
|
|
if (info != NULL) {
|
|
// check param
|
|
int32 index = 0;
|
|
if (error == B_OK) {
|
|
switch (kind) {
|
|
case B_APP_VERSION_KIND:
|
|
index = 0;
|
|
break;
|
|
case B_SYSTEM_VERSION_KIND:
|
|
index = 1;
|
|
break;
|
|
default:
|
|
error = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
}
|
|
// read both infos
|
|
version_info infos[2];
|
|
if (error == B_OK) {
|
|
size_t read;
|
|
if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
|
|
B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info),
|
|
read) == B_OK) {
|
|
// clear the part that hasn't been read
|
|
if (read < sizeof(infos))
|
|
memset((char*)infos + read, 0, sizeof(infos) - read);
|
|
} else {
|
|
// failed to read -- clear
|
|
memset(infos, 0, sizeof(infos));
|
|
}
|
|
}
|
|
infos[index] = *info;
|
|
// write the data
|
|
if (error == B_OK) {
|
|
error = _WriteData(kVersionInfoAttribute,
|
|
kVersionInfoResourceID, B_VERSION_INFO_TYPE, infos,
|
|
2 * sizeof(version_info));
|
|
}
|
|
} else
|
|
error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetIconForType(const char* type, BBitmap* icon, icon_size size)
|
|
const
|
|
{
|
|
if (InitCheck() != B_OK)
|
|
return B_NO_INIT;
|
|
|
|
if (icon == NULL || icon->InitCheck() != B_OK)
|
|
return B_BAD_VALUE;
|
|
|
|
// TODO: for consistency with attribute based icon reading, we
|
|
// could also prefer B_CMAP8 icons here if the provided bitmap
|
|
// is in that format. Right now, an existing B_CMAP8 icon resource
|
|
// would be ignored as soon as a vector icon is present. On the other
|
|
// hand, maybe this still results in a more consistent user interface,
|
|
// since Tracker/Deskbar would surely show the vector icon.
|
|
|
|
// try vector icon first
|
|
BString vectorAttributeName(kIconAttribute);
|
|
|
|
// check type param
|
|
if (type != NULL) {
|
|
if (BMimeType::IsValid(type))
|
|
vectorAttributeName += type;
|
|
else
|
|
return B_BAD_VALUE;
|
|
} else {
|
|
vectorAttributeName += kIconType;
|
|
}
|
|
const char* attribute = vectorAttributeName.String();
|
|
|
|
size_t bytesRead;
|
|
void* allocatedBuffer;
|
|
status_t error = _ReadData(attribute, -1, B_VECTOR_ICON_TYPE, NULL, 0,
|
|
bytesRead, &allocatedBuffer);
|
|
if (error == B_OK) {
|
|
error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer,
|
|
bytesRead, icon);
|
|
free(allocatedBuffer);
|
|
return error;
|
|
}
|
|
|
|
// no vector icon if we got this far,
|
|
// align size argument just in case
|
|
if (size < B_LARGE_ICON)
|
|
size = B_MINI_ICON;
|
|
else
|
|
size = B_LARGE_ICON;
|
|
|
|
error = B_OK;
|
|
// set some icon size related variables
|
|
BString attributeString;
|
|
BRect bounds;
|
|
uint32 attrType = 0;
|
|
size_t attrSize = 0;
|
|
switch (size) {
|
|
case B_MINI_ICON:
|
|
attributeString = kMiniIconAttribute;
|
|
bounds.Set(0, 0, 15, 15);
|
|
attrType = B_MINI_ICON_TYPE;
|
|
attrSize = 16 * 16;
|
|
break;
|
|
case B_LARGE_ICON:
|
|
attributeString = kLargeIconAttribute;
|
|
bounds.Set(0, 0, 31, 31);
|
|
attrType = B_LARGE_ICON_TYPE;
|
|
attrSize = 32 * 32;
|
|
break;
|
|
default:
|
|
return B_BAD_VALUE;
|
|
}
|
|
|
|
// compose attribute name
|
|
attributeString += type != NULL ? type : kStandardIconType;
|
|
attribute = attributeString.String();
|
|
|
|
// check parameters
|
|
// currently, scaling B_CMAP8 icons is not supported
|
|
if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds)
|
|
return B_BAD_VALUE;
|
|
|
|
// read the data
|
|
if (error == B_OK) {
|
|
bool tempBuffer
|
|
= icon->ColorSpace() != B_CMAP8 || icon->Bounds() != bounds;
|
|
uint8* buffer = NULL;
|
|
size_t read;
|
|
if (tempBuffer) {
|
|
// other color space or bitmap size than stored in attribute
|
|
buffer = new(std::nothrow) uint8[attrSize];
|
|
if (!buffer) {
|
|
error = B_NO_MEMORY;
|
|
} else {
|
|
error = _ReadData(attribute, -1, attrType, buffer, attrSize,
|
|
read);
|
|
}
|
|
} else {
|
|
error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize,
|
|
read);
|
|
}
|
|
if (error == B_OK && read != attrSize)
|
|
error = B_ERROR;
|
|
if (tempBuffer) {
|
|
// other color space than stored in attribute
|
|
if (error == B_OK) {
|
|
error = BIconUtils::ConvertFromCMAP8(buffer, (uint32)size,
|
|
(uint32)size, (uint32)size, icon);
|
|
}
|
|
delete[] buffer;
|
|
}
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetIconForType(const char* type, uint8** data, size_t* size) const
|
|
{
|
|
if (InitCheck() != B_OK)
|
|
return B_NO_INIT;
|
|
|
|
if (data == NULL || size == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
// get vector icon
|
|
BString attributeName(kIconAttribute);
|
|
|
|
// check type param
|
|
if (type != NULL) {
|
|
if (BMimeType::IsValid(type))
|
|
attributeName += type;
|
|
else
|
|
return B_BAD_VALUE;
|
|
} else
|
|
attributeName += kIconType;
|
|
|
|
void* allocatedBuffer = NULL;
|
|
status_t ret = _ReadData(attributeName.String(), -1, B_VECTOR_ICON_TYPE,
|
|
NULL, 0, *size, &allocatedBuffer);
|
|
|
|
if (ret < B_OK)
|
|
return ret;
|
|
|
|
*data = (uint8*)allocatedBuffer;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
|
|
icon_size which, bool updateMimeDB)
|
|
{
|
|
status_t error = B_OK;
|
|
|
|
// set some icon size related variables
|
|
BString attributeString;
|
|
BRect bounds;
|
|
uint32 attrType = 0;
|
|
size_t attrSize = 0;
|
|
int32 resourceID = 0;
|
|
switch (which) {
|
|
case B_MINI_ICON:
|
|
attributeString = kMiniIconAttribute;
|
|
bounds.Set(0, 0, 15, 15);
|
|
attrType = B_MINI_ICON_TYPE;
|
|
attrSize = 16 * 16;
|
|
resourceID = type != NULL
|
|
? kMiniIconForTypeResourceID : kMiniIconResourceID;
|
|
break;
|
|
case B_LARGE_ICON:
|
|
attributeString = kLargeIconAttribute;
|
|
bounds.Set(0, 0, 31, 31);
|
|
attrType = B_LARGE_ICON_TYPE;
|
|
attrSize = 32 * 32;
|
|
resourceID = type != NULL
|
|
? kLargeIconForTypeResourceID : kLargeIconResourceID;
|
|
break;
|
|
default:
|
|
error = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
// check type param
|
|
if (error == B_OK) {
|
|
if (type != NULL) {
|
|
if (BMimeType::IsValid(type))
|
|
attributeString += type;
|
|
else
|
|
error = B_BAD_VALUE;
|
|
} else
|
|
attributeString += kStandardIconType;
|
|
}
|
|
const char* attribute = attributeString.String();
|
|
|
|
// check parameter and initialization
|
|
if (error == B_OK && icon != NULL
|
|
&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
|
|
error = B_BAD_VALUE;
|
|
}
|
|
if (error == B_OK && InitCheck() != B_OK)
|
|
error = B_NO_INIT;
|
|
|
|
// write/remove the attribute
|
|
if (error == B_OK) {
|
|
if (icon != NULL) {
|
|
bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
|
|
if (otherColorSpace) {
|
|
BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
|
|
error = bitmap.InitCheck();
|
|
if (error == B_OK)
|
|
error = bitmap.ImportBits(icon);
|
|
if (error == B_OK) {
|
|
error = _WriteData(attribute, resourceID, attrType,
|
|
bitmap.Bits(), attrSize, true);
|
|
}
|
|
} else {
|
|
error = _WriteData(attribute, resourceID, attrType,
|
|
icon->Bits(), attrSize, true);
|
|
}
|
|
} else // no icon given => remove
|
|
error = _RemoveData(attribute, attrType);
|
|
}
|
|
|
|
// set the attribute on the MIME type, if the file has a signature
|
|
BMimeType mimeType;
|
|
if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) {
|
|
if (!mimeType.IsInstalled())
|
|
error = mimeType.Install();
|
|
if (error == B_OK)
|
|
error = mimeType.SetIconForType(type, icon, which);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
|
|
icon_size which)
|
|
{
|
|
return SetIconForType(type, icon, which, true);
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size,
|
|
bool updateMimeDB)
|
|
{
|
|
if (InitCheck() != B_OK)
|
|
return B_NO_INIT;
|
|
|
|
// set some icon related variables
|
|
BString attributeString = kIconAttribute;
|
|
int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID;
|
|
uint32 attrType = B_VECTOR_ICON_TYPE;
|
|
|
|
// check type param
|
|
if (type != NULL) {
|
|
if (BMimeType::IsValid(type))
|
|
attributeString += type;
|
|
else
|
|
return B_BAD_VALUE;
|
|
} else
|
|
attributeString += kIconType;
|
|
|
|
const char* attribute = attributeString.String();
|
|
|
|
status_t error;
|
|
// write/remove the attribute
|
|
if (data != NULL)
|
|
error = _WriteData(attribute, resourceID, attrType, data, size, true);
|
|
else // no icon given => remove
|
|
error = _RemoveData(attribute, attrType);
|
|
|
|
// set the attribute on the MIME type, if the file has a signature
|
|
BMimeType mimeType;
|
|
if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) {
|
|
if (!mimeType.IsInstalled())
|
|
error = mimeType.Install();
|
|
if (error == B_OK)
|
|
error = mimeType.SetIconForType(type, data, size);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size)
|
|
{
|
|
return SetIconForType(type, data, size, true);
|
|
}
|
|
|
|
|
|
void
|
|
BAppFileInfo::SetInfoLocation(info_location location)
|
|
{
|
|
// if the resources failed to initialize, we must not use them
|
|
if (fResources == NULL)
|
|
location = info_location(location & ~B_USE_RESOURCES);
|
|
|
|
fWhere = location;
|
|
}
|
|
|
|
bool
|
|
BAppFileInfo::IsUsingAttributes() const
|
|
{
|
|
return (fWhere & B_USE_ATTRIBUTES) != 0;
|
|
}
|
|
|
|
|
|
bool
|
|
BAppFileInfo::IsUsingResources() const
|
|
{
|
|
return (fWhere & B_USE_RESOURCES) != 0;
|
|
}
|
|
|
|
|
|
// FBC
|
|
void BAppFileInfo::_ReservedAppFileInfo1() {}
|
|
void BAppFileInfo::_ReservedAppFileInfo2() {}
|
|
void BAppFileInfo::_ReservedAppFileInfo3() {}
|
|
|
|
|
|
BAppFileInfo&
|
|
BAppFileInfo::operator=(const BAppFileInfo&)
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
|
|
BAppFileInfo::BAppFileInfo(const BAppFileInfo&)
|
|
{
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::GetMetaMime(BMimeType* meta) const
|
|
{
|
|
char signature[B_MIME_TYPE_LENGTH];
|
|
status_t error = GetSignature(signature);
|
|
if (error == B_OK)
|
|
error = meta->SetTo(signature);
|
|
else if (error == B_BAD_VALUE)
|
|
error = B_ENTRY_NOT_FOUND;
|
|
if (error == B_OK && !meta->IsValid())
|
|
error = B_BAD_VALUE;
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::_ReadData(const char* name, int32 id, type_code type,
|
|
void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer)
|
|
const
|
|
{
|
|
status_t error = B_OK;
|
|
|
|
if (allocatedBuffer)
|
|
buffer = NULL;
|
|
|
|
bool foundData = false;
|
|
|
|
if (IsUsingAttributes()) {
|
|
// get an attribute info
|
|
attr_info info;
|
|
if (error == B_OK)
|
|
error = fNode->GetAttrInfo(name, &info);
|
|
|
|
// check type and size, allocate a buffer, if required
|
|
if (error == B_OK && info.type != type)
|
|
error = B_BAD_VALUE;
|
|
if (error == B_OK && allocatedBuffer != NULL) {
|
|
buffer = malloc(info.size);
|
|
if (buffer == NULL)
|
|
error = B_NO_MEMORY;
|
|
bufferSize = info.size;
|
|
}
|
|
if (error == B_OK && (off_t)bufferSize < info.size)
|
|
error = B_BAD_VALUE;
|
|
|
|
// read the data
|
|
if (error == B_OK) {
|
|
ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
|
|
if (read < 0)
|
|
error = read;
|
|
else if (read != info.size)
|
|
error = B_ERROR;
|
|
else
|
|
bytesRead = read;
|
|
}
|
|
|
|
foundData = error == B_OK;
|
|
|
|
// free the allocated buffer on error
|
|
if (!foundData && allocatedBuffer != NULL && buffer != NULL) {
|
|
free(buffer);
|
|
buffer = NULL;
|
|
}
|
|
}
|
|
|
|
if (!foundData && IsUsingResources()) {
|
|
// get a resource info
|
|
error = B_OK;
|
|
int32 idFound;
|
|
size_t sizeFound;
|
|
if (error == B_OK) {
|
|
if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
|
|
error = B_ENTRY_NOT_FOUND;
|
|
}
|
|
|
|
// check id and size, allocate a buffer, if required
|
|
if (error == B_OK && id >= 0 && idFound != id)
|
|
error = B_ENTRY_NOT_FOUND;
|
|
if (error == B_OK && allocatedBuffer) {
|
|
buffer = malloc(sizeFound);
|
|
if (!buffer)
|
|
error = B_NO_MEMORY;
|
|
bufferSize = sizeFound;
|
|
}
|
|
if (error == B_OK && bufferSize < sizeFound)
|
|
error = B_BAD_VALUE;
|
|
|
|
// load resource
|
|
const void* resourceData = NULL;
|
|
if (error == B_OK) {
|
|
resourceData = fResources->LoadResource(type, name, &bytesRead);
|
|
if (resourceData != NULL && sizeFound == bytesRead)
|
|
memcpy(buffer, resourceData, bytesRead);
|
|
else
|
|
error = B_ERROR;
|
|
}
|
|
} else if (!foundData)
|
|
error = B_BAD_VALUE;
|
|
|
|
// return the allocated buffer, or free it on error
|
|
if (allocatedBuffer != NULL) {
|
|
if (error == B_OK)
|
|
*allocatedBuffer = buffer;
|
|
else
|
|
free(buffer);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::_WriteData(const char* name, int32 id, type_code type,
|
|
const void* buffer, size_t bufferSize, bool findID)
|
|
{
|
|
if (!IsUsingAttributes() && !IsUsingResources())
|
|
return B_NO_INIT;
|
|
|
|
status_t error = B_OK;
|
|
|
|
// write to attribute
|
|
if (IsUsingAttributes()) {
|
|
ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
|
|
if (written < 0)
|
|
error = written;
|
|
else if (written != (ssize_t)bufferSize)
|
|
error = B_ERROR;
|
|
}
|
|
// write to resource
|
|
if (IsUsingResources() && error == B_OK) {
|
|
if (findID) {
|
|
// get the resource info
|
|
int32 idFound;
|
|
size_t sizeFound;
|
|
if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
|
|
id = idFound;
|
|
else {
|
|
// type-name pair doesn't exist yet -- find unused ID
|
|
while (fResources->HasResource(type, id))
|
|
id++;
|
|
}
|
|
}
|
|
error = fResources->AddResource(type, id, buffer, bufferSize, name);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
status_t
|
|
BAppFileInfo::_RemoveData(const char* name, type_code type)
|
|
{
|
|
if (!IsUsingAttributes() && !IsUsingResources())
|
|
return B_NO_INIT;
|
|
|
|
status_t error = B_OK;
|
|
|
|
// remove the attribute
|
|
if (IsUsingAttributes()) {
|
|
error = fNode->RemoveAttr(name);
|
|
// It's no error, if there has been no attribute.
|
|
if (error == B_ENTRY_NOT_FOUND)
|
|
error = B_OK;
|
|
}
|
|
// remove the resource
|
|
if (IsUsingResources() && error == B_OK) {
|
|
// get a resource info
|
|
int32 idFound;
|
|
size_t sizeFound;
|
|
if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
|
|
error = fResources->RemoveResource(type, idFound);
|
|
}
|
|
return error;
|
|
}
|