diff --git a/src/kits/storage/NodeInfo.cpp b/src/kits/storage/NodeInfo.cpp index 27aec13dbc..a8025ec175 100644 --- a/src/kits/storage/NodeInfo.cpp +++ b/src/kits/storage/NodeInfo.cpp @@ -11,21 +11,27 @@ #include +#include +#include #include -#include +#include +#include #include +// attribute names #define NI_BEOS "BEOS" -// I've added a BEOS hash-define in case we wish to change to OBOS -#define NI_TYPE NI_BEOS ":TYPE" -#define NI_PREF NI_BEOS ":PREF_APP" -#define NI_HINT NI_BEOS ":PPATH" -#define NI_ICON "STD_ICON" -#define NI_M_ICON NI_BEOS ":M:" NI_ICON -#define NI_L_ICON NI_BEOS ":L:" NI_ICON -#define NI_ICON_SIZE(k) ((k == B_LARGE_ICON) ? NI_L_ICON : NI_M_ICON ) +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"; +// icon types +enum { + B_MINI_ICON_TYPE = 'MICN', + B_LARGE_ICON_TYPE = 'ICON', +}; // constructor /*! \brief Creates an uninitialized BNode object. @@ -35,6 +41,8 @@ \see SetTo(BNode *node) */ BNodeInfo::BNodeInfo() + : fNode(NULL), + fCStatus(B_NO_INIT) { } @@ -46,6 +54,8 @@ BNodeInfo::BNodeInfo() \see SetTo(BNode *node) */ BNodeInfo::BNodeInfo(BNode *node) + : fNode(NULL), + fCStatus(B_NO_INIT) { fCStatus = SetTo(node); } @@ -60,7 +70,7 @@ BNodeInfo::~BNodeInfo() } // SetTo -/*! \brief Sets the node for which you want data on. +/*! \brief Initializes the BNodeInfo to the supplied node. The BNodeInfo object does not copy the supplied object, but uses it directly. You must not delete the object you supply while the BNodeInfo @@ -76,11 +86,11 @@ BNodeInfo::~BNodeInfo() status_t BNodeInfo::SetTo(BNode *node) { - fCStatus = B_BAD_VALUE; - if (node != NULL) { - fCStatus = node->InitCheck(); + fNode = NULL; + // check parameter + fCStatus = (node && node->InitCheck() == B_OK ? B_OK : B_BAD_VALUE); + if (fCStatus == B_OK) fNode = node; - } return fCStatus; } @@ -109,30 +119,41 @@ BNodeInfo::InitCheck() const \return - \c B_OK: Everything went fine. - \c B_NO_INIT: The object is not properly initialized. - - \c B_BAD_VALUE: \c NULL \a type. + - \c B_BAD_VALUE: \c NULL \a type or the type string stored in the + attribute is longer than \c B_MIME_TYPE_LENGTH. + - \c B_BAD_TYPE: The attribute the type string is stored in has the wrong + type. + - \c B_ENTRY_NOT_FOUND: No type is set on the node. - other error codes */ status_t BNodeInfo::GetType(char *type) const { - if (type == NULL) - return; - - if (fCStatus == B_OK) { - attr_info attrInfo; - status_t error; - - error = fNode->GetAttrInfo(NI_TYPE, &attrInfo); - if (error == B_OK) { - error = fNode->ReadAttr(NI_TYPE, attrInfo.type, 0, type, - attrInfo.size); - } - // Future Idea: Add a bit to identify based on extention etc - // see CVS verion 1.6 for big chuck of the code. - - return (error > B_OK ? B_OK : error); - } else - return B_NO_INIT; + // check parameter and initialization + status_t error = (type ? B_OK : B_BAD_VALUE); + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // get the attribute info and check type and length of the attr contents + attr_info attrInfo; + if (error == B_OK) + error = fNode->GetAttrInfo(kNITypeAttribute, &attrInfo); + if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE) + error = B_BAD_TYPE; + if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH) + error = B_BAD_VALUE; // TODO: B_BAD_DATA? + // read the data + if (error == B_OK) { + ssize_t read = fNode->ReadAttr(kNITypeAttribute, attrInfo.type, 0, + type, attrInfo.size); + if (read < 0) + error = read; + else if (read != attrInfo.size) + error = B_ERROR; + // to be save, null terminate the string at the very end + if (error == B_OK) + type[B_MIME_TYPE_LENGTH - 1] = '\0'; + } + return error; } // SetType @@ -140,25 +161,41 @@ BNodeInfo::GetType(char *type) const The supplied string is written into the node's "BEOS:TYPE" attribute. + If \a type is \c NULL, the respective attribute is removed. + \param type The MIME type to be assigned to the node. Must not be longer than \c B_MIME_TYPE_LENGTH (including the terminating null). + May be \c NULL. \return - \c B_OK: Everything went fine. - \c B_NO_INIT: The object is not properly initialized. - - \c B_BAD_VALUE: \c NULL \a type or \a type is longer than - \c B_MIME_TYPE_LENGTH. + - \c B_BAD_VALUE: \a type is longer than \c B_MIME_TYPE_LENGTH. - other error codes */ status_t BNodeInfo::SetType(const char *type) { - if (fCStatus == B_OK) { - status_t error; - error = fNode->WriteAttr(NI_TYPE, B_STRING_TYPE, 0, type, - sizeof(type)); - return (error > B_OK ? B_OK : error); - } else - return B_NO_INIT; + // check parameter and initialization + status_t error = B_OK; + if (error == B_OK && type && strlen(type) >= B_MIME_TYPE_LENGTH) + error = B_BAD_VALUE; + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // write/remove the attribute + if (error == B_OK) { + if (type) { + size_t toWrite = strlen(type) + 1; + ssize_t written = fNode->WriteAttr(kNITypeAttribute, + B_MIME_STRING_TYPE, 0, type, + toWrite); + if (written < 0) + error = written; + else if (written != (ssize_t)toWrite) + error = B_ERROR; + } else + error = fNode->RemoveAttr(kNITypeAttribute); + } + return error; } // GetIcon @@ -182,20 +219,76 @@ BNodeInfo::SetType(const char *type) status_t BNodeInfo::GetIcon(BBitmap *icon, icon_size k) const { - if (fCStatus == B_OK) { - attr_info attrInfo; - int error; - - error = fNode->GetAttrInfo(NI_ICON_SIZE(k), &attrInfo); - if (error == B_OK) { - - error = fNode->ReadAttr(NI_ICON_SIZE(k), attrInfo.type, 0, icon, - attrInfo.size); + status_t error = B_OK; + // set some icon size related variables + const char *attribute = NULL; + BRect bounds; + uint32 attrType; + size_t attrSize; + switch (k) { + 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: + error = B_BAD_VALUE; + break; + } + // check parameter and initialization + if (error == B_OK + && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { + error = B_BAD_VALUE; + } + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // get the attribute info and check type and size of the attr contents + attr_info attrInfo; + if (error == B_OK) + error = fNode->GetAttrInfo(attribute, &attrInfo); + if (error == B_OK && attrInfo.type != attrType) + error = B_BAD_TYPE; + if (error == B_OK && attrInfo.size != attrSize) + error = B_BAD_VALUE; // TODO: B_BAD_DATA? + // read the attribute + if (error == B_OK) { + bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); + char *buffer = NULL; + ssize_t read; + if (otherColorSpace) { + // other color space than stored in attribute + buffer = new(nothrow) char[attrSize]; + if (!buffer) + error = B_NO_MEMORY; + if (error == B_OK) { + read = fNode->ReadAttr(attribute, attrType, 0, buffer, + attrSize); + } + } else { + read = fNode->ReadAttr(attribute, attrType, 0, icon->Bits(), + attrSize); } - - return (error > B_OK ? B_OK : error); - } else - return B_NO_INIT; + if (error == B_OK) { + if (read < 0) + error = read; + else if (read != attrInfo.size) + error = B_ERROR; + } + if (otherColorSpace) { + // other color space than stored in attribute + if (error == B_OK) + icon->SetBits(buffer, attrSize, 0, B_CMAP8); + delete[] buffer; + } + } + return error; } // SetIcon @@ -207,6 +300,7 @@ BNodeInfo::GetIcon(BBitmap *icon, icon_size k) const If \a icon is \c NULL, the respective attribute is removed. \param icon A pointer to the BBitmap containing the icon to be set. + May be \c NULL. \param k Specifies the size of the icon to be set: \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon. \return @@ -219,11 +313,63 @@ BNodeInfo::GetIcon(BBitmap *icon, icon_size k) const status_t BNodeInfo::SetIcon(const BBitmap *icon, icon_size k) { - if (fCStatus == B_OK) { - return fNode->WriteAttr(NI_ICON_SIZE(k), B_COLOR_8_BIT_TYPE, - 0, icon, sizeof(icon)); - } else - return B_NO_INIT; + status_t error = B_OK; + // set some icon size related variables + const char *attribute = NULL; + BRect bounds; + uint32 attrType; + size_t attrSize; + switch (k) { + 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: + error = B_BAD_VALUE; + break; + } + // check parameter and initialization + if (error == B_OK && icon + && (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) { + bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); + ssize_t written; + if (otherColorSpace) { + BBitmap bitmap(bounds, B_CMAP8); + error = bitmap.InitCheck(); + if (error == B_OK) { + bitmap.SetBits(icon->Bits(), 0, attrSize, B_CMAP8); + written = fNode->WriteAttr(attribute, attrType, 0, + bitmap.Bits(), attrSize); + } + } else { + written = fNode->WriteAttr(attribute, attrType, 0, + icon->Bits(), attrSize); + } + if (error == B_OK) { + if (written < 0) + error = written; + else if (written != (ssize_t)attrSize) + error = B_ERROR; + } + } else // no icon given => remove + error = fNode->RemoveAttr(attribute); + } + return error; } // GetPreferredApp @@ -247,31 +393,31 @@ BNodeInfo::SetIcon(const BBitmap *icon, icon_size k) status_t BNodeInfo::GetPreferredApp(char *signature, app_verb verb) const { - if (fCStatus == B_OK) { - attr_info attrInfo; - int error; - - error = fNode->GetAttrInfo(NI_PREF, &attrInfo); - if (error == B_OK) { - - error = fNode->ReadAttr(NI_PREF, attrInfo.type, 0, - signature, attrInfo.size); - if (error < B_OK) { - char *mimetpye = new(nothrow) char[B_MIME_TYPE_LENGTH]; - if (mimetype) { - if (GetMineType(mimetype) >= B_OK) { - BMimeType mime(mimetype); - error = mine.GetPreferredApp(signature, verb); - } - delete minetype; - } else - error = B_NO_MEMORY; - } - } - - return (error > B_OK ? B_OK : error); - } else - return B_NO_INIT; + // check parameter and initialization + status_t error = (signature && verb == B_OPEN ? B_OK : B_BAD_VALUE); + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // get the attribute info and check type and length of the attr contents + attr_info attrInfo; + if (error == B_OK) + error = fNode->GetAttrInfo(kNIPreferredAppAttribute, &attrInfo); + if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE) + error = B_BAD_TYPE; + if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH) + error = B_BAD_VALUE; // TODO: B_BAD_DATA? + // read the data + if (error == B_OK) { + ssize_t read = fNode->ReadAttr(kNIPreferredAppAttribute, attrInfo.type, + 0, signature, attrInfo.size); + if (read < 0) + error = read; + else if (read != attrInfo.size) + error = B_ERROR; + // to be save, null terminate the string at the very end + if (error == B_OK) + signature[B_MIME_TYPE_LENGTH - 1] = '\0'; + } + return error; } // SetPreferredApp @@ -279,28 +425,44 @@ BNodeInfo::GetPreferredApp(char *signature, app_verb verb) const The supplied string is written into the node's "BEOS:PREF_APP" attribute. + If \a signature is \c NULL, the respective attribute is removed. + \param signature The signature of the preferred application to be set. Must not be longer than \c B_MIME_TYPE_LENGTH (including the - terminating null). + terminating null). May be \c NULL. \param verb Specifies the type of access the preferred application shall be set for. Currently only \c B_OPEN is meaningful. \return - \c B_OK: Everything went fine. - \c B_NO_INIT: The object is not properly initialized. - - \c B_BAD_VALUE: \c NULL \a signature or bad app_verb \a verb. + - \c B_BAD_VALUE: \c NULL \a signature, \a signature is longer than + \c B_MIME_TYPE_LENGTH or bad app_verb \a verb. - other error codes */ status_t BNodeInfo::SetPreferredApp(const char *signature, app_verb verb) { - if (size_of(signature) > B_MIME_TYPE_LENGTH) - return B_BAD_VALUE; - - if (fCStatus == B_OK) { - return fNode->WriteAttr(NI_PREF, B_STRING_TYPE, 0, signature, - sizeof(signature)); - } else - return B_NO_INIT; + // check parameters and initialization + status_t error = (verb == B_OPEN ? B_OK : B_BAD_VALUE); + if (error == B_OK && signature && strlen(signature) >= B_MIME_TYPE_LENGTH) + error = B_BAD_VALUE; + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // write/remove the attribute + if (error == 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) + error = written; + else if (written != (ssize_t)toWrite) + error = B_ERROR; + } else + error = fNode->RemoveAttr(kNIPreferredAppAttribute); + } + return error; } // GetAppHint @@ -321,32 +483,37 @@ BNodeInfo::SetPreferredApp(const char *signature, app_verb verb) status_t BNodeInfo::GetAppHint(entry_ref *ref) const { - if (fCStatus == B_OK) { - attr_info attrInfo; - status_t error; - - error = fNode->GetAttrInfo(NI_HINT, &attrInfo); + // check parameter and initialization + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // get the attribute info and check type and length of the attr contents + attr_info attrInfo; + if (error == B_OK) + error = fNode->GetAttrInfo(kNIAppHintAttribute, &attrInfo); + // NOTE: The attribute type should be B_STRING_TYPE, but R5 uses + // B_MIME_STRING_TYPE. + if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE) + error = B_BAD_TYPE; + if (error == B_OK && attrInfo.size > B_PATH_NAME_LENGTH) + error = B_BAD_VALUE; // TODO: B_BAD_DATA? + // read the data + if (error == B_OK) { + char path[B_PATH_NAME_LENGTH]; + ssize_t read = fNode->ReadAttr(kNIAppHintAttribute, attrInfo.type, 0, + path, attrInfo.size); + if (read < 0) + error = read; + else if (read != attrInfo.size) + error = B_ERROR; + // get the entry_ref for the path if (error == B_OK) { - - error = fNode->ReadAttr(NI_HINT, attrInfo.type, 0, - ref, attrInfo.size); - if(error < B_OK) { - char *mimetype = new(nothrow) char[B_MIME_TYPE_LENGTH]; - if (mimetype) { - if( GetMineType(mimetype) >= B_OK ) { - BMimeType mime(mimetype); - error = mime.GetAppHint(ref); - } - - delete minetype; - } else - error = B_NO_MEMORY; - } + // to be save, null terminate the path at the very end + path[B_PATH_NAME_LENGTH - 1] = '\0'; + error = get_ref_for_path(path, ref); } - - return (error > B_OK ? B_OK : error); - } else - return B_NO_INIT; + } + return error; } // SetAppHint @@ -355,7 +522,10 @@ BNodeInfo::GetAppHint(entry_ref *ref) const The supplied entry_ref is converted into a path and stored in the node's "BEOS:PPATH" attribute. + If \a ref is \c NULL, the respective attribute is removed. + \param ref A pointer to an entry_ref referring to the application. + May be \c NULL. \return - \c B_OK: Everything went fine. - \c B_NO_INIT: The object is not properly initialized. @@ -365,25 +535,47 @@ BNodeInfo::GetAppHint(entry_ref *ref) const status_t BNodeInfo::SetAppHint(const entry_ref *ref) { - if (fCStatus == B_OK) { - return fNode->WriteAttr(NI_HINT, B_REF_TYPE, 0, ref, sizeof(ref)); - } else - return B_NO_INIT; + // check parameter and initialization + status_t error = B_OK; + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + // write/remove the attribute + if (error == B_OK) { + if (ref) { + BPath path; + error = path.SetTo(ref); + if (error == 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) + error = written; + else if (written != (ssize_t)toWrite) + error = B_ERROR; + } + } else + error = fNode->RemoveAttr(kNIAppHintAttribute); + } + return error; } // GetTrackerIcon /*! \brief Gets the icon which tracker displays. This method tries real hard to find an icon for the node: + - If the node has no type, return the icon for "application/octet-stream" + from the MIME database. Even, if the node has an own icon! - Ask GetIcon(). - Get the preferred application and ask the MIME database, if that application has a special icon for the node's file type. - Ask the MIME database whether there is an icon for the node's file type. - 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. + - Return the icon for "application/octet-stream" from the MIME database. This list is processed in the given order and the icon the first - successful method provides is returned. In case none of them yields an - icon, this method fails. + successful attempt provides is returned. In case none of them yields an + icon, this method fails. This is very unlikely though. \param icon A pointer to a pre-allocated BBitmap of the correct dimension to store the requested icon (16x16 for the mini and 32x32 for the @@ -400,45 +592,73 @@ BNodeInfo::SetAppHint(const entry_ref *ref) status_t BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size k) const { - status_t getIconReturn = GetIcon(icon, k); - entry_ref ref; - char mimetype[B_MIME_TYPE_LENGTH]; - - // Ask the attr - if (getIconReturn == B_OK) - return OK; - - // Ask the File Type db based on app sig - if (GetAppHint(&ref) == B_OK) { - BFile appFile(ref); - if (appFile.InitCheck() == B_OK) { - BAppFileInfo appFileInfo( appFile ); - if (appFileInfo.GetIcon( icon, k ) == B_OK) - return B_OK; + // set some icon size related variables + status_t error = B_OK; + BRect bounds; + switch (k) { + case B_MINI_ICON: + bounds.Set(0, 0, 15, 15); + break; + case B_LARGE_ICON: + bounds.Set(0, 0, 31, 31); + break; + default: + error = B_BAD_VALUE; + break; + } + // check parameters and initialization + if (error == B_OK + && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { + error = B_BAD_VALUE; + } + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + bool success = false; + // get node MIME type, and, if that fails, the generic icon + char mimeString[B_MIME_TYPE_LENGTH]; + if (error == B_OK) { + if (GetType(mimeString) != B_OK) { + // no type available -- get the "application/octet-stream" icon + BMimeType type("application/octet-stream"); + error = type.GetIcon(icon, k); + success = (error == B_OK); } } - - // Ask FTdb based on mime type - if (GetMimeType(&mimetype)) { - if (BMimeType.GetIconForType(mimetype, icon, k) == B_OK) - return B_OK; - - // asks the File Type database for the preferred app based on the node's - // file type, and then asks that app for the icon it uses to display this - // node's file type. - BMimeType mime(mimetype); - if (mime.GetAppHint(&ref) == B_OK) { - BFile appFile(ref); - if (appFile.InitCheck() == B_OK) { - BAppFileInfo appFileInfo( appFile ); - if (appFileInfo.GetIcon( icon, k ) == B_OK) - return B_OK; - } + // Ask GetIcon(). + if (error == B_OK && !success) + success = (GetIcon(icon, k) == B_OK); + // Get the preferred application and ask the MIME database, if that + // application has a special icon for the node's file type. + if (error == B_OK && !success) { + char signature[B_MIME_TYPE_LENGTH]; + if (GetPreferredApp(signature) == B_OK) { + BMimeType type(signature); + success = (type.GetIconForType(mimeString, icon, k) == B_OK); } } - - // Quit - return getIconReturn; + // Ask the MIME database whether there is an icon for the node's file type. + BMimeType nodeType; + if (error == B_OK && !success) { + nodeType.SetTo(mimeString); + success = (nodeType.GetIcon(icon, k) == B_OK); + } + // 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 (error == B_OK && !success) { + char signature[B_MIME_TYPE_LENGTH]; + if (nodeType.GetPreferredApp(signature) == B_OK) { + BMimeType type(signature); + success = (type.GetIconForType(mimeString, icon, k) == B_OK); + } + } + // Return the icon for "application/octet-stream" from the MIME database. + if (error == B_OK && !success) { + // get the "application/octet-stream" icon + BMimeType type("application/octet-stream"); + error = type.GetIcon(icon, k); + success = (error == B_OK); + } + return error; } // GetTrackerIcon @@ -465,13 +685,20 @@ BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size k) const status_t BNodeInfo::GetTrackerIcon(const entry_ref *ref, BBitmap *icon, icon_size k) { - BNode node(ref); - if (node.InitCheck() == B_OK) { - BNodeInfo nodeInfo(node); - if (nodeInfo.InitCheck() == B_OK) - return nodeInfo.GetTrackerIcon(icon, k); - } - return B_NO_INIT; + // check ref param + status_t error = (ref ? B_OK : B_BAD_VALUE); + // init a BNode + BNode node; + if (error == B_OK) + error = node.SetTo(ref); + // init a BNodeInfo + BNodeInfo nodeInfo; + if (error == B_OK) + error = nodeInfo.SetTo(&node); + // let the non-static GetTrackerIcon() do the dirty work + if (error == B_OK) + error = nodeInfo.GetTrackerIcon(icon, k); + return error; } void @@ -505,6 +732,3 @@ BNodeInfo::BNodeInfo(const BNodeInfo &) { } - - -