/*
 * Copyright 2002-2014, Haiku, Inc.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Ingo Weinhold, ingo_weinhold@gmx.de
 */
 
 
#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 (InitCheck() != B_OK)
		error = B_NO_INIT;
	if (error == B_OK) {
		if (type != NULL) {
			// check param
			size_t typeLen = strlen(type);
			if (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 (InitCheck() != B_OK)
		error = B_NO_INIT;
	if (error == B_OK) {
		if (signature) {
			// check param
			size_t signatureLen = strlen(signature);
			if (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 (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 (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 (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 0
		if (updateMimeDB && error == B_OK && mimeType.IsInstalled())
			error = mimeType.SetSupportedTypes(types, syncAll);
#endif
	}
	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 (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
#if 0
	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);
	}
#endif
	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
#if 0
	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);
	}
#endif
	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;
}

V547 Expression 'error == ((int) 0)' is always true.

V547 Expression 'error == ((int) 0)' is always true.

V547 Expression 'error == ((int) 0)' is always true.

V547 Expression 'error == ((int) 0)' is always true.