/*
* Copyright 2002-2010 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold, bonefish@users.sf.net
* Axel Dörfler, axeld@pinc-software.de
*/
#include <NodeInfo.h>
#include <new>
#include <string.h>
#include <MimeTypes.h>
#include <Bitmap.h>
#include <Entry.h>
#include <IconUtils.h>
#include <Node.h>
#include <Path.h>
#include <Rect.h>
#include <fs_attr.h>
#include <fs_info.h>
using namespace std;
// attribute names
#define NI_BEOS "BEOS"
static const char* kNITypeAttribute = NI_BEOS ":TYPE";
static const char* kNIPreferredAppAttribute = NI_BEOS ":PREF_APP";
static const char* kNIAppHintAttribute = NI_BEOS ":PPATH";
static const char* kNIMiniIconAttribute = NI_BEOS ":M:STD_ICON";
static const char* kNILargeIconAttribute = NI_BEOS ":L:STD_ICON";
static const char* kNIIconAttribute = NI_BEOS ":ICON";
// #pragma mark - BNodeInfo
BNodeInfo::BNodeInfo()
:
fNode(NULL),
fCStatus(B_NO_INIT)
{
}
BNodeInfo::BNodeInfo(BNode* node)
:
fNode(NULL),
fCStatus(B_NO_INIT)
{
fCStatus = SetTo(node);
}
BNodeInfo::~BNodeInfo()
{
}
status_t
BNodeInfo::SetTo(BNode* node)
{
fNode = NULL;
// check parameter
fCStatus = (node && node->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
if (fCStatus == B_OK)
fNode = node;
return fCStatus;
}
status_t
BNodeInfo::InitCheck() const
{
return fCStatus;
}
status_t
BNodeInfo::GetType(char* type) const
{
// check parameter and initialization
status_t result = (type ? B_OK : B_BAD_VALUE);
if (result == B_OK && InitCheck() != B_OK)
result = B_NO_INIT;
// get the attribute info and check type and length of the attr contents
attr_info attrInfo;
if (result == B_OK)
result = fNode->GetAttrInfo(kNITypeAttribute, &attrInfo);
if (result == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
result = B_BAD_TYPE;
if (result == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
result = B_BAD_DATA;
// read the data
if (result == B_OK) {
ssize_t read = fNode->ReadAttr(kNITypeAttribute, attrInfo.type, 0,
type, attrInfo.size);
if (read < 0)
result = read;
else if (read != attrInfo.size)
result = B_ERROR;
if (result == B_OK) {
// attribute strings doesn't have to be null terminated
type[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
}
}
return result;
}
status_t
BNodeInfo::SetType(const char* type)
{
// check parameter and initialization
status_t result = B_OK;
if (result == B_OK && type && strlen(type) >= B_MIME_TYPE_LENGTH)
result = B_BAD_VALUE;
if (result == B_OK && InitCheck() != B_OK)
result = B_NO_INIT;
// write/remove the attribute
if (result == B_OK) {
if (type != NULL) {
size_t toWrite = strlen(type) + 1;
ssize_t written = fNode->WriteAttr(kNITypeAttribute,
B_MIME_STRING_TYPE, 0, type, toWrite);
if (written < 0)
result = written;
else if (written != (ssize_t)toWrite)
result = B_ERROR;
} else
result = fNode->RemoveAttr(kNITypeAttribute);
}
return result;
}
status_t
BNodeInfo::GetIcon(BBitmap* icon, icon_size which) const
{
const char* iconAttribute = kNIIconAttribute;
const char* miniIconAttribute = kNIMiniIconAttribute;
const char* largeIconAttribute = kNILargeIconAttribute;
return BIconUtils::GetIcon(fNode, iconAttribute, miniIconAttribute,
largeIconAttribute, which, icon);
}
status_t
BNodeInfo::SetIcon(const BBitmap* icon, icon_size which)
{
status_t result = B_OK;
// set some icon size related variables
const char* attribute = NULL;
BRect bounds;
uint32 attrType = 0;
size_t attrSize = 0;
switch (which) {
case B_MINI_ICON:
attribute = kNIMiniIconAttribute;
bounds.Set(0, 0, 15, 15);
attrType = B_MINI_ICON_TYPE;
attrSize = 16 * 16;
break;
case B_LARGE_ICON:
attribute = kNILargeIconAttribute;
bounds.Set(0, 0, 31, 31);
attrType = B_LARGE_ICON_TYPE;
attrSize = 32 * 32;
break;
default:
result = B_BAD_VALUE;
break;
}
// check parameter and initialization
if (result == B_OK && icon != NULL
&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
result = B_BAD_VALUE;
}
if (result == B_OK && InitCheck() != B_OK)
result = B_NO_INIT;
// write/remove the attribute
if (result == B_OK) {
if (icon != NULL) {
bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
ssize_t written = 0;
if (otherColorSpace) {
BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
result = bitmap.InitCheck();
if (result == B_OK)
result = bitmap.ImportBits(icon);
if (result == B_OK) {
written = fNode->WriteAttr(attribute, attrType, 0,
bitmap.Bits(), attrSize);
}
} else {
written = fNode->WriteAttr(attribute, attrType, 0,
icon->Bits(), attrSize);
}
if (result == B_OK) {
if (written < 0)
result = written;
else if (written != (ssize_t)attrSize)
result = B_ERROR;
}
} else {
// no icon given => remove
result = fNode->RemoveAttr(attribute);
}
}
return result;
}
status_t
BNodeInfo::GetIcon(uint8** data, size_t* size, type_code* type) const
{
// check params
if (data == NULL || size == NULL || type == NULL)
return B_BAD_VALUE;
// check initialization
if (InitCheck() != B_OK)
return B_NO_INIT;
// get the attribute info and check type and size of the attr contents
attr_info attrInfo;
status_t result = fNode->GetAttrInfo(kNIIconAttribute, &attrInfo);
if (result != B_OK)
return result;
// chicken out on unrealisticly large attributes
if (attrInfo.size > 128 * 1024)
return B_ERROR;
// fill the params
*type = attrInfo.type;
*size = attrInfo.size;
*data = new (nothrow) uint8[*size];
if (*data == NULL)
return B_NO_MEMORY;
// featch the data
ssize_t read = fNode->ReadAttr(kNIIconAttribute, *type, 0, *data, *size);
if (read != attrInfo.size) {
delete[] *data;
*data = NULL;
return B_ERROR;
}
return B_OK;
}
status_t
BNodeInfo::SetIcon(const uint8* data, size_t size)
{
// check initialization
if (InitCheck() != B_OK)
return B_NO_INIT;
status_t result = B_OK;
// write/remove the attribute
if (data && size > 0) {
ssize_t written = fNode->WriteAttr(kNIIconAttribute,
B_VECTOR_ICON_TYPE, 0, data, size);
if (written < 0)
result = (status_t)written;
else if (written != (ssize_t)size)
result = B_ERROR;
} else {
// no icon given => remove
result = fNode->RemoveAttr(kNIIconAttribute);
}
return result;
}
status_t
BNodeInfo::GetPreferredApp(char* signature, app_verb verb) const
{
// check parameter and initialization
status_t result = (signature && verb == B_OPEN ? B_OK : B_BAD_VALUE);
if (result == B_OK && InitCheck() != B_OK)
result = B_NO_INIT;
// get the attribute info and check type and length of the attr contents
attr_info attrInfo;
if (result == B_OK)
result = fNode->GetAttrInfo(kNIPreferredAppAttribute, &attrInfo);
if (result == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
result = B_BAD_TYPE;
if (result == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
result = B_BAD_DATA;
// read the data
if (result == B_OK) {
ssize_t read = fNode->ReadAttr(kNIPreferredAppAttribute, attrInfo.type,
0, signature, attrInfo.size);
if (read < 0)
result = read;
else if (read != attrInfo.size)
result = B_ERROR;
if (result == B_OK) {
// attribute strings doesn't have to be null terminated
signature[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
}
}
return result;
}
status_t
BNodeInfo::SetPreferredApp(const char* signature, app_verb verb)
{
// check parameters and initialization
status_t result = (verb == B_OPEN ? B_OK : B_BAD_VALUE);
if (result == B_OK && signature && strlen(signature) >= B_MIME_TYPE_LENGTH)
result = B_BAD_VALUE;
if (result == B_OK && InitCheck() != B_OK)
result = B_NO_INIT;
// write/remove the attribute
if (result == B_OK) {
if (signature) {
size_t toWrite = strlen(signature) + 1;
ssize_t written = fNode->WriteAttr(kNIPreferredAppAttribute,
B_MIME_STRING_TYPE, 0, signature, toWrite);
if (written < 0)
result = written;
else if (written != (ssize_t)toWrite)
result = B_ERROR;
} else
result = fNode->RemoveAttr(kNIPreferredAppAttribute);
}
return result;
}
status_t
BNodeInfo::GetAppHint(entry_ref* ref) const
{
// check parameter and initialization
status_t result = (ref ? B_OK : B_BAD_VALUE);
if (result == B_OK && InitCheck() != B_OK)
result = B_NO_INIT;
// get the attribute info and check type and length of the attr contents
attr_info attrInfo;
if (result == B_OK)
result = fNode->GetAttrInfo(kNIAppHintAttribute, &attrInfo);
// NOTE: The attribute type should be B_STRING_TYPE, but R5 uses
// B_MIME_STRING_TYPE.
if (result == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
result = B_BAD_TYPE;
if (result == B_OK && attrInfo.size > B_PATH_NAME_LENGTH)
result = B_BAD_DATA;
// read the data
if (result == B_OK) {
char path[B_PATH_NAME_LENGTH];
ssize_t read = fNode->ReadAttr(kNIAppHintAttribute, attrInfo.type, 0,
path, attrInfo.size);
if (read < 0)
result = read;
else if (read != attrInfo.size)
result = B_ERROR;
// get the entry_ref for the path
if (result == B_OK) {
// attribute strings doesn't have to be null terminated
path[min_c(attrInfo.size, B_PATH_NAME_LENGTH - 1)] = '\0';
result = get_ref_for_path(path, ref);
}
}
return result;
}
status_t
BNodeInfo::SetAppHint(const entry_ref* ref)
{
// check parameter and initialization
if (InitCheck() != B_OK)
return B_NO_INIT;
status_t result = B_OK;
if (ref != NULL) {
// write/remove the attribute
BPath path;
result = path.SetTo(ref);
if (result == B_OK) {
size_t toWrite = strlen(path.Path()) + 1;
ssize_t written = fNode->WriteAttr(kNIAppHintAttribute,
B_MIME_STRING_TYPE, 0, path.Path(), toWrite);
if (written < 0)
result = written;
else if (written != (ssize_t)toWrite)
result = B_ERROR;
}
} else
result = fNode->RemoveAttr(kNIAppHintAttribute);
return result;
}
status_t
BNodeInfo::GetTrackerIcon(BBitmap* icon, icon_size which) const
{
if (icon == NULL)
return B_BAD_VALUE;
// set some icon size related variables
BRect bounds;
switch (which) {
case B_MINI_ICON:
bounds.Set(0, 0, 15, 15);
break;
case B_LARGE_ICON:
bounds.Set(0, 0, 31, 31);
break;
default:
// result = B_BAD_VALUE;
// NOTE: added to be less strict and support scaled icons
bounds = icon->Bounds();
break;
}
// check parameters and initialization
if (icon->InitCheck() != B_OK || icon->Bounds() != bounds)
return B_BAD_VALUE;
if (InitCheck() != B_OK)
return B_NO_INIT;
// Ask GetIcon() first.
if (GetIcon(icon, which) == B_OK)
return B_OK;
// If not successful, see if the node has a type available at all.
// If no type is available, use one of the standard types.
status_t result = B_OK;
char mimeString[B_MIME_TYPE_LENGTH];
if (GetType(mimeString) != B_OK) {
// Get the icon from a mime type...
BMimeType type;
struct stat stat;
result = fNode->GetStat(&stat);
if (result == B_OK) {
// no type available -- get the icon for the appropriate type
// (file/dir/etc.)
if (S_ISREG(stat.st_mode)) {
// is it an application (executable) or just a regular file?
if ((stat.st_mode & S_IXUSR) != 0)
type.SetTo(B_APP_MIME_TYPE);
else
type.SetTo(B_FILE_MIME_TYPE);
} else if (S_ISDIR(stat.st_mode)) {
// it's either a volume or just a standard directory
fs_info info;
if (fs_stat_dev(stat.st_dev, &info) == 0
&& stat.st_ino == info.root) {
type.SetTo(B_VOLUME_MIME_TYPE);
} else
type.SetTo(B_DIRECTORY_MIME_TYPE);
} else if (S_ISLNK(stat.st_mode))
type.SetTo(B_SYMLINK_MIME_TYPE);
} else {
// GetStat() failed. Return the icon for
// "application/octet-stream" from the MIME database.
type.SetTo(B_FILE_MIME_TYPE);
}
return type.GetIcon(icon, which);
} else {
// We know the mimetype of the node.
bool success = false;
// Get the preferred application and ask the MIME database, if that
// application has a special icon for the node's file type.
char signature[B_MIME_TYPE_LENGTH];
if (GetPreferredApp(signature) == B_OK) {
BMimeType type(signature);
success = type.GetIconForType(mimeString, icon, which) == B_OK;
}
// ToDo: Confirm Tracker asks preferred app icons before asking
// mime icons.
BMimeType nodeType(mimeString);
// Ask the MIME database for the preferred application for the node's
// file type and whether this application has a special icon for the
// type.
if (!success && nodeType.GetPreferredApp(signature) == B_OK) {
BMimeType type(signature);
success = type.GetIconForType(mimeString, icon, which) == B_OK;
}
// Ask the MIME database whether there is an icon for the node's file
// type.
if (!success)
success = nodeType.GetIcon(icon, which) == B_OK;
// Get the super type if still no success.
BMimeType superType;
if (!success && nodeType.GetSupertype(&superType) == B_OK) {
// Ask the MIME database for the preferred application for the
// node's super type and whether this application has a special
// icon for the type.
if (superType.GetPreferredApp(signature) == B_OK) {
BMimeType type(signature);
success = type.GetIconForType(superType.Type(), icon,
which) == B_OK;
}
// Get the icon of the super type itself.
if (!success)
success = superType.GetIcon(icon, which) == B_OK;
}
if (success)
return B_OK;
}
return B_ERROR;
}
status_t
BNodeInfo::GetTrackerIcon(const entry_ref* ref, BBitmap* icon, icon_size which)
{
// check ref param
status_t result = (ref ? B_OK : B_BAD_VALUE);
// init a BNode
BNode node;
if (result == B_OK)
result = node.SetTo(ref);
// init a BNodeInfo
BNodeInfo nodeInfo;
if (result == B_OK)
result = nodeInfo.SetTo(&node);
// let the non-static GetTrackerIcon() do the dirty work
if (result == B_OK)
result = nodeInfo.GetTrackerIcon(icon, which);
return result;
}
/*! This method is provided for binary compatibility purposes
(for example the program "Guido" depends on it.)
*/
extern "C"
status_t
GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(
BNodeInfo* nodeInfo, entry_ref* ref,
BBitmap* bitmap, icon_size iconSize)
{
// NOTE: nodeInfo is ignored - maybe that's wrong!
return BNodeInfo::GetTrackerIcon(ref, bitmap, iconSize);
}
void BNodeInfo::_ReservedNodeInfo1() {}
void BNodeInfo::_ReservedNodeInfo2() {}
void BNodeInfo::_ReservedNodeInfo3() {}
/*! Assignment operator is declared private to prevent it from being created
automatically by the compiler.
*/
BNodeInfo&
BNodeInfo::operator=(const BNodeInfo &nodeInfo)
{
return *this;
}
/*! Copy constructor is declared private to prevent it from being created
automatically by the compiler.
*/
BNodeInfo::BNodeInfo(const BNodeInfo &)
{
}
↑ V547 Expression 'verb == B_OPEN' is always true.