From b94857b322093c296230a18d47f6a98a2896b062 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 7 May 2013 23:15:36 +0200 Subject: [PATCH] Refactor MIME DB access * Add class DatabaseLocation. It contains a list of the MIME DB directory paths plus methods to access type files. * Move all low-level MIME DB access functions from database_{support,access} to DatabaseLocation. All code that formerly used those now requires a DatabaseLocation object. In BMimeType and in the registrar the default object is used, but the low-level classes can now be reused with different locations. * Move get_icon_data() from database_access to database_support and delete the former, which is now empty. --- .../private/storage/mime/AssociatedTypes.h | 10 +- headers/private/storage/mime/Database.h | 13 +- .../private/storage/mime/DatabaseDirectory.h | 6 +- .../private/storage/mime/DatabaseLocation.h | 119 +++ headers/private/storage/mime/InstalledTypes.h | 8 +- headers/private/storage/mime/SnifferRules.h | 11 +- headers/private/storage/mime/SupportingApps.h | 11 +- .../private/storage/mime/database_access.h | 49 - .../private/storage/mime/database_support.h | 34 +- src/kits/storage/Mime.cpp | 1 - src/kits/storage/MimeType.cpp | 78 +- src/kits/storage/mime/AssociatedTypes.cpp | 12 +- src/kits/storage/mime/Database.cpp | 68 +- src/kits/storage/mime/DatabaseDirectory.cpp | 7 +- src/kits/storage/mime/DatabaseLocation.cpp | 909 ++++++++++++++++++ src/kits/storage/mime/InstalledTypes.cpp | 7 +- src/kits/storage/mime/Jamfile | 2 +- src/kits/storage/mime/SnifferRules.cpp | 15 +- src/kits/storage/mime/SupportingApps.cpp | 13 +- src/kits/storage/mime/database_access.cpp | 585 ----------- src/kits/storage/mime/database_support.cpp | 483 ++-------- src/servers/registrar/MIMEManager.cpp | 5 +- .../mime/CreateAppMetaMimeThread.cpp | 3 +- 23 files changed, 1294 insertions(+), 1155 deletions(-) create mode 100644 headers/private/storage/mime/DatabaseLocation.h delete mode 100644 headers/private/storage/mime/database_access.h create mode 100644 src/kits/storage/mime/DatabaseLocation.cpp delete mode 100644 src/kits/storage/mime/database_access.cpp diff --git a/headers/private/storage/mime/AssociatedTypes.h b/headers/private/storage/mime/AssociatedTypes.h index 3f484371b8..a4b4e70c73 100644 --- a/headers/private/storage/mime/AssociatedTypes.h +++ b/headers/private/storage/mime/AssociatedTypes.h @@ -21,12 +21,15 @@ namespace BPrivate { namespace Storage { namespace Mime { + +class DatabaseLocation; class MimeSniffer; class AssociatedTypes { public: - AssociatedTypes(MimeSniffer* mimeSniffer); + AssociatedTypes(DatabaseLocation* databaseLocation, + MimeSniffer* mimeSniffer); ~AssociatedTypes(); status_t GetAssociatedTypes(const char *extension, BMessage *types); @@ -50,8 +53,9 @@ private: std::map > fAssociatedTypes; // file extension => set of associated mime types private: - MimeSniffer* fMimeSniffer; - bool fHaveDoneFullBuild; + DatabaseLocation* fDatabaseLocation; + MimeSniffer* fMimeSniffer; + bool fHaveDoneFullBuild; }; } // namespace Mime diff --git a/headers/private/storage/mime/Database.h b/headers/private/storage/mime/Database.h index de5d061a36..2f621d3ea6 100644 --- a/headers/private/storage/mime/Database.h +++ b/headers/private/storage/mime/Database.h @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -36,8 +35,11 @@ namespace BPrivate { namespace Storage { namespace Mime { + +class DatabaseLocation; class MimeSniffer; + // types of mime update functions that may be run asynchronously typedef enum { B_REG_UPDATE_MIME_INFO, @@ -49,16 +51,18 @@ class Database { class NotificationListener; public: - Database(MimeSniffer* mimeSniffer, + Database(DatabaseLocation* databaseLocation, MimeSniffer* mimeSniffer, NotificationListener* notificationListener); ~Database(); - + status_t InitCheck() const; + DatabaseLocation* Location() const { return fLocation; } + // Type management status_t Install(const char *type); status_t Delete(const char *type); - + // Set() status_t SetAppHint(const char *type, const entry_ref *ref); status_t SetAttrInfo(const char *type, const BMessage *info); @@ -142,6 +146,7 @@ class Database { private: status_t fStatus; + DatabaseLocation* fLocation; NotificationListener* fNotificationListener; std::set fMonitorMessengers; AssociatedTypes fAssociatedTypes; diff --git a/headers/private/storage/mime/DatabaseDirectory.h b/headers/private/storage/mime/DatabaseDirectory.h index 4642f2f2d4..8cf8a74af8 100644 --- a/headers/private/storage/mime/DatabaseDirectory.h +++ b/headers/private/storage/mime/DatabaseDirectory.h @@ -17,12 +17,16 @@ namespace Storage { namespace Mime { +class DatabaseLocation; + + class DatabaseDirectory : public BMergedDirectory { public: DatabaseDirectory(); virtual ~DatabaseDirectory(); - status_t Init(const char* superType = NULL); + status_t Init(DatabaseLocation* databaseLocation, + const char* superType = NULL); protected: virtual bool ShallPreferFirstEntry(const entry_ref& entry1, diff --git a/headers/private/storage/mime/DatabaseLocation.h b/headers/private/storage/mime/DatabaseLocation.h new file mode 100644 index 0000000000..22769cbad4 --- /dev/null +++ b/headers/private/storage/mime/DatabaseLocation.h @@ -0,0 +1,119 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef _MIME_DATABASE_LOCATION_H +#define _MIME_DATABASE_LOCATION_H + + +#include +#include + + +namespace BPrivate { +namespace Storage { +namespace Mime { + + +class DatabaseLocation { +public: + DatabaseLocation(); + ~DatabaseLocation(); + + bool AddDirectory(const BString& directory); + + // paths + + const BStringList& Directories() const + { return fDirectories; } + BString WritableDirectory() const + { return fDirectories.StringAt(0); } + + BString WritablePathForType(const char* type) const + { return _TypeToFilename(type, 0); } + + // opening type nodes + + status_t OpenType(const char* type, BNode& _node) const; + status_t OpenOrCreateType(const char* type, + BNode& _node, bool* _didCreate = NULL) + const; + + // generic type attributes access + + ssize_t ReadAttribute(const char* type, + const char* attribute, void* data, + size_t length, type_code datatype) const; + status_t ReadMessageAttribute(const char* type, + const char* attribute, BMessage& _message) + const; + status_t ReadStringAttribute(const char* type, + const char* attribute, BString& _string) + const; + + status_t WriteAttribute(const char* type, + const char* attribute, const void* data, + size_t length, type_code datatype, + bool* _didCreate) const; + status_t WriteMessageAttribute(const char* type, + const char* attribute, + const BMessage& message, bool* _didCreate) + const; + + status_t DeleteAttribute(const char* type, + const char* attribute) const; + + // type attribute convenience getters + + status_t GetAppHint(const char* type, entry_ref& _ref); + status_t GetAttributesInfo(const char* type, + BMessage& _info); + status_t GetShortDescription(const char* type, + char* description); + status_t GetLongDescription(const char* type, + char* description); + status_t GetFileExtensions(const char* type, + BMessage& _extensions); + status_t GetIcon(const char* type, BBitmap& _icon, + icon_size size); + status_t GetIcon(const char* type, uint8*& _data, + size_t& _size); + status_t GetIconForType(const char* type, + const char* fileType, BBitmap& _icon, + icon_size which); + status_t GetIconForType(const char* type, + const char* fileType, uint8*& _data, + size_t& _size); + status_t GetPreferredApp(const char* type, + char* signature, app_verb verb); + status_t GetSnifferRule(const char* type, + BString& _result); + status_t GetSupportedTypes(const char* type, + BMessage& _types); + + bool IsInstalled(const char* type); + +private: + BString _TypeToFilename(const char* type, int32 index) + const; + status_t _OpenType(const char* type, BNode& _node, + int32& _index) const; + status_t _CreateTypeNode(const char* type, BNode& _node) + const; + status_t _CopyTypeNode(BNode& source, const char* type, + BNode& _target) const; + +private: + BStringList fDirectories; +}; + + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + + +#endif // _MIME_DATABASE_LOCATION_H diff --git a/headers/private/storage/mime/InstalledTypes.h b/headers/private/storage/mime/InstalledTypes.h index fa32f10942..fff75e61d8 100644 --- a/headers/private/storage/mime/InstalledTypes.h +++ b/headers/private/storage/mime/InstalledTypes.h @@ -25,9 +25,13 @@ namespace BPrivate { namespace Storage { namespace Mime { + +class DatabaseLocation; + + class InstalledTypes { public: - InstalledTypes(); + InstalledTypes(DatabaseLocation* databaseLocation); ~InstalledTypes(); status_t GetInstalledTypes(BMessage *types); @@ -55,6 +59,8 @@ class InstalledTypes { status_t _BuildInstalledTypesList(); +private: + DatabaseLocation* fDatabaseLocation; std::map fSupertypes; BMessage *fCachedMessage; BMessage *fCachedSupertypesMessage; diff --git a/headers/private/storage/mime/SnifferRules.h b/headers/private/storage/mime/SnifferRules.h index e9c68460a2..eba6d3af87 100644 --- a/headers/private/storage/mime/SnifferRules.h +++ b/headers/private/storage/mime/SnifferRules.h @@ -25,12 +25,14 @@ namespace Sniffer { namespace Mime { + +class DatabaseLocation; class MimeSniffer; class SnifferRules { public: - SnifferRules(MimeSniffer* mimeSniffer); + SnifferRules(DatabaseLocation* databaseLocation, MimeSniffer* mimeSniffer); ~SnifferRules(); status_t GuessMimeType(const entry_ref *ref, BString *type); @@ -59,9 +61,10 @@ private: std::list fRuleList; private: - MimeSniffer* fMimeSniffer; - ssize_t fMaxBytesNeeded; - bool fHaveDoneFullBuild; + DatabaseLocation* fDatabaseLocation; + MimeSniffer* fMimeSniffer; + ssize_t fMaxBytesNeeded; + bool fHaveDoneFullBuild; }; } // namespace Mime diff --git a/headers/private/storage/mime/SupportingApps.h b/headers/private/storage/mime/SupportingApps.h index a7b31c8bf6..f885e486dd 100644 --- a/headers/private/storage/mime/SupportingApps.h +++ b/headers/private/storage/mime/SupportingApps.h @@ -22,11 +22,15 @@ namespace BPrivate { namespace Storage { namespace Mime { + +class DatabaseLocation; + + class SupportingApps { public: - SupportingApps(); + SupportingApps(DatabaseLocation* databaseLocation); ~SupportingApps(); - + status_t GetSupportingApps(const char *type, BMessage *apps); status_t SetSupportedTypes(const char *app, const BMessage *types, bool fullSync); @@ -41,6 +45,9 @@ private: std::map > fSupportingApps; // mime type => set of supporting apps std::map > fStrandedTypes; // app sig => set of no longer supported types for whom the // given app is still listed as a supporting app + +private: + DatabaseLocation* fDatabaseLocation; bool fHaveDoneFullBuild; }; diff --git a/headers/private/storage/mime/database_access.h b/headers/private/storage/mime/database_access.h deleted file mode 100644 index e1ea3397b6..0000000000 --- a/headers/private/storage/mime/database_access.h +++ /dev/null @@ -1,49 +0,0 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -//--------------------------------------------------------------------- -/*! - \file database_access.h - Mime database atomic read functions and miscellany declarations -*/ - -#ifndef _MIME_DATABASE_ACCESS_H -#define _MIME_DATABASE_ACCESS_H - -#include - -class BNode; -class BBitmap; -class BMessage; - -namespace BPrivate { -namespace Storage { -namespace Mime { - -// Get() functions -status_t get_app_hint(const char *type, entry_ref *ref); -status_t get_attr_info(const char *type, BMessage *info); -status_t get_short_description(const char *type, char *description); -status_t get_long_description(const char *type, char *description); -status_t get_file_extensions(const char *type, BMessage *extensions); -status_t get_icon(const char *type, BBitmap *icon, icon_size size); -status_t get_icon(const char *type, uint8** data, size_t* size); -status_t get_icon_for_type(const char *type, const char *fileType, - BBitmap *icon, icon_size which); -status_t get_icon_for_type(const char *type, const char *fileType, - uint8** data, size_t* size); -status_t get_preferred_app(const char *type, char *signature, app_verb verb); -status_t get_sniffer_rule(const char *type, BString *result); -status_t get_supported_types(const char *type, BMessage *types); - -bool is_installed(const char *type); - -// Called by BMimeType to get properly formatted icon data ready -// to be shipped off to SetIcon*() and written to the database -status_t get_icon_data(const BBitmap *icon, icon_size size, void **data, int32 *dataSize); - -} // namespace Mime -} // namespace Storage -} // namespace BPrivate - -#endif // _MIME_DATABASE_H diff --git a/headers/private/storage/mime/database_support.h b/headers/private/storage/mime/database_support.h index 0e54903270..dc280afd8f 100644 --- a/headers/private/storage/mime/database_support.h +++ b/headers/private/storage/mime/database_support.h @@ -1,27 +1,25 @@ /* - * Copyright 2002-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2002-2013, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _MIME_DATABASE_SUPPORT_H #define _MIME_DATABASE_SUPPORT_H -#include -#include +#include +#include -class BNode; -class BMessage; -class BStringList; +class BBitmap; namespace BPrivate { namespace Storage { namespace Mime { -// Database directory -const BStringList& get_database_directories(); -BString get_writable_database_directory(); + +class DatabaseLocation; + // Attribute Prefixes extern const char *kMiniIconAttrPrefix; @@ -75,24 +73,18 @@ extern const char *kMetaMimeType; // Error codes (to be used only by BPrivate::Storage::Mime members) extern const status_t kMimeGuessFailureError; -BString type_to_writable_filename(const char *type); -status_t open_type(const char *type, BNode *result); -status_t open_or_create_type(const char *type, BNode *result, bool *didCreate); +DatabaseLocation* default_database_location(); -ssize_t read_mime_attr(const char *type, const char *attr, void *data, - size_t len, type_code datatype); -status_t read_mime_attr_message(const char *type, const char *attr, BMessage *msg); -status_t read_mime_attr_string(const char *type, const char *attr, BString *str); -status_t write_mime_attr(const char *type, const char *attr, const void *data, - size_t len, type_code datatype, bool *didCreate); -status_t write_mime_attr_message(const char *type, const char *attr, - const BMessage *msg, bool *didCreate); +// Called by BMimeType to get properly formatted icon data ready +// to be shipped off to SetIcon*() and written to the database +status_t get_icon_data(const BBitmap *icon, icon_size size, void **data, + int32 *dataSize); -status_t delete_attribute(const char *type, const char *attr); } // namespace Mime } // namespace Storage } // namespace BPrivate + #endif // _MIME_DATABASE_SUPPORT_H diff --git a/src/kits/storage/Mime.cpp b/src/kits/storage/Mime.cpp index 8058be2594..b3d5d3ddf5 100644 --- a/src/kits/storage/Mime.cpp +++ b/src/kits/storage/Mime.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/src/kits/storage/MimeType.cpp b/src/kits/storage/MimeType.cpp index 15c779497e..b10842188c 100644 --- a/src/kits/storage/MimeType.cpp +++ b/src/kits/storage/MimeType.cpp @@ -12,7 +12,8 @@ #include "MimeType.h" #include -#include +#include +#include #include #include @@ -176,7 +177,8 @@ BMimeType::IsSupertypeOnly() const bool BMimeType::IsInstalled() const { - return InitCheck() == B_OK && is_installed(Type()); + return InitCheck() == B_OK + && default_database_location()->IsInstalled(Type()); } @@ -307,9 +309,12 @@ BMimeType::Delete() status_t BMimeType::GetIcon(BBitmap *icon, icon_size size) const { + if (icon == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); if (!err) - err = get_icon(Type(), icon, size); + err = default_database_location()->GetIcon(Type(), *icon, size); return err; } @@ -319,9 +324,12 @@ BMimeType::GetIcon(BBitmap *icon, icon_size size) const status_t BMimeType::GetIcon(uint8** data, size_t* size) const { + if (data == NULL || size == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); if (!err) - err = get_icon(Type(), data, size); + err = default_database_location()->GetIcon(Type(), *data, *size); return err; } @@ -333,8 +341,10 @@ status_t BMimeType::GetPreferredApp(char *signature, app_verb verb) const { status_t err = InitCheck(); - if (!err) - err = get_preferred_app(Type(), signature, verb); + if (!err) { + err = default_database_location()->GetPreferredApp(Type(), signature, + verb); + } return err; } @@ -345,9 +355,12 @@ BMimeType::GetPreferredApp(char *signature, app_verb verb) const status_t BMimeType::GetAttrInfo(BMessage *info) const { + if (info == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); if (!err) - err = get_attr_info(Type(), info); + err = default_database_location()->GetAttributesInfo(Type(), *info); return err; } @@ -358,9 +371,14 @@ BMimeType::GetAttrInfo(BMessage *info) const status_t BMimeType::GetFileExtensions(BMessage *extensions) const { + if (extensions == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); - if (!err) - err = get_file_extensions(Type(), extensions); + if (!err) { + err = default_database_location()->GetFileExtensions(Type(), + *extensions); + } return err; } @@ -371,8 +389,10 @@ status_t BMimeType::GetShortDescription(char *description) const { status_t err = InitCheck(); - if (!err) - err = get_short_description(Type(), description); + if (!err) { + err = default_database_location()->GetShortDescription(Type(), + description); + } return err; } @@ -383,8 +403,10 @@ status_t BMimeType::GetLongDescription(char *description) const { status_t err = InitCheck(); - if (!err) - err = get_long_description(Type(), description); + if (!err) { + err = default_database_location()->GetLongDescription(Type(), + description); + } return err; } @@ -703,9 +725,12 @@ BMimeType::IsValid(const char *string) status_t BMimeType::GetAppHint(entry_ref *ref) const { + if (ref == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); if (!err) - err = get_app_hint(Type(), ref); + err = default_database_location()->GetAppHint(Type(), *ref); return err; } @@ -745,13 +770,18 @@ BMimeType::SetAppHint(const entry_ref *ref) status_t BMimeType::GetIconForType(const char *type, BBitmap *icon, icon_size which) const { + if (icon == NULL) + return B_BAD_VALUE; + // If type is NULL, this function works just like GetIcon(), othewise, // we need to make sure the give type is valid. status_t err; if (type) { err = BMimeType::IsValid(type) ? B_OK : B_BAD_VALUE; - if (!err) - err = get_icon_for_type(Type(), type, icon, which); + if (!err) { + err = default_database_location()->GetIconForType(Type(), type, + *icon, which); + } } else err = GetIcon(icon, which); @@ -764,6 +794,9 @@ BMimeType::GetIconForType(const char *type, BBitmap *icon, icon_size which) cons status_t BMimeType::GetIconForType(const char *type, uint8** _data, size_t* _size) const { + if (_data == NULL || _size == NULL) + return B_BAD_VALUE; + // If type is NULL, this function works just like GetIcon(), otherwise, // we need to make sure the give type is valid. if (type == NULL) @@ -772,7 +805,8 @@ BMimeType::GetIconForType(const char *type, uint8** _data, size_t* _size) const if (!BMimeType::IsValid(type)) return B_BAD_VALUE; - return get_icon_for_type(Type(), type, _data, _size); + return default_database_location()->GetIconForType(Type(), type, *_data, + *_size); } @@ -871,9 +905,12 @@ BMimeType::SetIconForType(const char* type, const uint8* data, size_t dataSize) status_t BMimeType::GetSnifferRule(BString *result) const { + if (result == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); if (!err) - err = get_sniffer_rule(Type(), result); + err = default_database_location()->GetSnifferRule(Type(), *result); return err; } @@ -1096,9 +1133,12 @@ BMimeType::BMimeType(const BMimeType &) status_t BMimeType::GetSupportedTypes(BMessage *types) { + if (types == NULL) + return B_BAD_VALUE; + status_t err = InitCheck(); if (!err) - err = get_supported_types(Type(), types); + err = default_database_location()->GetSupportedTypes(Type(), *types); return err; } diff --git a/src/kits/storage/mime/AssociatedTypes.cpp b/src/kits/storage/mime/AssociatedTypes.cpp index c292f495e0..e41fde9fd2 100644 --- a/src/kits/storage/mime/AssociatedTypes.cpp +++ b/src/kits/storage/mime/AssociatedTypes.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +41,10 @@ namespace Mime { // Constructor //! Constructs a new AssociatedTypes object -AssociatedTypes::AssociatedTypes(MimeSniffer* mimeSniffer) +AssociatedTypes::AssociatedTypes(DatabaseLocation* databaseLocation, + MimeSniffer* mimeSniffer) : + fDatabaseLocation(databaseLocation), fMimeSniffer(mimeSniffer), fHaveDoneFullBuild(false) { @@ -333,7 +336,7 @@ AssociatedTypes::BuildAssociatedTypesTable() fAssociatedTypes.clear(); DatabaseDirectory root; - status_t err = root.Init(); + status_t err = root.Init(fDatabaseLocation); if (!err) { root.Rewind(); while (true) { @@ -357,7 +360,7 @@ AssociatedTypes::BuildAssociatedTypesTable() // First, iterate through this supertype directory and process // all of its subtypes DatabaseDirectory dir; - if (dir.Init(supertype) == B_OK) { + if (dir.Init(fDatabaseLocation, supertype) == B_OK) { dir.Rewind(); while (true) { BEntry subEntry; @@ -424,7 +427,8 @@ AssociatedTypes::ProcessType(const char *type) if (!err) { // Read in the list of file extension types BMessage msg; - if (read_mime_attr_message(type, kFileExtensionsAttr, &msg) == B_OK) { + if (fDatabaseLocation->ReadMessageAttribute(type, kFileExtensionsAttr, + msg) == B_OK) { // Iterate through the file extesions, adding them to the list of // file extensions for the mime type and adding the mime type // to the list of associated types for each file extension diff --git a/src/kits/storage/mime/Database.cpp b/src/kits/storage/mime/Database.cpp index c653979d10..fd6bec286a 100644 --- a/src/kits/storage/mime/Database.cpp +++ b/src/kits/storage/mime/Database.cpp @@ -30,8 +30,8 @@ #include #include -#include #include +#include #include @@ -64,18 +64,21 @@ Database::NotificationListener::~NotificationListener() // constructor /*! \brief Creates and initializes a Mime::Database object. */ -Database::Database(MimeSniffer* mimeSniffer, +Database::Database(DatabaseLocation* databaseLocation, MimeSniffer* mimeSniffer, NotificationListener* notificationListener) : fStatus(B_NO_INIT), + fLocation(databaseLocation), fNotificationListener(notificationListener), - fAssociatedTypes(mimeSniffer), - fSnifferRules(mimeSniffer), + fAssociatedTypes(databaseLocation, mimeSniffer), + fInstalledTypes(databaseLocation), + fSnifferRules(databaseLocation, mimeSniffer), + fSupportingApps(databaseLocation), fDeferredInstallNotificationsLocker("deferred install notifications"), fDeferredInstallNotifications() { // make sure the user's MIME DB directory exists - fStatus = create_directory(get_writable_database_directory(), + fStatus = create_directory(fLocation->WritableDirectory(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); } @@ -116,14 +119,14 @@ Database::Install(const char *type) return B_BAD_VALUE; BEntry entry; - status_t err = entry.SetTo(type_to_writable_filename(type)); + status_t err = entry.SetTo(fLocation->WritablePathForType(type)); if (!err) { if (entry.Exists()) err = B_FILE_EXISTS; else { bool didCreate = false; BNode node; - err = open_or_create_type(type, &node, &didCreate); + err = fLocation->OpenOrCreateType(type, node, &didCreate); if (!err && didCreate) { fInstalledTypes.AddType(type); _SendInstallNotification(type); @@ -148,7 +151,7 @@ Database::Delete(const char *type) // Open the type BEntry entry; - status_t status = entry.SetTo(type_to_writable_filename(type)); + status_t status = entry.SetTo(fLocation->WritablePathForType(type)); if (status != B_OK) return status; @@ -198,7 +201,7 @@ Database::_SetStringValue(const char *type, int32 what, const char* attribute, return B_BAD_VALUE; char oldValue[maxLength]; - status_t status = read_mime_attr(type, attribute, oldValue, + status_t status = fLocation->ReadAttribute(type, attribute, oldValue, maxLength, attributeType); if (status >= B_OK && !strcmp(value, oldValue)) { // nothing has changed, no need to write back the data @@ -206,7 +209,7 @@ Database::_SetStringValue(const char *type, int32 what, const char* attribute, } bool didCreate = false; - status = write_mime_attr(type, attribute, value, length + 1, + status = fLocation->WriteAttribute(type, attribute, value, length + 1, attributeType, &didCreate); if (status == B_OK) { @@ -267,7 +270,8 @@ Database::SetAttrInfo(const char *type, const BMessage *info) return B_BAD_VALUE; bool didCreate = false; - status_t status = write_mime_attr_message(type, kAttrInfoAttr, info, &didCreate); + status_t status = fLocation->WriteMessageAttribute(type, kAttrInfoAttr, + *info, &didCreate); if (status == B_OK) { if (didCreate) _SendInstallNotification(type); @@ -334,8 +338,8 @@ Database::SetFileExtensions(const char *type, const BMessage *extensions) return B_BAD_VALUE; bool didCreate = false; - status_t status = write_mime_attr_message(type, kFileExtensionsAttr, - extensions, &didCreate); + status_t status = fLocation->WriteMessageAttribute(type, + kFileExtensionsAttr, *extensions, &didCreate); if (status == B_OK) { if (didCreate) { @@ -439,7 +443,7 @@ Database::SetIconForType(const char *type, const char *fileType, BNode node; bool didCreate = false; - status_t err = open_or_create_type(type, &node, &didCreate); + status_t err = fLocation->OpenOrCreateType(type, node, &didCreate); if (err != B_OK) return err; @@ -500,7 +504,7 @@ Database::SetIconForType(const char *type, const char *fileType, BNode node; bool didCreate = false; - status_t err = open_or_create_type(type, &node, &didCreate); + status_t err = fLocation->OpenOrCreateType(type, node, &didCreate); if (err != B_OK) return err; @@ -556,8 +560,8 @@ Database::SetSnifferRule(const char *type, const char *rule) return B_BAD_VALUE; bool didCreate = false; - status_t status = write_mime_attr(type, kSnifferRuleAttr, rule, strlen(rule) + 1, - kSnifferRuleType, &didCreate); + status_t status = fLocation->WriteAttribute(type, kSnifferRuleAttr, rule, + strlen(rule) + 1, kSnifferRuleType, &didCreate); if (status == B_OK) status = fSnifferRules.SetSnifferRule(type, rule); @@ -597,7 +601,7 @@ Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSy // Install the types const char *supportedType; for (int32 i = 0; types->FindString("types", i, &supportedType) == B_OK; i++) { - if (!is_installed(supportedType)) { + if (!fLocation->IsInstalled(supportedType)) { if (Install(supportedType) != B_OK) break; @@ -610,8 +614,8 @@ Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSy // Write the attr bool didCreate = false; - status_t status = write_mime_attr_message(type, kSupportedTypesAttr, types, - &didCreate); + status_t status = fLocation->WriteMessageAttribute(type, + kSupportedTypesAttr, *types, &didCreate); // Notify the monitor if we created the type when we opened it if (status != B_OK) @@ -976,7 +980,7 @@ Database::StopWatching(BMessenger target) status_t Database::DeleteAppHint(const char *type) { - status_t status = delete_attribute(type, kAppHintAttr); + status_t status = fLocation->DeleteAttribute(type, kAppHintAttr); if (status == B_OK) _SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED); else if (status == B_ENTRY_NOT_FOUND) @@ -998,7 +1002,7 @@ Database::DeleteAppHint(const char *type) status_t Database::DeleteAttrInfo(const char *type) { - status_t status = delete_attribute(type, kAttrInfoAttr); + status_t status = fLocation->DeleteAttribute(type, kAttrInfoAttr); if (status == B_OK) _SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED); else if (status == B_ENTRY_NOT_FOUND) @@ -1020,7 +1024,7 @@ Database::DeleteAttrInfo(const char *type) status_t Database::DeleteShortDescription(const char *type) { - status_t status = delete_attribute(type, kShortDescriptionAttr); + status_t status = fLocation->DeleteAttribute(type, kShortDescriptionAttr); if (status == B_OK) _SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); else if (status == B_ENTRY_NOT_FOUND) @@ -1042,7 +1046,7 @@ Database::DeleteShortDescription(const char *type) status_t Database::DeleteLongDescription(const char *type) { - status_t status = delete_attribute(type, kLongDescriptionAttr); + status_t status = fLocation->DeleteAttribute(type, kLongDescriptionAttr); if (status == B_OK) _SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); else if (status == B_ENTRY_NOT_FOUND) @@ -1064,7 +1068,7 @@ Database::DeleteLongDescription(const char *type) status_t Database::DeleteFileExtensions(const char *type) { - status_t status = delete_attribute(type, kFileExtensionsAttr); + status_t status = fLocation->DeleteAttribute(type, kFileExtensionsAttr); if (status == B_OK) _SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED); else if (status == B_ENTRY_NOT_FOUND) @@ -1088,7 +1092,7 @@ status_t Database::DeleteIcon(const char *type, icon_size which) { const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; - status_t status = delete_attribute(type, attr); + status_t status = fLocation->DeleteAttribute(type, attr); if (status == B_OK) _SendMonitorUpdate(B_ICON_CHANGED, type, which, B_META_MIME_DELETED); else if (status == B_ENTRY_NOT_FOUND) @@ -1111,7 +1115,7 @@ status_t Database::DeleteIcon(const char *type) { // TODO: extra notification for vector icon (uses B_LARGE_ICON now) - status_t status = delete_attribute(type, kIconAttr); + status_t status = fLocation->DeleteAttribute(type, kIconAttr); if (status == B_OK) { _SendMonitorUpdate(B_ICON_CHANGED, type, B_LARGE_ICON, B_META_MIME_DELETED); @@ -1146,7 +1150,7 @@ Database::DeleteIconForType(const char *type, const char *fileType, icon_size wh std::string attr = (which == B_MINI_ICON ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType); - status_t status = delete_attribute(type, attr.c_str()); + status_t status = fLocation->DeleteAttribute(type, attr.c_str()); if (status == B_OK) { _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, which == B_LARGE_ICON, B_META_MIME_DELETED); @@ -1181,7 +1185,7 @@ Database::DeleteIconForType(const char *type, const char *fileType) // TODO: introduce extra notification for vector icons? // (uses B_LARGE_ICON now) - status_t status = delete_attribute(type, attr.c_str()); + status_t status = fLocation->DeleteAttribute(type, attr.c_str()); if (status == B_OK) { _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, true, B_META_MIME_DELETED); @@ -1209,7 +1213,7 @@ Database::DeletePreferredApp(const char *type, app_verb verb) switch (verb) { case B_OPEN: - status = delete_attribute(type, kPreferredAppAttr); + status = fLocation->DeleteAttribute(type, kPreferredAppAttr); break; default: @@ -1242,7 +1246,7 @@ Database::DeletePreferredApp(const char *type, app_verb verb) status_t Database::DeleteSnifferRule(const char *type) { - status_t status = delete_attribute(type, kSnifferRuleAttr); + status_t status = fLocation->DeleteAttribute(type, kSnifferRuleAttr); if (status == B_OK) { status = fSnifferRules.DeleteSnifferRule(type); if (status == B_OK) { @@ -1274,7 +1278,7 @@ Database::DeleteSnifferRule(const char *type) status_t Database::DeleteSupportedTypes(const char *type, bool fullSync) { - status_t status = delete_attribute(type, kSupportedTypesAttr); + status_t status = fLocation->DeleteAttribute(type, kSupportedTypesAttr); // Update the supporting apps database. If fullSync is specified, // do so even if the supported types attribute didn't exist, as diff --git a/src/kits/storage/mime/DatabaseDirectory.cpp b/src/kits/storage/mime/DatabaseDirectory.cpp index 1f62a509f8..58f22f0a62 100644 --- a/src/kits/storage/mime/DatabaseDirectory.cpp +++ b/src/kits/storage/mime/DatabaseDirectory.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace BPrivate { @@ -34,14 +35,14 @@ DatabaseDirectory::~DatabaseDirectory() status_t -DatabaseDirectory::Init(const char* superType) +DatabaseDirectory::Init(DatabaseLocation* databaseLocation, + const char* superType) { status_t error = BMergedDirectory::Init(); if (error != B_OK) return error; - const BStringList& directories - = BPrivate::Storage::Mime::get_database_directories(); + const BStringList& directories = databaseLocation->Directories(); int32 count = directories.CountStrings(); for (int32 i = 0; i < count; i++) { BString directory = directories.StringAt(i); diff --git a/src/kits/storage/mime/DatabaseLocation.cpp b/src/kits/storage/mime/DatabaseLocation.cpp new file mode 100644 index 0000000000..b00af66c7a --- /dev/null +++ b/src/kits/storage/mime/DatabaseLocation.cpp @@ -0,0 +1,909 @@ +/* + * Copyright 2002-2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Tyler Dauwalder + * Ingo Weinhold + */ + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace BPrivate { +namespace Storage { +namespace Mime { + + +DatabaseLocation::DatabaseLocation() + : + fDirectories() +{ +} + + +DatabaseLocation::~DatabaseLocation() +{ +} + + +bool +DatabaseLocation::AddDirectory(const BString& directory) +{ + return !directory.IsEmpty() && fDirectories.Add(directory); +} + + +/*! \brief Opens a BNode on the given type, failing if the type has no + corresponding file in the database. + \param type The MIME type to open. + \param _node Node opened on the given MIME type. +*/ +status_t +DatabaseLocation::OpenType(const char* type, BNode& _node) const +{ + if (type == NULL) + return B_BAD_VALUE; + + int32 index; + return _OpenType(type, _node, index); +} + + +/*! \brief Opens a BNode on the given type, creating a node of the + appropriate flavor if necessary. + All MIME types are converted to lowercase for use in the filesystem. + \param type The MIME type to open. + \param _node Node opened on the given MIME type. + \param _didCreate If not \c NULL, the variable the pointer refers to is + set to \c true, if the node has been newly create, to \c false + otherwise. +*/ +status_t +DatabaseLocation::OpenOrCreateType(const char* type, BNode& _node, + bool* _didCreate) const +{ + if (_didCreate) + *_didCreate = false; + + // See, if the type already exists. + int32 index; + status_t error = _OpenType(type, _node, index); + if (error == B_OK) { + if (index == 0) + return B_OK; + + // The caller wants a editable node, but the node found is not in the + // user's settings directory. Copy the node. + BNode nodeToClone(_node); + if (nodeToClone.InitCheck() != B_OK) + return nodeToClone.InitCheck(); + + error = _CopyTypeNode(nodeToClone, type, _node); + if (error != B_OK) { + _node.Unset(); + return error; + } + + if (_didCreate != NULL) + *_didCreate = true; + return error; + } + + // type doesn't exist yet -- create the respective node + error = _CreateTypeNode(type, _node); + if (error != B_OK) + return error; + + // write the type attribute + error = _node.WriteAttr(kTypeAttr, B_STRING_TYPE, 0, type, + strlen(type) + 1); + if (error != B_OK) { + _node.Unset(); + return error; + } + + if (_didCreate != NULL) + *_didCreate = true; + return B_OK; +} + + +/*! \brief Reads up to \c len bytes of the given data from the given attribute + for the given MIME type. + + If no entry for the given type exists in the database, the function fails, + and the contents of \c data are undefined. + + \param type The MIME type + \param attribute The attribute name + \param data Pointer to a memory buffer into which the data should be copied + \param length The maximum number of bytes to read + \param datatype The expected data type + \return If successful, the number of bytes read is returned, otherwise, an + error code is returned. +*/ +ssize_t +DatabaseLocation::ReadAttribute(const char* type, const char* attribute, + void* data, size_t length, type_code datatype) const +{ + if (type == NULL || attribute == NULL || data == NULL) + return B_BAD_VALUE; + + BNode node; + status_t error = OpenType(type, node); + if (error != B_OK) + return error; + + return node.ReadAttr(attribute, datatype, 0, data, length); +} + + +/*! \brief Reads a flattened BMessage from the given attribute of the given + MIME type. + + If no entry for the given type exists in the database, or if the data + stored in the attribute is not a flattened BMessage, the function fails + and the contents of \c msg are undefined. + + \param type The MIME type + \param attribute The attribute name + \param data Reference to a pre-allocated BMessage into which the attribute + data is unflattened. +*/ +status_t +DatabaseLocation::ReadMessageAttribute(const char* type, const char* attribute, + BMessage& _message) const +{ + if (type == NULL || attribute == NULL) + return B_BAD_VALUE; + + BNode node; + attr_info info; + + status_t error = OpenType(type, node); + if (error != B_OK) + return error; + + error = node.GetAttrInfo(attribute, &info); + if (error != B_OK) + return error; + + if (info.type != B_MESSAGE_TYPE) + return B_BAD_VALUE; + + void* buffer = malloc(info.size); + if (buffer == NULL) + return B_NO_MEMORY; + MemoryDeleter bufferDeleter(buffer); + + ssize_t bytesRead = node.ReadAttr(attribute, B_MESSAGE_TYPE, 0, buffer, + info.size); + if (bytesRead != info.size) + return bytesRead < 0 ? (status_t)bytesRead : (status_t)B_FILE_ERROR; + + return _message.Unflatten((const char*)buffer); +} + + +/*! \brief Reads a BString from the given attribute of the given + MIME type. + + If no entry for the given type exists in the database, the function fails + and the contents of \c str are undefined. + + \param type The MIME type + \param attribute The attribute name + \param _string Reference to a pre-allocated BString into which the attribute + data stored. +*/ +status_t +DatabaseLocation::ReadStringAttribute(const char* type, const char* attribute, + BString& _string) const +{ + if (type == NULL || attribute == NULL) + return B_BAD_VALUE; + + BNode node; + status_t error = OpenType(type, node); + if (error != B_OK) + return error; + + return node.ReadAttrString(attribute, &_string); +} + + +/*! \brief Writes \c len bytes of the given data to the given attribute + for the given MIME type. + + If no entry for the given type exists in the database, it is created. + + \param type The MIME type + \param attribute The attribute name + \param data Pointer to the data to write + \param length The number of bytes to write + \param datatype The data type of the given data +*/ +status_t +DatabaseLocation::WriteAttribute(const char* type, const char* attribute, + const void* data, size_t length, type_code datatype, bool* _didCreate) const +{ + if (type == NULL || attribute == NULL || data == NULL) + return B_BAD_VALUE; + + BNode node; + status_t error = OpenOrCreateType(type, node, _didCreate); + if (error != B_OK) + return error; + + ssize_t bytesWritten = node.WriteAttr(attribute, datatype, 0, data, length); + if (bytesWritten < 0) + return bytesWritten; + return bytesWritten == (ssize_t)length ? B_OK : B_FILE_ERROR; +} + + +/*! \brief Flattens the given \c BMessage and writes it to the given attribute + of the given MIME type. + + If no entry for the given type exists in the database, it is created. + + \param type The MIME type + \param attribute The attribute name + \param message The BMessage to flatten and write +*/ +status_t +DatabaseLocation::WriteMessageAttribute(const char* type, const char* attribute, + const BMessage& message, bool* _didCreate) const +{ + BMallocIO data; + status_t error = data.SetSize(message.FlattenedSize()); + if (error != B_OK) + return error; + + ssize_t bytes; + error = message.Flatten(&data, &bytes); + if (error != B_OK) + return error; + + return WriteAttribute(type, attribute, data.Buffer(), data.BufferLength(), + B_MESSAGE_TYPE, _didCreate); +} + + +//! Deletes the given attribute for the given type +/*! + \param type The mime type + \param attribute The attribute name + \return + - B_OK: success + - B_ENTRY_NOT_FOUND: no such type or attribute + - "error code": failure +*/ +status_t +DatabaseLocation::DeleteAttribute(const char* type, const char* attribute) const +{ + if (type == NULL || attribute == NULL) + return B_BAD_VALUE; + + BNode node; + int32 index; + status_t error = _OpenType(type, node, index); + if (error != B_OK) + return error; + + if (index != 0) + return B_NOT_ALLOWED; + + return node.RemoveAttr(attribute); +} + + +/*! \brief Fetches the application hint for the given MIME type. + + The entry_ref pointed to by \c ref must be pre-allocated. + + \param type The MIME type of interest + \param _ref Reference to a pre-allocated \c entry_ref struct into + which the location of the hint application is copied. + + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No app hint exists for the given type + - "error code": Failure +*/ +status_t +DatabaseLocation::GetAppHint(const char* type, entry_ref& _ref) +{ + if (type == NULL) + return B_BAD_VALUE; + + char path[B_PATH_NAME_LENGTH]; + BEntry entry; + ssize_t status = ReadAttribute(type, kAppHintAttr, path, B_PATH_NAME_LENGTH, + kAppHintType); + + if (status >= B_OK) + status = entry.SetTo(path); + if (status == B_OK) + status = entry.GetRef(&_ref); + + return status; +} + + +/*! \brief Fetches from the MIME database a BMessage describing the attributes + typically associated with files of the given MIME type + + The attribute information is returned in a pre-allocated BMessage pointed to + by the \c info parameter (note that the any prior contents of the message + will be destroyed). Please see BMimeType::SetAttrInfo() for a description + of the expected format of such a message. + + \param _info Reference to a pre-allocated BMessage into which information + about the MIME type's associated file attributes is stored. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +DatabaseLocation::GetAttributesInfo(const char* type, BMessage& _info) +{ + status_t err = ReadMessageAttribute(type, kAttrInfoAttr, _info); + if (err == B_ENTRY_NOT_FOUND) { + // return an empty message + _info.MakeEmpty(); + err = B_OK; + } + if (err == B_OK) { + _info.what = 233; + // Don't know why, but that's what R5 does. + err = _info.AddString("type", type); + } + return err; +} + + +/*! \brief Fetches the short description for the given MIME type. + + The string pointed to by \c description must be long enough to + hold the short description; a length of \c B_MIME_TYPE_LENGTH is + recommended. + + \param type The MIME type of interest + \param description Pointer to a pre-allocated string into which the short + description is copied. If the function fails, the contents of the string + are undefined. + + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No short description exists for the given type + - "error code": Failure +*/ +status_t +DatabaseLocation::GetShortDescription(const char* type, char* description) +{ + ssize_t err = ReadAttribute(type, kShortDescriptionAttr, description, + B_MIME_TYPE_LENGTH, kShortDescriptionType); + return err >= 0 ? B_OK : err ; +} + + +//! Fetches the long description for the given MIME type. +/*! The string pointed to by \c description must be long enough to + hold the long description; a length of \c B_MIME_TYPE_LENGTH is + recommended. + + \param type The MIME type of interest + \param description Pointer to a pre-allocated string into which the long + description is copied. If the function fails, the contents of the string + are undefined. + + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No long description exists for the given type + - "error code": Failure +*/ +status_t +DatabaseLocation::GetLongDescription(const char* type, char* description) +{ + ssize_t err = ReadAttribute(type, kLongDescriptionAttr, description, + B_MIME_TYPE_LENGTH, kLongDescriptionType); + return err >= 0 ? B_OK : err ; +} + + +/*! \brief Fetches a BMessage describing the MIME type's associated filename + extensions + + The list of extensions is returned in a pre-allocated BMessage pointed to + by the \c extensions parameter (note that the any prior contents of the + message will be destroyed). Please see BMimeType::GetFileExtensions() for + a description of the message format. + + \param extensions Reference to a pre-allocated BMessage into which the MIME + type's associated file extensions will be stored. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +DatabaseLocation::GetFileExtensions(const char* type, BMessage& _extensions) +{ + status_t err = ReadMessageAttribute(type, kFileExtensionsAttr, _extensions); + if (err == B_ENTRY_NOT_FOUND) { + // return an empty message + _extensions.MakeEmpty(); + err = B_OK; + } + if (err == B_OK) { + _extensions.what = 234; // Don't know why, but that's what R5 does. + err = _extensions.AddString("type", type); + } + return err; +} + + +/*! \brief Fetches the icon of given size associated with the given MIME type + + The bitmap pointed to by \c icon must be of the proper size (\c 32x32 + for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and color depth + (\c B_CMAP8). + + \param type The mime type + \param icon Reference to a pre-allocated bitmap of proper dimensions and + color depth + \param size The size icon you're interested in (\c B_LARGE_ICON or + \c B_MINI_ICON) +*/ +status_t +DatabaseLocation::GetIcon(const char* type, BBitmap& _icon, icon_size size) +{ + return GetIconForType(type, NULL, _icon, size); +} + + +//! Fetches the vector icon associated with the given MIME type +/** \param type The mime type + \param _data Reference via which the allocated icon data is returned. You + need to free the buffer once you're done with it. + \param _size Reference via which the size of the icon data is returned. +*/ +status_t +DatabaseLocation::GetIcon(const char* type, uint8*& _data, size_t& _size) +{ + return GetIconForType(type, NULL, _data, _size); +} + + +/*! \brief Fetches the large or mini icon used by an application of this type + for files of the given type. + + The type of the \c BMimeType object is not required to actually be a subtype + of \c "application/"; that is the intended use however, and calling + \c GetIconForType() on a non-application type will likely return + \c B_ENTRY_NOT_FOUND. + + The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap + must be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini + icon. + + \param type The MIME type + \param fileType Pointer to a pre-allocated string containing the MIME type + whose custom icon you wish to fetch. If NULL, works just like + GetIcon(). + \param icon Reference to a pre-allocated \c BBitmap of proper size and + colorspace into which the icon is copied. + \param icon_size Value that specifies which icon to return. Currently + \c B_LARGE_ICON and \c B_MINI_ICON are supported. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type + - "error code": Failure + +*/ +status_t +DatabaseLocation::GetIconForType(const char* type, const char* fileType, + BBitmap& _icon, icon_size which) +{ + if (type == NULL) + return B_BAD_VALUE; + + // open the node for the given type + BNode node; + ssize_t err = OpenType(type, node); + if (err < B_OK) + return (status_t)err; + + // construct our attribute name + BString vectorIconAttrName; + BString smallIconAttrName; + BString largeIconAttrName; + + if (fileType) { + BString lowerCaseFileType(fileType); + lowerCaseFileType.ToLower(); + + vectorIconAttrName << kIconAttrPrefix << lowerCaseFileType; + smallIconAttrName << kMiniIconAttrPrefix << lowerCaseFileType; + largeIconAttrName << kLargeIconAttrPrefix << lowerCaseFileType; + } else { + vectorIconAttrName = kIconAttr; + smallIconAttrName = kMiniIconAttr; + largeIconAttrName = kLargeIconAttr; + } + + return BIconUtils::GetIcon(&node, vectorIconAttrName, smallIconAttrName, + largeIconAttrName, which, &_icon); + +// ssize_t err = type && icon ? B_OK : B_BAD_VALUE; +// +// // Figure out what kind of data we *should* find +// uint32 attrType = 0; +// ssize_t attrSize = 0; +// BRect bounds; +// +// if (!err) { +// switch (which) { +// case B_MINI_ICON: +// bounds.Set(0, 0, 15, 15); +// attrType = kMiniIconType; +// attrSize = 16 * 16; +// break; +// case B_LARGE_ICON: +// bounds.Set(0, 0, 31, 31); +// attrType = kLargeIconType; +// attrSize = 32 * 32; +// break; +// default: +// err = B_BAD_VALUE; +// break; +// } +// } +// // Construct our attribute name +// std::string attr; +// if (fileType) { +// attr = (which == B_MINI_ICON +// ? kMiniIconAttrPrefix +// : kLargeIconAttrPrefix) +// + BPrivate::Storage::to_lower(fileType); +// } else { +// attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr; +// } +// // Check the icon and attribute to see if they match +// if (!err) { +// err = (icon->InitCheck() == B_OK +// && icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE; +// } +// +// BNode node; +// if (!err) +// err = open_type(type, &node); +// +// attr_info info; +// if (!err) +// err = node.GetAttrInfo(attr.c_str(), &info); +// +// if (!err) +// err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE; +// // read the attribute +// if (!err) { +// bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); +// char *buffer = NULL; +// if (otherColorSpace) { +// // other color space than stored in attribute +// buffer = new(std::nothrow) char[attrSize]; +// if (!buffer) +// err = B_NO_MEMORY; +// if (!err) +// err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize); +// } else { +// // same color space, just read direct +// err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize); +// } +// if (err >= 0) +// err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR; +// if (otherColorSpace) { +// if (!err) { +// err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, +// 0, B_CMAP8); +// } +// delete[] buffer; +// } +// } +// +// return err; +} + + +/*! \brief Fetches the vector icon used by an application of this type for files + of the given type. + + The type of the \c BMimeType object is not required to actually be a subtype + of \c "application/"; that is the intended use however, and calling + \c GetIconForType() on a non-application type will likely return + \c B_ENTRY_NOT_FOUND. + + The icon data is allocated and returned in \a _data. + + \param type The MIME type + \param fileType Reference to a pre-allocated string containing the MIME type + whose custom icon you wish to fetch. If NULL, works just like GetIcon(). + \param _data Reference via which the icon data is returned on success. + \param _size Reference via which the size of the icon data is returned. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No vector icon exists for the given type + - "error code": Failure +*/ +status_t +DatabaseLocation::GetIconForType(const char* type, const char* fileType, + uint8*& _data, size_t& _size) +{ + if (type == NULL) + return B_BAD_VALUE; + + // open the node for the given type + BNode node; + ssize_t err = OpenType(type, node); + if (err < B_OK) + return (status_t)err; + + // construct our attribute name + BString iconAttrName; + + if (fileType) + iconAttrName << kIconAttrPrefix << BString(fileType).ToLower(); + else + iconAttrName = kIconAttr; + + // get info about attribute for that name + attr_info info; + if (!err) + err = node.GetAttrInfo(iconAttrName, &info); + + // validate attribute type + if (!err) + err = (info.type == B_VECTOR_ICON_TYPE) ? B_OK : B_BAD_VALUE; + + // allocate a buffer and read the attribute data into it + if (!err) { + uint8* buffer = new(std::nothrow) uint8[info.size]; + if (!buffer) + err = B_NO_MEMORY; + if (!err) { + err = node.ReadAttr(iconAttrName, B_VECTOR_ICON_TYPE, 0, buffer, + info.size); + } + + if (err >= 0) + err = (err == info.size) ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; + + if (!err) { + // success, set data pointer and size + _data = buffer; + _size = info.size; + } else { + delete[] buffer; + } + } + + return err; +} + + +/*! \brief Fetches signature of the MIME type's preferred application for the + given action. + + The string pointed to by \c signature must be long enough to + hold the short description; a length of \c B_MIME_TYPE_LENGTH is + recommended. + + Currently, the only supported app verb is \c B_OPEN. + + \param type The MIME type of interest + \param description Pointer to a pre-allocated string into which the + preferred application's signature is copied. If the function fails, + the contents of the string are undefined. + \param verb \c The action of interest + + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No such preferred application exists + - "error code": Failure +*/ +status_t +DatabaseLocation::GetPreferredApp(const char* type, char* signature, + app_verb verb) +{ + // Since B_OPEN is the currently the only app_verb, it is essentially + // ignored + ssize_t err = ReadAttribute(type, kPreferredAppAttr, signature, + B_MIME_TYPE_LENGTH, kPreferredAppType); + return err >= 0 ? B_OK : err ; +} + + +/*! \brief Fetches the sniffer rule for the given MIME type. + \param type The MIME type of interest + \param _result Pointer to a pre-allocated BString into which the type's + sniffer rule is copied. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No such preferred application exists + - "error code": Failure +*/ +status_t +DatabaseLocation::GetSnifferRule(const char* type, BString& _result) +{ + return ReadStringAttribute(type, kSnifferRuleAttr, _result); +} + + +status_t +DatabaseLocation::GetSupportedTypes(const char* type, BMessage& _types) +{ + status_t err = ReadMessageAttribute(type, kSupportedTypesAttr, _types); + if (err == B_ENTRY_NOT_FOUND) { + // return an empty message + _types.MakeEmpty(); + err = B_OK; + } + if (err == B_OK) { + _types.what = 0; + err = _types.AddString("type", type); + } + return err; +} + + +//! Checks if the given MIME type is present in the database +bool +DatabaseLocation::IsInstalled(const char* type) +{ + BNode node; + return OpenType(type, node) == B_OK; +} + + +BString +DatabaseLocation::_TypeToFilename(const char* type, int32 index) const +{ + BString path = fDirectories.StringAt(index); + return path << '/' << BString(type).ToLower(); +} + + +status_t +DatabaseLocation::_OpenType(const char* type, BNode& _node, int32& _index) const +{ + int32 count = fDirectories.CountStrings(); + for (int32 i = 0; i < count; i++) { + status_t error = _node.SetTo(_TypeToFilename(type, i)); + attr_info attrInfo; + if (error == B_OK && _node.GetAttrInfo(kTypeAttr, &attrInfo) == B_OK) { + _index = i; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +DatabaseLocation::_CreateTypeNode(const char* type, BNode& _node) const +{ + const char* slash = strchr(type, '/'); + BString superTypeName; + if (slash != NULL) + superTypeName.SetTo(type, slash - type); + else + superTypeName = type; + superTypeName.ToLower(); + + // open/create the directory for the supertype + BDirectory parent(WritableDirectory()); + status_t error = parent.InitCheck(); + if (error != B_OK) + return error; + + BDirectory superTypeDirectory; + if (BEntry(&parent, superTypeName).Exists()) + error = superTypeDirectory.SetTo(&parent, superTypeName); + else + error = parent.CreateDirectory(superTypeName, &superTypeDirectory); + if (error != B_OK) + return error; + + // create the subtype + BFile subTypeFile; + if (slash != NULL) { + error = superTypeDirectory.CreateFile(BString(slash + 1).ToLower(), + &subTypeFile); + if (error != B_OK) + return error; + } + + // assign the result + if (slash != NULL) + _node = subTypeFile; + else + _node = superTypeDirectory; + return _node.InitCheck(); +} + + +status_t +DatabaseLocation::_CopyTypeNode(BNode& source, const char* type, BNode& _target) + const +{ + status_t error = _CreateTypeNode(type, _target); + if (error != B_OK) + return error; + + // copy the attributes + MemoryDeleter bufferDeleter; + size_t bufferSize = 0; + + source.RewindAttrs(); + char attribute[B_ATTR_NAME_LENGTH]; + while (source.GetNextAttrName(attribute) == B_OK) { + attr_info info; + error = source.GetAttrInfo(attribute, &info); + if (error != B_OK) { + syslog(LOG_ERR, "Failed to get info for attribute \"%s\" of MIME " + "type \"%s\": %s", attribute, type, strerror(error)); + continue; + } + + // resize our buffer, if necessary + if (info.size > bufferSize) { + bufferDeleter.SetTo(malloc(info.size)); + if (bufferDeleter.Get() == NULL) + return B_NO_MEMORY; + bufferSize = info.size; + } + + ssize_t bytesRead = source.ReadAttr(attribute, info.type, 0, + bufferDeleter.Get(), info.size); + if (bytesRead != info.size) { + syslog(LOG_ERR, "Failed to read attribute \"%s\" of MIME " + "type \"%s\": %s", attribute, type, + bytesRead < 0 ? strerror(bytesRead) : "short read"); + continue; + } + + ssize_t bytesWritten = _target.WriteAttr(attribute, info.type, 0, + bufferDeleter.Get(), info.size); + if (bytesWritten < 0) { + syslog(LOG_ERR, "Failed to write attribute \"%s\" of MIME " + "type \"%s\": %s", attribute, type, + bytesWritten < 0 ? strerror(bytesWritten) : "short write"); + continue; + } + } + + return B_OK; +} + + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate diff --git a/src/kits/storage/mime/InstalledTypes.cpp b/src/kits/storage/mime/InstalledTypes.cpp index b4dbd3842a..2961796cdc 100644 --- a/src/kits/storage/mime/InstalledTypes.cpp +++ b/src/kits/storage/mime/InstalledTypes.cpp @@ -40,8 +40,9 @@ namespace Mime { */ //! Constructs a new InstalledTypes object -InstalledTypes::InstalledTypes() +InstalledTypes::InstalledTypes(DatabaseLocation* databaseLocation) : + fDatabaseLocation(databaseLocation), fCachedMessage(NULL), fCachedSupertypesMessage(NULL), fHaveDoneFullBuild(false) @@ -385,7 +386,7 @@ InstalledTypes::_BuildInstalledTypesList() DatabaseDirectory root; if (!err) - err = root.Init(); + err = root.Init(fDatabaseLocation); if (!err) { root.Rewind(); while (true) { @@ -417,7 +418,7 @@ InstalledTypes::_BuildInstalledTypesList() // Now iterate through this supertype directory and add // all of its subtypes DatabaseDirectory dir; - if (dir.Init(supertype) == B_OK) { + if (dir.Init(fDatabaseLocation, supertype) == B_OK) { dir.Rewind(); while (true) { BEntry subEntry; diff --git a/src/kits/storage/mime/Jamfile b/src/kits/storage/mime/Jamfile index 0ee32705cc..d736873f74 100644 --- a/src/kits/storage/mime/Jamfile +++ b/src/kits/storage/mime/Jamfile @@ -13,7 +13,7 @@ StaticLibrary libstorage_kit_mime.a : AssociatedTypes.cpp Database.cpp DatabaseDirectory.cpp - database_access.cpp + DatabaseLocation.cpp database_support.cpp InstalledTypes.cpp MimeSniffer.cpp diff --git a/src/kits/storage/mime/SnifferRules.cpp b/src/kits/storage/mime/SnifferRules.cpp index 119d5e0416..bee94c6173 100644 --- a/src/kits/storage/mime/SnifferRules.cpp +++ b/src/kits/storage/mime/SnifferRules.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -112,8 +113,10 @@ bool operator<(SnifferRules::sniffer_rule &left, SnifferRules::sniffer_rule &rig // Constructor //! Constructs a new SnifferRules object -SnifferRules::SnifferRules(MimeSniffer* mimeSniffer) +SnifferRules::SnifferRules(DatabaseLocation* databaseLocation, + MimeSniffer* mimeSniffer) : + fDatabaseLocation(databaseLocation), fMimeSniffer(mimeSniffer), fMaxBytesNeeded(0), fHaveDoneFullBuild(false) @@ -338,7 +341,7 @@ SnifferRules::BuildRuleList() ssize_t bytesNeeded = 0; DatabaseDirectory root; - status_t err = root.Init(); + status_t err = root.Init(fDatabaseLocation); if (!err) { root.Rewind(); while (true) { @@ -362,7 +365,7 @@ SnifferRules::BuildRuleList() // First, iterate through this supertype directory and process // all of its subtypes DatabaseDirectory dir; - if (dir.Init(supertype) == B_OK) { + if (dir.Init(fDatabaseLocation, supertype) == B_OK) { dir.Rewind(); while (true) { BEntry subEntry; @@ -562,8 +565,10 @@ SnifferRules::ProcessType(const char *type, ssize_t *bytesNeeded) if (!err) err = rule.rule ? B_OK : B_NO_MEMORY; // Read the attr - if (!err) - err = read_mime_attr_string(type, kSnifferRuleAttr, &str); + if (!err) { + err = fDatabaseLocation->ReadStringAttribute(type, kSnifferRuleAttr, + str); + } // Parse the rule if (!err) { err = Sniffer::parse(str.String(), rule.rule, &errorMsg); diff --git a/src/kits/storage/mime/SupportingApps.cpp b/src/kits/storage/mime/SupportingApps.cpp index 7f1f8b94be..4689462bb7 100644 --- a/src/kits/storage/mime/SupportingApps.cpp +++ b/src/kits/storage/mime/SupportingApps.cpp @@ -24,6 +24,7 @@ #include #include +#include #include @@ -42,8 +43,10 @@ namespace Mime { // Constructor //! Constructs a new SupportingApps object -SupportingApps::SupportingApps() - : fHaveDoneFullBuild(false) +SupportingApps::SupportingApps(DatabaseLocation* databaseLocation) + : + fDatabaseLocation(databaseLocation), + fHaveDoneFullBuild(false) { } @@ -266,7 +269,7 @@ SupportingApps::BuildSupportingAppsTable() fStrandedTypes.clear(); DatabaseDirectory dir; - status_t status = dir.Init("application"); + status_t status = dir.Init(fDatabaseLocation, "application"); // Build the supporting apps table based on the mime database if (status == B_OK) { @@ -290,8 +293,8 @@ SupportingApps::BuildSupportingAppsTable() &appSignature) >= B_OK) { // Read in the list of supported types BMessage msg; - if (read_mime_attr_message(appSignature.String(), kSupportedTypesAttr, - &msg) == B_OK) { + if (fDatabaseLocation->ReadMessageAttribute(appSignature, + kSupportedTypesAttr, msg) == B_OK) { // Iterate through the supported types, adding them to the list of // supported types for the application and adding the application's // signature to the list of supporting apps for each type diff --git a/src/kits/storage/mime/database_access.cpp b/src/kits/storage/mime/database_access.cpp deleted file mode 100644 index b227a182d2..0000000000 --- a/src/kits/storage/mime/database_access.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright 2002-2007, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Tyler Dauwalder - */ - - -/*! - \file database_access.cpp - Mime database atomic read functions -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // For struct attr_info -#include -#include // For new(nothrow) -#include -#include - - -#define DBG(x) x -//#define DBG(x) -#define OUT printf - -namespace BPrivate { -namespace Storage { -namespace Mime { - - -/*! \brief Fetches the application hint for the given MIME type. - - The entry_ref pointed to by \c ref must be pre-allocated. - - \param type The MIME type of interest - \param ref Pointer to a pre-allocated \c entry_ref struct into - which the location of the hint application is copied. - - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No app hint exists for the given type - - "error code": Failure -*/ -status_t -get_app_hint(const char *type, entry_ref *ref) -{ - if (type == NULL || ref == NULL) - return B_BAD_VALUE; - - char path[B_PATH_NAME_LENGTH]; - BEntry entry; - ssize_t status = read_mime_attr(type, kAppHintAttr, path, - B_PATH_NAME_LENGTH, kAppHintType); - - if (status >= B_OK) - status = entry.SetTo(path); - if (status == B_OK) - status = entry.GetRef(ref); - - return status; -} - - -/*! \brief Fetches from the MIME database a BMessage describing the attributes - typically associated with files of the given MIME type - - The attribute information is returned in a pre-allocated BMessage pointed to by - the \c info parameter (note that the any prior contents of the message - will be destroyed). Please see BMimeType::SetAttrInfo() for a description - of the expected format of such a message. - - \param info Pointer to a pre-allocated BMessage into which information about - the MIME type's associated file attributes is stored. - \return - - \c B_OK: Success - - "error code": Failure -*/ -status_t -get_attr_info(const char *type, BMessage *info) -{ - status_t err = read_mime_attr_message(type, kAttrInfoAttr, info); - if (err == B_ENTRY_NOT_FOUND) { - // return an empty message - info->MakeEmpty(); - err = B_OK; - } - if (err == B_OK) { - info->what = 233; - // Don't know why, but that's what R5 does. - err = info->AddString("type", type); - } - return err; -} - - -/*! \brief Fetches the short description for the given MIME type. - - The string pointed to by \c description must be long enough to - hold the short description; a length of \c B_MIME_TYPE_LENGTH is - recommended. - - \param type The MIME type of interest - \param description Pointer to a pre-allocated string into which the short - description is copied. If the function fails, the contents - of the string are undefined. - - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No short description exists for the given type - - "error code": Failure -*/ -status_t -get_short_description(const char *type, char *description) -{ -/// DBG(OUT("Mime::Database::get_short_description()\n")); - ssize_t err = read_mime_attr(type, kShortDescriptionAttr, description, - B_MIME_TYPE_LENGTH, kShortDescriptionType); - return err >= 0 ? B_OK : err ; -} - -// get_long_description -//! Fetches the long description for the given MIME type. -/*! The string pointed to by \c description must be long enough to - hold the long description; a length of \c B_MIME_TYPE_LENGTH is - recommended. - - \param type The MIME type of interest - \param description Pointer to a pre-allocated string into which the long - description is copied. If the function fails, the contents - of the string are undefined. - - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No long description exists for the given type - - "error code": Failure -*/ -status_t -get_long_description(const char *type, char *description) -{ -// DBG(OUT("Mime::Database::get_long_description()\n")); - ssize_t err = read_mime_attr(type, kLongDescriptionAttr, description, - B_MIME_TYPE_LENGTH, kLongDescriptionType); - return err >= 0 ? B_OK : err ; -} - - -/*! \brief Fetches a BMessage describing the MIME type's associated filename - extensions - - The list of extensions is returned in a pre-allocated BMessage pointed to - by the \c extensions parameter (note that the any prior contents of the - message will be destroyed). Please see BMimeType::GetFileExtensions() for - a description of the message format. - - \param extensions Pointer to a pre-allocated BMessage into which the MIME - type's associated file extensions will be stored. - \return - - \c B_OK: Success - - "error code": Failure -*/ -status_t -get_file_extensions(const char *type, BMessage *extensions) -{ - status_t err = read_mime_attr_message(type, kFileExtensionsAttr, extensions); - if (err == B_ENTRY_NOT_FOUND) { - // return an empty message - extensions->MakeEmpty(); - err = B_OK; - } - if (err == B_OK) { - extensions->what = 234; // Don't know why, but that's what R5 does. - err = extensions->AddString("type", type); - } - return err; -} - - -/*! \brief Fetches the icon of given size associated with the given MIME type - - The bitmap pointed to by \c icon must be of the proper size (\c 32x32 - for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and color depth - (\c B_CMAP8). - - \param type The mime type - \param icon Pointer to a pre-allocated bitmap of proper dimensions and color depth - \param size The size icon you're interested in (\c B_LARGE_ICON or \c B_MINI_ICON) -*/ -status_t -get_icon(const char *type, BBitmap *icon, icon_size which) -{ - return get_icon_for_type(type, NULL, icon, which); -} - -// get_icon -//! Fetches the vector icon associated with the given MIME type -/* \param type The mime type - \param data Pointer in which the allocated icon data is returned. You need to - free the buffer once you're done with it. - \param size Pointer in which the size of the icon data is returned. -*/ -status_t -get_icon(const char *type, uint8** data, size_t* size) -{ - return get_icon_for_type(type, NULL, data, size); -} - -// get_icon_for_type -/*! \brief Fetches the large or mini icon used by an application of this type for files of the - given type. - - The type of the \c BMimeType object is not required to actually be a subtype of - \c "application/"; that is the intended use however, and calling \c get_icon_for_type() - on a non-application type will likely return \c B_ENTRY_NOT_FOUND. - - The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap must - be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon. - - \param type The MIME type - \param fileType Pointer to a pre-allocated string containing the MIME type whose - custom icon you wish to fetch. If NULL, works just like get_icon(). - \param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace into - which the icon is copied. - \param icon_size Value that specifies which icon to return. Currently \c B_LARGE_ICON - and \c B_MINI_ICON are supported. - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type - - "error code": Failure - -*/ -status_t -get_icon_for_type(const char* type, const char* fileType, BBitmap* icon, - icon_size which) -{ - if (!type || !icon) - return B_BAD_VALUE; - - // open the node for the given type - BNode node; - ssize_t err = open_type(type, &node); - if (err < B_OK) - return (status_t)err; - - // construct our attribute name - std::string vectorIconAttrName; - std::string smallIconAttrName; - std::string largeIconAttrName; - - if (fileType) { - std::string lowerCaseFileType = BPrivate::Storage::to_lower(fileType); - - vectorIconAttrName = kIconAttrPrefix + lowerCaseFileType; - smallIconAttrName = kMiniIconAttrPrefix + lowerCaseFileType; - largeIconAttrName = kLargeIconAttrPrefix + lowerCaseFileType; - } else { - vectorIconAttrName = kIconAttr; - smallIconAttrName = kMiniIconAttr; - largeIconAttrName = kLargeIconAttr; - } - - return BIconUtils::GetIcon(&node, vectorIconAttrName.c_str(), - smallIconAttrName.c_str(), largeIconAttrName.c_str(), - which, icon); - - -// ssize_t err = type && icon ? B_OK : B_BAD_VALUE; -// -// // Figure out what kind of data we *should* find -// uint32 attrType = 0; -// ssize_t attrSize = 0; -// BRect bounds; -// -// if (!err) { -// switch (which) { -// case B_MINI_ICON: -// bounds.Set(0, 0, 15, 15); -// attrType = kMiniIconType; -// attrSize = 16 * 16; -// break; -// case B_LARGE_ICON: -// bounds.Set(0, 0, 31, 31); -// attrType = kLargeIconType; -// attrSize = 32 * 32; -// break; -// default: -// err = B_BAD_VALUE; -// break; -// } -// } -// // Construct our attribute name -// std::string attr; -// if (fileType) { -// attr = (which == B_MINI_ICON -// ? kMiniIconAttrPrefix -// : kLargeIconAttrPrefix) -// + BPrivate::Storage::to_lower(fileType); -// } else { -// attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr; -// } -// // Check the icon and attribute to see if they match -// if (!err) { -// err = (icon->InitCheck() == B_OK -// && icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE; -// } -// -// BNode node; -// if (!err) -// err = open_type(type, &node); -// -// attr_info info; -// if (!err) -// err = node.GetAttrInfo(attr.c_str(), &info); -// -// if (!err) -// err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE; -// // read the attribute -// if (!err) { -// bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); -// char *buffer = NULL; -// if (otherColorSpace) { -// // other color space than stored in attribute -// buffer = new(std::nothrow) char[attrSize]; -// if (!buffer) -// err = B_NO_MEMORY; -// if (!err) -// err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize); -// } else { -// // same color space, just read direct -// err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize); -// } -// if (err >= 0) -// err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR; -// if (otherColorSpace) { -// if (!err) { -// err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, -// 0, B_CMAP8); -// } -// delete[] buffer; -// } -// } -// -// return err; -} - -// get_icon_for_type -/*! \brief Fetches the vector icon used by an application of this type for files of the - given type. - - The type of the \c BMimeType object is not required to actually be a subtype of - \c "application/"; that is the intended use however, and calling \c get_icon_for_type() - on a non-application type will likely return \c B_ENTRY_NOT_FOUND. - - The icon data is allocated and returned in \a data. - - \param type The MIME type - \param fileType Pointer to a pre-allocated string containing the MIME type whose - custom icon you wish to fetch. If NULL, works just like get_icon(). - \param data Pointer in which the icon data is returned on success. - \param size Pointer in which the size of the icon data is returned. - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No vector icon exists for the given type - - "error code": Failure - -*/ -status_t -get_icon_for_type(const char* type, const char* fileType, uint8** data, - size_t* size) -{ - if (!type || !data || !size) - return B_BAD_VALUE; - - // open the node for the given type - BNode node; - ssize_t err = open_type(type, &node); - if (err < B_OK) - return (status_t)err; - - // construct our attribute name - std::string iconAttrName; - - if (fileType) - iconAttrName = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType); - else - iconAttrName = kIconAttr; - - // get info about attribute for that name - attr_info info; - if (!err) - err = node.GetAttrInfo(iconAttrName.c_str(), &info); - - // validate attribute type - if (!err) - err = (info.type == B_VECTOR_ICON_TYPE) ? B_OK : B_BAD_VALUE; - - // allocate a buffer and read the attribute data into it - if (!err) { - uint8* buffer = new(std::nothrow) uint8[info.size]; - if (!buffer) - err = B_NO_MEMORY; - if (!err) { - err = node.ReadAttr(iconAttrName.c_str(), B_VECTOR_ICON_TYPE, - 0, buffer, info.size); - } - - if (err >= 0) - err = (err == info.size) ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; - - if (!err) { - // success, set data pointer and size - *data = buffer; - *size = info.size; - } else { - delete[] buffer; - } - } - - return err; -} - - -/*! \brief Fetches signature of the MIME type's preferred application for the - given action. - - The string pointed to by \c signature must be long enough to - hold the short description; a length of \c B_MIME_TYPE_LENGTH is - recommended. - - Currently, the only supported app verb is \c B_OPEN. - - \param type The MIME type of interest - \param description Pointer to a pre-allocated string into which the - preferred application's signature is copied. If the function fails, - the contents of the string are undefined. - \param verb \c The action of interest - - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No such preferred application exists - - "error code": Failure -*/ -status_t -get_preferred_app(const char *type, char *signature, app_verb verb = B_OPEN) -{ - // Since B_OPEN is the currently the only app_verb, it is essentially ignored - ssize_t err = read_mime_attr(type, kPreferredAppAttr, signature, - B_MIME_TYPE_LENGTH, kPreferredAppType); - return err >= 0 ? B_OK : err ; -} - - -/*! \brief Fetches the sniffer rule for the given MIME type. - \param type The MIME type of interest - \param result Pointer to a pre-allocated BString into which the type's - sniffer rule is copied. - \return - - \c B_OK: Success - - \c B_ENTRY_NOT_FOUND: No such preferred application exists - - "error code": Failure -*/ -status_t -get_sniffer_rule(const char *type, BString *result) -{ - return read_mime_attr_string(type, kSnifferRuleAttr, result); -} - - -status_t -get_supported_types(const char *type, BMessage *types) -{ - status_t err = read_mime_attr_message(type, kSupportedTypesAttr, types); - if (err == B_ENTRY_NOT_FOUND) { - // return an empty message - types->MakeEmpty(); - err = B_OK; - } - if (err == B_OK) { - types->what = 0; - err = types->AddString("type", type); - } - return err; -} - - -//! Checks if the given MIME type is present in the database -bool -is_installed(const char *type) -{ - BNode node; - return open_type(type, &node) == B_OK; -} - - -/*! \brief Returns properly formatted raw bitmap data, ready to be shipped off - to the hacked up 4-parameter version of Database::SetIcon() - - This function exists as something of a hack until an OBOS::BBitmap - implementation is available. It takes the given bitmap, converts it to the - B_CMAP8 color space if necessary and able, and returns said bitmap data in - a newly allocated array pointed to by the pointer that's pointed to by - \c data. The length of the array is stored in the integer pointed to by - \c dataSize. The array is allocated with \c new[], and it's your - responsibility to \c delete[] it when you're finished. -*/ -status_t -get_icon_data(const BBitmap *icon, icon_size which, void **data, - int32 *dataSize) -{ - if (icon == NULL || data == NULL || dataSize == 0 - || icon->InitCheck() != B_OK) - return B_BAD_VALUE; - - BRect bounds; - BBitmap *icon8 = NULL; - void *srcData = NULL; - bool otherColorSpace = false; - - // Figure out what kind of data we *should* have - 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: - return B_BAD_VALUE; - } - - // Check the icon - status_t err = icon->Bounds() == bounds ? B_OK : B_BAD_VALUE; - - // Convert to B_CMAP8 if necessary - if (!err) { - otherColorSpace = (icon->ColorSpace() != B_CMAP8); - if (otherColorSpace) { - icon8 = new(std::nothrow) BBitmap(bounds, B_BITMAP_NO_SERVER_LINK, - B_CMAP8); - if (!icon8) - err = B_NO_MEMORY; - if (!err) - err = icon8->ImportBits(icon); - if (!err) { - srcData = icon8->Bits(); - *dataSize = icon8->BitsLength(); - } - } else { - srcData = icon->Bits(); - *dataSize = icon->BitsLength(); - } - } - - // Alloc a new data buffer - if (!err) { - *data = new(std::nothrow) char[*dataSize]; - if (!*data) - err = B_NO_MEMORY; - } - - // Copy the data into it. - if (!err) - memcpy(*data, srcData, *dataSize); - if (otherColorSpace) - delete icon8; - return err; -} - -} // namespace Mime -} // namespace Storage -} // namespace BPrivate - diff --git a/src/kits/storage/mime/database_support.cpp b/src/kits/storage/mime/database_support.cpp index 09703f40da..76f36ba5d0 100644 --- a/src/kits/storage/mime/database_support.cpp +++ b/src/kits/storage/mime/database_support.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006, Haiku. + * Copyright 2002-2013, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -7,37 +7,16 @@ * Ingo Weinhold */ -/*! - \file database_support.cpp - Private mime database functions and constants -*/ -#include -#include -#include -#include +#include + +#include + +#include #include -#include -#include -#include #include -#include -#include -#include -#include // For struct attr_info -#include // For new(nothrow) -#include -#include -#include - -#include - -#include "mime/database_support.h" - -//#define DBG(x) x -#define DBG(x) -#define OUT printf +#include namespace BPrivate { @@ -109,12 +88,12 @@ static const directory_which kBaseDirectoryConstants[] = { B_SYSTEM_DATA_DIRECTORY }; -static pthread_once_t sDatabaseDirectoryInitOnce = PTHREAD_ONCE_INIT; -static BStringList sDatabaseDirectories; +static pthread_once_t sDefaultDatabaseLocationInitOnce = PTHREAD_ONCE_INIT; +static DatabaseLocation sDefaultDatabaseLocation; static void -init_database_directories() +init_default_database_location() { for (size_t i = 0; i < sizeof(kBaseDirectoryConstants) @@ -129,410 +108,94 @@ init_database_directories() continue; directoryPath += "/mime_db"; - sDatabaseDirectories.Add(directoryPath); + sDefaultDatabaseLocation.AddDirectory(directoryPath); } } -const BStringList& -get_database_directories() +DatabaseLocation* +default_database_location() { - pthread_once(&sDatabaseDirectoryInitOnce, &init_database_directories); - return sDatabaseDirectories; + pthread_once(&sDefaultDatabaseLocationInitOnce, + &init_default_database_location); + return &sDefaultDatabaseLocation; } -BString -get_writable_database_directory() -{ - return get_database_directories().StringAt(0); -} +/*! \brief Returns properly formatted raw bitmap data, ready to be shipped off + to the hacked up 4-parameter version of Database::SetIcon() - -static BString -type_to_filename(const char* type, int32 index) -{ - BString path = get_database_directories().StringAt(index); - return path << '/' << BPrivate::Storage::to_lower(type).c_str(); -} - - -/*! Converts the given MIME type to an absolute path in the user writeable MIME - database directory. -*/ -BString -type_to_writable_filename(const char* type) -{ - return type_to_filename(type, 0); -} - - -static status_t -open_type(const char* type, BNode* _node, int32& _index) -{ - const BStringList& directories = get_database_directories(); - int32 count = directories.CountStrings(); - for (int32 i = 0; i < count; i++) { - status_t error = _node->SetTo(type_to_filename(type, i)); - attr_info attrInfo; - if (error == B_OK && _node->GetAttrInfo(kTypeAttr, &attrInfo) == B_OK) { - _index = i; - return B_OK; - } - } - - return B_ENTRY_NOT_FOUND; -} - - -static status_t -create_type_node(const char* type, BNode& _result) -{ - const char* slash = strchr(type, '/'); - BString superTypeName; - if (slash != NULL) - superTypeName.SetTo(type, slash - type); - else - superTypeName = type; - superTypeName.ToLower(); - - // open/create the directory for the supertype - BDirectory parent(get_writable_database_directory()); - status_t error = parent.InitCheck(); - if (error != B_OK) - return error; - - BDirectory superTypeDirectory; - if (BEntry(&parent, superTypeName).Exists()) - error = superTypeDirectory.SetTo(&parent, superTypeName); - else - error = parent.CreateDirectory(superTypeName, &superTypeDirectory); - if (error != B_OK) - return error; - - // create the subtype - BFile subTypeFile; - if (slash != NULL) { - error = superTypeDirectory.CreateFile(BString(slash + 1).ToLower(), - &subTypeFile); - if (error != B_OK) - return error; - } - - // assign the result - if (slash != NULL) - _result = subTypeFile; - else - _result = superTypeDirectory; - return _result.InitCheck(); -} - - -static status_t -copy_type_node(BNode& source, const char* type, BNode& _target) -{ - status_t error = create_type_node(type, _target); - if (error != B_OK) - return error; - - // copy the attributes - MemoryDeleter bufferDeleter; - size_t bufferSize = 0; - - source.RewindAttrs(); - char attribute[B_ATTR_NAME_LENGTH]; - while (source.GetNextAttrName(attribute) == B_OK) { - attr_info info; - error = source.GetAttrInfo(attribute, &info); - if (error != B_OK) { - syslog(LOG_ERR, "Failed to get info for attribute \"%s\" of MIME " - "type \"%s\": %s", attribute, type, strerror(error)); - continue; - } - - // resize our buffer, if necessary - if (info.size > bufferSize) { - bufferDeleter.SetTo(malloc(info.size)); - if (bufferDeleter.Get() == NULL) - return B_NO_MEMORY; - bufferSize = info.size; - } - - ssize_t bytesRead = source.ReadAttr(attribute, info.type, 0, - bufferDeleter.Get(), info.size); - if (bytesRead != info.size) { - syslog(LOG_ERR, "Failed to read attribute \"%s\" of MIME " - "type \"%s\": %s", attribute, type, - bytesRead < 0 ? strerror(bytesRead) : "short read"); - continue; - } - - ssize_t bytesWritten = _target.WriteAttr(attribute, info.type, 0, - bufferDeleter.Get(), info.size); - if (bytesWritten < 0) { - syslog(LOG_ERR, "Failed to write attribute \"%s\" of MIME " - "type \"%s\": %s", attribute, type, - bytesWritten < 0 ? strerror(bytesWritten) : "short write"); - continue; - } - } - - return B_OK; -} - - -// open_type -/*! \brief Opens a BNode on the given type, failing if the type has no - corresponding file in the database. - \param type The MIME type to open - \param result Pointer to a pre-allocated BNode into which - is opened on the given MIME type + This function exists as something of a hack until an OBOS::BBitmap + implementation is available. It takes the given bitmap, converts it to the + B_CMAP8 color space if necessary and able, and returns said bitmap data in + a newly allocated array pointed to by the pointer that's pointed to by + \c data. The length of the array is stored in the integer pointed to by + \c dataSize. The array is allocated with \c new[], and it's your + responsibility to \c delete[] it when you're finished. */ status_t -open_type(const char *type, BNode *result) +get_icon_data(const BBitmap *icon, icon_size which, void **data, + int32 *dataSize) { - if (type == NULL || result == NULL) + if (icon == NULL || data == NULL || dataSize == 0 + || icon->InitCheck() != B_OK) return B_BAD_VALUE; - int32 index; - return open_type(type, result, index); -} + BRect bounds; + BBitmap *icon8 = NULL; + void *srcData = NULL; + bool otherColorSpace = false; -// open_or_create_type -/*! \brief Opens a BNode on the given type, creating a node of the - appropriate flavor if necessary. - - All MIME types are converted to lowercase for use in the filesystem. - \param type The MIME type to open - \param result Pointer to a pre-allocated BNode into which - is opened on the given MIME type -*/ -status_t -open_or_create_type(const char *type, BNode *result, bool *didCreate) -{ - if (didCreate) - *didCreate = false; - - // See, if the type already exists. - int32 index; - status_t error = open_type(type, result, index); - if (error == B_OK) { - if (index == 0) - return B_OK; - - // The caller wants a editable node, but the node found is not in the - // user's settings directory. Copy the node. - BNode nodeToClone(*result); - if (nodeToClone.InitCheck() != B_OK) - return nodeToClone.InitCheck(); - - error = copy_type_node(nodeToClone, type, *result); - if (error != B_OK) { - result->Unset(); - return error; - } - - if (didCreate != NULL) - *didCreate = true; - return error; + // Figure out what kind of data we *should* have + 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: + return B_BAD_VALUE; } - // type doesn't exist yet -- create the respective node - error = create_type_node(type, *result); - if (error != B_OK) - return error; + // Check the icon + status_t err = icon->Bounds() == bounds ? B_OK : B_BAD_VALUE; - // write the type attribute - error = result->WriteAttr(kTypeAttr, B_STRING_TYPE, 0, type, - strlen(type) + 1); - if (error != B_OK) { - result->Unset(); - return error; - } - - if (didCreate != NULL) - *didCreate = true; - return B_OK; -} - -// read_mime_attr -/*! \brief Reads up to \c len bytes of the given data from the given attribute - for the given MIME type. - - If no entry for the given type exists in the database, the function fails, - and the contents of \c data are undefined. - - \param type The MIME type - \param attr The attribute name - \param data Pointer to a memory buffer into which the data should be copied - \param len The maximum number of bytes to read - \param datatype The expected data type - \return If successful, the number of bytes read is returned, otherwise, an - error code is returned. -*/ -ssize_t -read_mime_attr(const char *type, const char *attr, void *data, - size_t len, type_code datatype) -{ - BNode node; - ssize_t err = (type && attr && data ? B_OK : B_BAD_VALUE); - if (!err) - err = open_type(type, &node); - if (!err) - err = node.ReadAttr(attr, datatype, 0, data, len); - return err; -} - -// read_mime_attr_message -/*! \brief Reads a flattened BMessage from the given attribute of the given - MIME type. - - If no entry for the given type exists in the database, or if the data - stored in the attribute is not a flattened BMessage, the function fails - and the contents of \c msg are undefined. - - \param type The MIME type - \param attr The attribute name - \param data Pointer to a pre-allocated BMessage into which the attribute - data is unflattened. -*/ -status_t -read_mime_attr_message(const char *type, const char *attr, BMessage *msg) -{ - BNode node; - attr_info info; - char *buffer = NULL; - ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE); - if (!err) - err = open_type(type, &node); - if (!err) - err = node.GetAttrInfo(attr, &info); - if (!err) - err = info.type == B_MESSAGE_TYPE ? B_OK : B_BAD_VALUE; + // Convert to B_CMAP8 if necessary if (!err) { - buffer = new(std::nothrow) char[info.size]; - if (!buffer) + otherColorSpace = (icon->ColorSpace() != B_CMAP8); + if (otherColorSpace) { + icon8 = new(std::nothrow) BBitmap(bounds, B_BITMAP_NO_SERVER_LINK, + B_CMAP8); + if (!icon8) + err = B_NO_MEMORY; + if (!err) + err = icon8->ImportBits(icon); + if (!err) { + srcData = icon8->Bits(); + *dataSize = icon8->BitsLength(); + } + } else { + srcData = icon->Bits(); + *dataSize = icon->BitsLength(); + } + } + + // Alloc a new data buffer + if (!err) { + *data = new(std::nothrow) char[*dataSize]; + if (!*data) err = B_NO_MEMORY; } + + // Copy the data into it. if (!err) - err = node.ReadAttr(attr, B_MESSAGE_TYPE, 0, buffer, info.size); - if (err >= 0) - err = err == info.size ? (status_t)B_OK : (status_t)B_FILE_ERROR; - if (!err) - err = msg->Unflatten(buffer); - delete [] buffer; + memcpy(*data, srcData, *dataSize); + if (otherColorSpace) + delete icon8; return err; } -// read_mime_attr_string -/*! \brief Reads a BString from the given attribute of the given - MIME type. - - If no entry for the given type exists in the database, the function fails - and the contents of \c str are undefined. - - \param type The MIME type - \param attr The attribute name - \param str Pointer to a pre-allocated BString into which the attribute - data stored. -*/ -status_t -read_mime_attr_string(const char *type, const char *attr, BString *str) -{ - BNode node; - status_t err = (type && attr && str ? B_OK : B_BAD_VALUE); - if (!err) - err = open_type(type, &node); - if (!err) - err = node.ReadAttrString(attr, str); - return err; -} - -// write_mime_attr -/*! \brief Writes \c len bytes of the given data to the given attribute - for the given MIME type. - - If no entry for the given type exists in the database, it is created. - - \param type The MIME type - \param attr The attribute name - \param data Pointer to the data to write - \param len The number of bytes to write - \param datatype The data type of the given data -*/ -status_t -write_mime_attr(const char *type, const char *attr, const void *data, - size_t len, type_code datatype, bool *didCreate) -{ - BNode node; - status_t err = (type && attr && data ? B_OK : B_BAD_VALUE); - if (!err) - err = open_or_create_type(type, &node, didCreate); - if (!err) { - ssize_t bytes = node.WriteAttr(attr, datatype, 0, data, len); - if (bytes < B_OK) - err = bytes; - else - err = (bytes != (ssize_t)len ? (status_t)B_FILE_ERROR : (status_t)B_OK); - } - return err; -} - -// write_mime_attr_message -/*! \brief Flattens the given \c BMessage and writes it to the given attribute - of the given MIME type. - - If no entry for the given type exists in the database, it is created. - - \param type The MIME type - \param attr The attribute name - \param msg The BMessage to flatten and write -*/ -status_t -write_mime_attr_message(const char *type, const char *attr, const BMessage *msg, bool *didCreate) -{ - BNode node; - BMallocIO data; - ssize_t bytes; - ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE); - if (!err) - err = data.SetSize(msg->FlattenedSize()); - if (!err) - err = msg->Flatten(&data, &bytes); - if (!err) - err = bytes == msg->FlattenedSize() ? B_OK : B_ERROR; - if (!err) - err = open_or_create_type(type, &node, didCreate); - if (!err) - err = node.WriteAttr(attr, B_MESSAGE_TYPE, 0, data.Buffer(), data.BufferLength()); - if (err >= 0) - err = err == (ssize_t)data.BufferLength() ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; - return err; -} - -// delete_attribute -//! Deletes the given attribute for the given type -/*! - \param type The mime type - \param attr The attribute name - \return - - B_OK: success - - B_ENTRY_NOT_FOUND: no such type or attribute - - "error code": failure -*/ -status_t -delete_attribute(const char *type, const char *attr) -{ - status_t err = type ? B_OK : B_BAD_VALUE; - BNode node; - if (!err) - err = open_type(type, &node); - if (!err) - err = node.RemoveAttr(attr); - return err; -} - - } // namespace Mime } // namespace Storage diff --git a/src/servers/registrar/MIMEManager.cpp b/src/servers/registrar/MIMEManager.cpp index 8332422fbc..ebde527dd7 100644 --- a/src/servers/registrar/MIMEManager.cpp +++ b/src/servers/registrar/MIMEManager.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include "CreateAppMetaMimeThread.h" #include "MessageDeliverer.h" #include "MimeSnifferAddonManager.h" @@ -56,7 +58,8 @@ init_mime_sniffer_add_on_manager() MIMEManager::MIMEManager() : BLooper("main_mime"), - fDatabase(init_mime_sniffer_add_on_manager(), this), + fDatabase(BPrivate::Storage::Mime::default_database_location(), + init_mime_sniffer_add_on_manager(), this), fThreadManager() { AddHandler(&fThreadManager); diff --git a/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp b/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp index 18164cfda9..599c2a13cd 100644 --- a/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp +++ b/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp @@ -23,6 +23,7 @@ #include #include +#include namespace BPrivate { @@ -83,7 +84,7 @@ CreateAppMetaMimeThread::DoMimeUpdate(const entry_ref* ref, bool* _entryIsDir) mime.Install(); BNode typeNode; - status = open_type(signature, &typeNode); + status = fDatabase->Location()->OpenType(signature, typeNode); if (status < B_OK) return status;