diff --git a/headers/os/storage/MimeType.h b/headers/os/storage/MimeType.h index 0239955c1f..a024ee4551 100644 --- a/headers/os/storage/MimeType.h +++ b/headers/os/storage/MimeType.h @@ -57,6 +57,7 @@ enum { B_MIME_TYPE_CREATED = 0x00000100, B_MIME_TYPE_DELETED = 0x00000200, B_SNIFFER_RULE_CHANGED = 0x00000400, + B_SUPPORTED_TYPES_CHANGED = 0x00000800, B_EVERYTHING_CHANGED = (int)0xFFFFFFFF }; @@ -121,9 +122,9 @@ public: status_t SetShortDescription(const char *description); status_t SetLongDescription(const char *description); - static status_t GetInstalledSupertypes(BMessage *super_types); + static status_t GetInstalledSupertypes(BMessage *supertypes); static status_t GetInstalledTypes(BMessage *types); - static status_t GetInstalledTypes(const char *super_type, + static status_t GetInstalledTypes(const char *supertype, BMessage *subtypes); static status_t GetWildcardApps(BMessage *wild_ones); static bool IsValid(const char *mimeType); @@ -156,15 +157,16 @@ public: status_t SetType(const char *mimeType); /* Brand new Delete() methods */ - status_t DeleteIcon(icon_size size); - status_t DeletePreferredApp(app_verb verb = B_OPEN); + status_t DeleteAppHint(); status_t DeleteAttrInfo(); - status_t DeleteFileExtensions(); status_t DeleteShortDescription(); status_t DeleteLongDescription(); - status_t DeleteSnifferRule(); + status_t DeleteFileExtensions(); + status_t DeleteIcon(icon_size size); status_t DeleteIconForType(const char *type, icon_size which); - status_t DeleteAppHint(); + status_t DeletePreferredApp(app_verb verb = B_OPEN); + status_t DeleteSnifferRule(); + status_t DeleteSupportedTypes(); private: BMimeType(const char *mimeType, const char *mimePath); @@ -192,24 +194,24 @@ private: BMimeType &operator=(const BMimeType &); BMimeType(const BMimeType &); -/* - void InitData(const char *type); - void InitData(const char *type); - status_t OpenFile(bool create_file = false, dev_t dev = -1) const; - status_t CloseFile() const; + +// void InitData(const char *type); +// void InitData(const char *type); +// status_t OpenFile(bool create_file = false, dev_t dev = -1) const; +// status_t CloseFile() const; status_t GetSupportedTypes(BMessage *types); status_t SetSupportedTypes(const BMessage *types); - void MimeChanged(int32 w, const char *type = NULL, - bool large = true) const; -*/ +// void MimeChanged(int32 w, const char *type = NULL, +// bool large = true) const; - char *fType; - BFile *fMeta; - BPrivate::MimeDatabase *fMimeDatabase; // Was: "void *_unused;" - entry_ref fRef; - int fWhere; - status_t fCStatus; - uint32 _reserved[3]; + + char *fType; + BFile *fMeta; + void *_unused; + entry_ref fRef; + int fWhere; + status_t fCStatus; + uint32 _reserved[3]; }; diff --git a/headers/private/storage/mime/Database.h b/headers/private/storage/mime/Database.h new file mode 100644 index 0000000000..d59d858079 --- /dev/null +++ b/headers/private/storage/mime/Database.h @@ -0,0 +1,100 @@ +// mime/Database.h + +#ifndef _MIME_DATABASE_H +#define _MIME_DATABASE_H + +#include +#include +#include +#include + +#include +#include +#include + +class BNode; +class BBitmap; +class BMessage; + +namespace BPrivate { +namespace Storage { +namespace Mime { + +class Database { +public: + Database(); + ~Database(); + + status_t InitCheck() const; + + // 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); + status_t SetShortDescription(const char *type, const char *description); + status_t SetLongDescription(const char *type, const char *description); + status_t SetFileExtensions(const char *type, const BMessage *extensions); + status_t SetIcon(const char *type, const void *data, size_t dataSize, icon_size which); + status_t SetIconForType(const char *type, const char *fileType, const void *data, + size_t dataSize, icon_size which); + status_t SetPreferredApp(const char *type, const char *signature, app_verb verb = B_OPEN); +// status_t SetSnifferRule(const char *); + status_t SetSupportedTypes(const char *type, const BMessage *types); + + // Non-atomic Get() + status_t GetInstalledSupertypes(BMessage *super_types); + status_t GetInstalledTypes(BMessage *types); + status_t GetInstalledTypes(const char *super_type, + BMessage *subtypes); + status_t GetSupportingApps(const char *type, BMessage *signatures); + + // Sniffer +// static status_t CheckSnifferRule(const char *rule, BString *parseError); +// static status_t GuessMimeType(const entry_ref *file, BMimeType *result); +// static status_t GuessMimeType(const void *buffer, int32 length, +// BMimeType *result); +// static status_t GuessMimeType(const char *filename, BMimeType *result); + + // Monitor + status_t StartWatching(BMessenger target); + status_t StopWatching(BMessenger target); + + // Delete() + status_t DeleteAppHint(const char *type); + status_t DeleteAttrInfo(const char *type); + status_t DeleteShortDescription(const char *type); + status_t DeleteLongDescription(const char *type); + status_t DeleteFileExtensions(const char *type); + status_t DeleteIcon(const char *type, icon_size size); + status_t DeleteIconForType(const char *type, const char *fileType, icon_size which); + status_t DeletePreferredApp(const char *type, app_verb verb = B_OPEN); + status_t DeleteSnifferRule(const char *type); + status_t DeleteSupportedTypes(const char *type); + +private: + status_t SendInstallNotification(const char *type); + status_t SendDeleteNotification(const char *type); + + status_t SendMonitorUpdate(int32 which, const char *type, const char *extraType, + bool largeIcon, int32 action); + status_t SendMonitorUpdate(int32 which, const char *type, const char *extraType, + int32 action); + status_t SendMonitorUpdate(int32 which, const char *type, bool largeIcon, + int32 action); + status_t SendMonitorUpdate(int32 which, const char *type, + int32 action); + status_t SendMonitorUpdate(BMessage &msg); + + status_t fCStatus; + std::set fMonitorSet; + InstalledTypes fInstalledTypes; +}; + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + +#endif // _MIME_DATABASE_H diff --git a/headers/private/storage/mime/InstalledTypes.h b/headers/private/storage/mime/InstalledTypes.h new file mode 100644 index 0000000000..d00fe2b3f5 --- /dev/null +++ b/headers/private/storage/mime/InstalledTypes.h @@ -0,0 +1,42 @@ +// mime/InstalledTypes.h + +#ifndef _MIME_INSTALLED_TYPES_H +#define _MIME_INSTALLED_TYPES_H + +#include +#include + +#include +#include + +class BMessage; + +namespace BPrivate { +namespace Storage { +namespace Mime { + +class InstalledTypes { +public: + InstalledTypes(); + ~InstalledTypes(); + + status_t GetInstalledTypes(BMessage *types); + status_t GetInstalledTypes(const char *supertype, BMessage *types); + status_t GetInstalledSupertypes(BMessage *types); + + void AddType(const char *type); + void AddSupertype(const char *type); + void AddSubtype(const char *super, const char *sub); +private: + void FillMessageWithTypes(BMessage *msg); + void FillMessageWithSupertypes(BMessage *msg); + + std::map fSupertypes; + BMessage *fCachedMessage; +}; + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + +#endif // _MIME_INSTALLED_TYPES_H diff --git a/headers/private/storage/mime/Supertype.h b/headers/private/storage/mime/Supertype.h new file mode 100644 index 0000000000..8479a9b333 --- /dev/null +++ b/headers/private/storage/mime/Supertype.h @@ -0,0 +1,34 @@ +// mime/Supertype.h + +#ifndef _MIME_SUPERTYPE_H +#define _MIME_SUPERTYPE_H + +#include + +#include +#include + +class BMessage; + +namespace BPrivate { +namespace Storage { +namespace Mime { + +class Supertype { +public: + Supertype(const char *super); + ~Supertype(); + + void AddSubtype(const char *sub); + void FillMessageWithTypes(BMessage *msg); +private: + std::set fSubtypes; + BMessage *fCachedMessage; + std::string fType; +}; + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + +#endif // _MIME_SUPERTYPE_H diff --git a/headers/private/storage/mime/database_access.h b/headers/private/storage/mime/database_access.h new file mode 100644 index 0000000000..869002c517 --- /dev/null +++ b/headers/private/storage/mime/database_access.h @@ -0,0 +1,39 @@ +// mime/database_access.h + +#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_for_type(const char *type, const char *fileType, BBitmap *icon, + icon_size which); +status_t get_preferred_app(const char *type, char *signature, app_verb verb); +status_t get_sniffer_rule(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 new file mode 100644 index 0000000000..2910ff6173 --- /dev/null +++ b/headers/private/storage/mime/database_support.h @@ -0,0 +1,71 @@ +// mime/database_support.h + +#ifndef _MIME_DATABASE_SUPPORT_H +#define _MIME_DATABASE_SUPPORT_H + +#include + +#include + +class BNode; +class BMessage; + +namespace BPrivate { +namespace Storage { +namespace Mime { + +// Database directory +extern const std::string kDatabaseDir; + +// Attribute Prefixes +extern const char *kMiniIconAttrPrefix; +extern const char *kLargeIconAttrPrefix; + +// Attribute names +extern const char *kFileTypeAttr; +extern const char *kTypeAttr; +extern const char *kAttrInfoAttr; +extern const char *kAppHintAttr; +extern const char *kShortDescriptionAttr; +extern const char *kLongDescriptionAttr; +extern const char *kFileExtensionsAttr; +extern const char *kMiniIconAttr; +extern const char *kLargeIconAttr; +extern const char *kPreferredAppAttr; +extern const char *kSnifferRuleAttr; +extern const char *kSupportedTypesAttr; + +// Attribute Datatypes +extern const int32 kFileTypeType; +extern const int32 kTypeType; +extern const int32 kAppHintType; +extern const int32 kAttrInfoType; +extern const int32 kShortDescriptionType; +extern const int32 kLongDescriptionType; +extern const int32 kFileExtensionsType; +extern const int32 kMiniIconType; +extern const int32 kLargeIconType; +extern const int32 kPreferredAppType; +extern const int32 kSnifferRuleType; +extern const int32 kSupportedTypesType; + +std::string type_to_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); + +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 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); + +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/Jamfile b/src/kits/storage/Jamfile index af551c4080..678ec2b041 100644 --- a/src/kits/storage/Jamfile +++ b/src/kits/storage/Jamfile @@ -24,15 +24,16 @@ UsePublicHeaders [ FDirName add-ons file_system ] ; # that can just be linked into libstorage.so and the # registrar separately. SEARCH_SOURCE += [ FDirName $(SUBDIR) sniffer ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) mime ] ; SharedLibrary storage : + # storage Directory.cpp Entry.cpp EntryList.cpp File.cpp FindDirectory.cpp Mime.cpp - MimeDatabase.cpp MimeType.cpp Node.cpp #NodeInfo.cpp @@ -45,21 +46,30 @@ SharedLibrary storage : ResourceItem.cpp Resources.cpp ResourceStrings.cpp - Err.cpp # Hack-o-rama - DisjList.cpp # Hack-o-rama - Pattern.cpp # Hack-o-rama - PatternList.cpp # Hack-o-rama - Parser.cpp # Hack-o-rama - Range.cpp # Hack-o-rama - RPattern.cpp # Hack-o-rama - RPatternList.cpp # Hack-o-rama - Rule.cpp # Hack-o-rama Statable.cpp SymLink.cpp Volume.cpp VolumeRoster.cpp kernel_interface.POSIX.cpp storage_support.cpp + + # storage/sniffer + Err.cpp + DisjList.cpp + Pattern.cpp + PatternList.cpp + Parser.cpp + Range.cpp + RPattern.cpp + RPatternList.cpp + Rule.cpp + + # storage/mime + Database.cpp + InstalledTypes.cpp + Supertype.cpp + database_access.cpp + database_support.cpp ; LinkSharedOSLibs libstorage.so : libopenbeos.so diff --git a/src/kits/storage/MimeType.cpp b/src/kits/storage/MimeType.cpp index 6516ec5133..b2326bffda 100644 --- a/src/kits/storage/MimeType.cpp +++ b/src/kits/storage/MimeType.cpp @@ -6,19 +6,20 @@ \file MimeType.cpp BMimeType implementation. */ -#include +#include "MimeType.h" + #include +#include +#include +#include + #include // For tolower() #include // For new(nothrow) #include // For printf() #include // For strncpy() -#include #include #include // For _send_to_roster_() -#include -#include - // Private helper functions bool isValidMimeChar(const char ch); status_t toLower(const char *str, char *result); @@ -27,6 +28,7 @@ enum { NOT_IMPLEMENTED = B_ERROR, }; +using namespace BPrivate::Storage::Mime; const char *B_PEF_APP_MIME_TYPE = "application/x-be-executable"; const char *B_PE_APP_MIME_TYPE = "application/x-vnd.be-peexecutable"; @@ -43,7 +45,6 @@ const char *B_APP_MIME_TYPE = B_ELF_APP_MIME_TYPE; BMimeType::BMimeType() : fType(NULL) , fCStatus(B_NO_INIT) - , fMimeDatabase(new(nothrow) BPrivate::MimeDatabase()) { } @@ -57,7 +58,6 @@ BMimeType::BMimeType() BMimeType::BMimeType(const char *mimeType) : fType(NULL) , fCStatus(B_NO_INIT) - , fMimeDatabase(new(nothrow) BPrivate::MimeDatabase()) { SetTo(mimeType); } @@ -68,7 +68,6 @@ BMimeType::BMimeType(const char *mimeType) BMimeType::~BMimeType() { Unset(); - delete fMimeDatabase; } // SetTo @@ -98,8 +97,6 @@ BMimeType::SetTo(const char *mimeType) { if (!mimeType || !BMimeType::IsValid(mimeType)) { fCStatus = B_BAD_VALUE; - } else if (!fMimeDatabase) { - fCStatus = B_NO_MEMORY; } else { Unset(); fType = new(nothrow) char[strlen(mimeType)+1]; @@ -193,7 +190,7 @@ BMimeType::IsSupertypeOnly() const bool BMimeType::IsInstalled() const { - return InitCheck() == B_OK && fMimeDatabase->IsInstalled(Type()); + return InitCheck() == B_OK && is_installed(Type()); } // GetSupertype @@ -388,7 +385,10 @@ BMimeType::Delete() status_t BMimeType::GetIcon(BBitmap *icon, icon_size size) const { - return fMimeDatabase->GetIcon(Type(), icon, size); + status_t err = InitCheck(); + if (!err) + err = get_icon(Type(), icon, size); + return err; } // GetPreferredApp @@ -414,7 +414,10 @@ BMimeType::GetIcon(BBitmap *icon, icon_size size) const status_t BMimeType::GetPreferredApp(char *signature, app_verb verb) const { - return fMimeDatabase->GetPreferredApp(Type(), signature, verb); + status_t err = InitCheck(); + if (!err) + err = get_preferred_app(Type(), signature, verb); + return err; } // GetAttrInfo @@ -470,7 +473,10 @@ BMimeType::GetPreferredApp(char *signature, app_verb verb) const status_t BMimeType::GetAttrInfo(BMessage *info) const { - return fMimeDatabase->GetAttrInfo(Type(), info); + status_t err = InitCheck(); + if (!err) + err = get_attr_info(Type(), info); + return err; } // GetFileExtensions @@ -504,7 +510,10 @@ BMimeType::GetAttrInfo(BMessage *info) const status_t BMimeType::GetFileExtensions(BMessage *extensions) const { - return fMimeDatabase->GetFileExtensions(Type(), extensions); + status_t err = InitCheck(); + if (!err) + err = get_file_extensions(Type(), extensions); + return err; } // GetShortDescription @@ -523,7 +532,10 @@ BMimeType::GetFileExtensions(BMessage *extensions) const status_t BMimeType::GetShortDescription(char *description) const { - return fMimeDatabase->GetShortDescription(Type(), description); + status_t err = InitCheck(); + if (!err) + err = get_short_description(Type(), description); + return err; } // GetLongDescription @@ -542,7 +554,10 @@ BMimeType::GetShortDescription(char *description) const status_t BMimeType::GetLongDescription(char *description) const { - return fMimeDatabase->GetLongDescription(Type(), description); + status_t err = InitCheck(); + if (!err) + err = get_long_description(Type(), description); + return err; } // GetSupportingApps @@ -908,9 +923,26 @@ BMimeType::SetLongDescription(const char *description) - "error code": Failure */ status_t -BMimeType::GetInstalledSupertypes(BMessage *super_types) +BMimeType::GetInstalledSupertypes(BMessage *supertypes) { - return NOT_IMPLEMENTED; + status_t err = supertypes ? B_OK : B_BAD_VALUE; + + BMessage msg(B_REG_MIME_GET_INSTALLED_SUPERTYPES); + BMessage reply; + status_t result; + + // Build and send the message, read the reply + if (!err) + err = _send_to_roster_(&msg, &reply, true); + if (!err) + err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE; + if (!err) + err = reply.FindInt32("result", &result); + if (!err) + err = result; + if (!err) + err = reply.FindMessage("types", supertypes); + return err; } // GetInstalledTypes @@ -929,7 +961,7 @@ BMimeType::GetInstalledSupertypes(BMessage *super_types) status_t BMimeType::GetInstalledTypes(BMessage *types) { - return NOT_IMPLEMENTED; + return GetInstalledTypes(NULL, types); } // GetInstalledTypes @@ -948,9 +980,28 @@ BMimeType::GetInstalledTypes(BMessage *types) - "error code": Failure */ status_t -BMimeType::GetInstalledTypes(const char *super_type, BMessage *subtypes) +BMimeType::GetInstalledTypes(const char *supertype, BMessage *types) { - return NOT_IMPLEMENTED; + status_t err = types ? B_OK : B_BAD_VALUE; + + BMessage msg(B_REG_MIME_GET_INSTALLED_TYPES); + BMessage reply; + status_t result; + + // Build and send the message, read the reply + if (!err && supertype) + err = msg.AddString("supertype", supertype); + if (!err) + err = _send_to_roster_(&msg, &reply, true); + if (!err) + err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE; + if (!err) + err = reply.FindInt32("result", &result); + if (!err) + err = result; + if (!err) + err = reply.FindMessage("types", types); + return err; } // GetWildcardApps @@ -1050,7 +1101,10 @@ bool isValidMimeChar(const char ch) status_t BMimeType::GetAppHint(entry_ref *ref) const { - return fMimeDatabase->GetAppHint(Type(), ref); + status_t err = InitCheck(); + if (!err) + err = get_app_hint(Type(), ref); + return err; } // SetAppHint @@ -1136,7 +1190,7 @@ BMimeType::GetIconForType(const char *type, BBitmap *icon, icon_size which) cons if (type) { err = BMimeType::IsValid(type) ? B_OK : B_BAD_VALUE; if (!err) - err = fMimeDatabase->GetIconForType(Type(), type, icon, which); + err = get_icon_for_type(Type(), type, icon, which); } else err = GetIcon(icon, which); return err; @@ -1191,7 +1245,7 @@ BMimeType::SetIconForType(const char *type, const BBitmap *icon, icon_size which err = msg.AddInt32("which", (type ? B_REG_MIME_ICON_FOR_TYPE : B_REG_MIME_ICON)); if (icon) { if (!err) - err = BPrivate::MimeDatabase::GetIconData(icon, which, &data, &dataSize); + err = get_icon_data(icon, which, &data, &dataSize); if (!err) err = msg.AddData("icon data", B_RAW_TYPE, data, dataSize); } @@ -1470,20 +1524,12 @@ BMimeType::SetType(const char *mimeType) SetTo(mimeType); } -// DeleteIcon -//! Deletes the mime type's icon of given size -status_t -BMimeType::DeleteIcon(icon_size which) -{ - return SetIcon(NULL, which); -} - -// DeletePreferredApp -//! Deletes the mime type's preferred app for the given verb +// DeleteAppHint +//! Deletes the mime type's application hint status_t -BMimeType::DeletePreferredApp(app_verb verb = B_OPEN) +BMimeType::DeleteAppHint() { - return SetPreferredApp(NULL, verb); + return SetAppHint(NULL); } // DeleteAttrInfo @@ -1494,14 +1540,6 @@ BMimeType::DeleteAttrInfo() return SetAttrInfo(NULL); } -// DeleteFileExtensions -//! Deletes the mime type's associated file extensions -status_t -BMimeType::DeleteFileExtensions() -{ - return SetFileExtensions(NULL); -} - // DeleteShortDescription //! Deletes the mime type's short description status_t @@ -1518,12 +1556,20 @@ BMimeType::DeleteLongDescription() return SetLongDescription(NULL); } -// DeleteSnifferRule -//! Deletes the mime type's sniffer rule +// DeleteFileExtensions +//! Deletes the mime type's associated file extensions status_t -BMimeType::DeleteSnifferRule() +BMimeType::DeleteFileExtensions() { - return SetSnifferRule(NULL); + return SetFileExtensions(NULL); +} + +// DeleteIcon +//! Deletes the mime type's icon of given size +status_t +BMimeType::DeleteIcon(icon_size which) +{ + return SetIcon(NULL, which); } // DeleteIconForType @@ -1534,12 +1580,28 @@ BMimeType::DeleteIconForType(const char *type, icon_size which) return SetIconForType(type, NULL, which); } -// DeleteAppHint -//! Deletes the mime type's application hint +// DeletePreferredApp +//! Deletes the mime type's preferred app for the given verb status_t -BMimeType::DeleteAppHint() +BMimeType::DeletePreferredApp(app_verb verb = B_OPEN) { - return SetAppHint(NULL); + return SetPreferredApp(NULL, verb); +} + +// DeleteSnifferRule +//! Deletes the mime type's sniffer rule +status_t +BMimeType::DeleteSnifferRule() +{ + return SetSnifferRule(NULL); +} + +// DeleteSupportedTypes +//! Deletes the mime type's supported types +status_t +BMimeType::DeleteSupportedTypes() +{ + return SetSupportedTypes(NULL); } void BMimeType::_ReservedMimeType1() {} @@ -1562,6 +1624,42 @@ BMimeType::BMimeType(const BMimeType &) { } +status_t +BMimeType::GetSupportedTypes(BMessage *types) +{ + status_t err = InitCheck(); + if (!err) + err = get_supported_types(Type(), types); + return err; +} + +status_t +BMimeType::SetSupportedTypes(const BMessage *types) +{ + status_t err = InitCheck(); + + BMessage msg(types ? B_REG_MIME_SET_PARAM : B_REG_MIME_DELETE_PARAM); + BMessage reply; + status_t result; + + // Build and send the message, read the reply + if (!err) + err = msg.AddString("type", Type()); + if (!err) + err = msg.AddInt32("which", B_REG_MIME_SUPPORTED_TYPES); + if (!err && types) + err = msg.AddMessage("types", types); + if (!err) + err = _send_to_roster_(&msg, &reply, true); + if (!err) + err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE; + if (!err) + err = reply.FindInt32("result", &result); + if (!err) + err = result; + return err; +} + // Returns a lowercase version of str in result. Result must // be preallocated and is assumed to be of adequate length. status_t diff --git a/src/kits/storage/mime/Database.cpp b/src/kits/storage/mime/Database.cpp new file mode 100644 index 0000000000..b70d8edfc7 --- /dev/null +++ b/src/kits/storage/mime/Database.cpp @@ -0,0 +1,752 @@ +// mime/Database.cpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // For struct attr_info +#include +#include // For new(nothrow) +#include +#include + +#include "mime/Database.h" + +//#define DBG(x) x +#define DBG(x) +#define OUT printf + +// icon types +enum { + B_MINI_ICON_TYPE = 'MICN', + B_LARGE_ICON_TYPE = 'ICON', +}; + +namespace BPrivate { +namespace Storage { +namespace Mime { + +/*! + \class Database + \brief Mime::Database is the master of the MIME data base. + + All write and non-atomic read accesses are carried out by this class. + Monitoring is handled by + + \note No error checking (other than checks for NULL pointers) is performed + by this class on the mime type strings passed to it. It's assumed + that this sort of checking has been done beforehand. +*/ + +// constructor +/*! \brief Creates and initializes a MimeDatabase. +*/ +Database::Database() + : fCStatus(B_NO_INIT) +{ + // Do some really minor error checking + BEntry entry(kDatabaseDir.c_str()); + fCStatus = entry.Exists() ? B_OK : B_BAD_VALUE; +} + +// destructor +/*! \brief Frees all resources associated with this object. +*/ +Database::~Database() +{ +} + +// InitCheck +/*! \brief Returns the initialization status of the object. + \return + - B_OK: success + - "error code": failure +*/ +status_t +Database::InitCheck() const +{ + return fCStatus; +} + +// Install +/*! \brief Installs the given type in the database + \note The R5 version of this call returned an unreliable result if the + MIME type was already installed. Ours simply returns B_OK. + \param type Pointer to a NULL-terminated string containing the MIME type of interest + \param decsription Pointer to a NULL-terminated string containing the new long description + \return + - B_OK: success + - B_FILE_EXISTS: the type is already installed + - "error code": failure +*/ +status_t +Database::Install(const char *type) +{ + BEntry entry; + status_t err = (type ? B_OK : B_BAD_VALUE); + if (!err) + err = entry.SetTo(type_to_filename(type).c_str()); + if (!err) { + if (entry.Exists()) + err = B_FILE_EXISTS; + else { + bool didCreate = false; + BNode node; + err = open_or_create_type(type, &node, &didCreate); + } + } + return err; +} + +// Delete +/*! \brief Removes the given type from the database + \param type Pointer to a NULL-terminated string containing the MIME type of interest + \return + - B_OK: success + - "error code": failure +*/ +status_t +Database::Delete(const char *type) +{ + BEntry entry; + status_t err = (type ? B_OK : B_BAD_VALUE); + if (!err) + err = entry.SetTo(type_to_filename(type).c_str()); + if (!err) + err = entry.Remove(); + if (!err) + err = SendDeleteNotification(type); + return err; +} + +// SetAppHint +/*! \brief Sets the application hint for the given MIME type + \param type Pointer to a NULL-terminated string containing the MIME type of interest + \param decsription Pointer to an entry_ref containing the location of an application + that should be used when launching an application with this signature. +*/ +status_t +Database::SetAppHint(const char *type, const entry_ref *ref) +{ + DBG(OUT("Database::SetAppHint()\n")); + BPath path; + bool didCreate = false; + status_t err = (type && ref) ? B_OK : B_BAD_VALUE; + if (!err) + err = path.SetTo(ref); + if (!err) + err = write_mime_attr(type, kAppHintAttr, path.Path(), strlen(path.Path())+1, + kAppHintType, &didCreate); + if (!err) + err = SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +// SetAttrInfo +/*! \brief Stores a BMessage describing the format of attributes typically associated with + files of the given MIME type + + See BMimeType::SetAttrInfo() for description of the expected message format. + + The \c BMessage::what value is ignored. + + \param info Pointer to a pre-allocated and properly formatted BMessage containing + information about the file attributes typically associated with the + MIME type. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +Database::SetAttrInfo(const char *type, const BMessage *info) +{ + DBG(OUT("Database::SetAttrInfo()\n")); + bool didCreate = false; + status_t err = (type && info) ? B_OK : B_BAD_VALUE; + if (!err) + err = write_mime_attr_message(type, kAttrInfoAttr, info, &didCreate); + if (!err) + err = SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +// SetShortDescription +/*! \brief Sets the short description for the given MIME type + \param type Pointer to a NULL-terminated string containing the MIME type of interest + \param decsription Pointer to a NULL-terminated string containing the new short description +*/ +status_t +Database::SetShortDescription(const char *type, const char *description) +{ + DBG(OUT("Database::SetShortDescription()\n")); + bool didCreate = false; + status_t err = (type && description && strlen(description) < B_MIME_TYPE_LENGTH) ? B_OK : B_BAD_VALUE; + if (!err) + err = write_mime_attr(type, kShortDescriptionAttr, description, strlen(description)+1, + kShortDescriptionType, &didCreate); + if (!err) + err = SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +// SetLongDescription +/*! \brief Sets the long description for the given MIME type + \param type Pointer to a NULL-terminated string containing the MIME type of interest + \param decsription Pointer to a NULL-terminated string containing the new long description +*/ +status_t +Database::SetLongDescription(const char *type, const char *description) +{ + DBG(OUT("Database::SetLongDescription()\n")); + bool didCreate = false; + status_t err = (type && description && strlen(description) < B_MIME_TYPE_LENGTH) ? B_OK : B_BAD_VALUE; + if (!err) + err = write_mime_attr(type, kLongDescriptionAttr, description, strlen(description)+1, + kLongDescriptionType, &didCreate); + if (!err) + err = SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +// SetFileExtensions +//! Sets the list of filename extensions associated with the MIME type +/*! The list of extensions is given in a pre-allocated BMessage pointed to by + the \c extensions parameter. Please see BMimeType::SetFileExtensions() + for a description of the expected message format. + + \param extensions Pointer to a pre-allocated, properly formatted BMessage containing + the new list of file extensions to associate with this MIME type. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +Database::SetFileExtensions(const char *type, const BMessage *extensions) +{ + DBG(OUT("Database::SetFileExtensions()\n")); + bool didCreate = false; + status_t err = (type && extensions) ? B_OK : B_BAD_VALUE; + if (!err) + err = write_mime_attr_message(type, kFileExtensionsAttr, extensions, &didCreate); + if (!err) + err = SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +//! Sets the icon for the given mime type +/*! This is the version I would have used if I could have gotten a BBitmap + to the registrar somehow. Since R5::BBitmap::Instantiate is causing a + violent crash, I've copied most of the icon color conversion code into + Mime::get_icon_data() so BMimeType::SetIcon() can get at it. + + Once we have a sufficiently complete OBOS::BBitmap implementation, we + ought to be able to use this version of SetIcon() again. At that point, + I'll add some real documentation. +*/ +status_t +Database::SetIcon(const char *type, const void *data, size_t dataSize, icon_size which) +{ + return SetIconForType(type, NULL, data, dataSize, which); +} + +// SetIconForType +/*! \brief Sets 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 application-specific + icons are not expected to be present for non-application types. + + The bitmap data pointed to by \c data must be of the proper size (\c 32x32 + for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and the proper color + space (B_CMAP8). + + \param type The MIME type + \param fileType The MIME type whose custom icon you wish to set. + \param data Pointer to an array of bitmap data of proper dimensions and color depth + \param dataSize The length of the array pointed to by \c data + \param size The size icon you're expecting (\c B_LARGE_ICON or \c B_MINI_ICON) + \return + - \c B_OK: Success + - "error code": Failure + +*/ +status_t +Database::SetIconForType(const char *type, const char *fileType, const void *data, + size_t dataSize, icon_size which) +{ + ssize_t err = (type && data) ? B_OK : B_BAD_VALUE; + + std::string attr; + int32 attrType; + int32 attrSize; + + // Figure out what kind of data we *should* have + if (!err) { + switch (which) { + case B_MINI_ICON: + attrType = kMiniIconType; + attrSize = 16 * 16; + break; + case B_LARGE_ICON: + attrType = kLargeIconType; + attrSize = 32 * 32; + break; + default: + err = B_BAD_VALUE; + break; + } + } + + // Construct our attribute name + if (fileType) { + attr = (which == B_MINI_ICON + ? kMiniIconAttrPrefix + : kLargeIconAttrPrefix) + + BPrivate::Storage::to_lower(fileType); + } else + attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; + + // Double check the data we've been given + if (!err) + err = dataSize == attrSize ? B_OK : B_BAD_VALUE; + + // Write the icon data + BNode node; + bool didCreate = false; + if (!err) + err = open_or_create_type(type, &node, &didCreate); + if (!err) + err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize); + if (err >= 0) + err = err == attrSize ? B_OK : B_FILE_ERROR; + return err; + +} + +// SetPreferredApp +/*! \brief Sets the signature of the preferred application for the given app verb + + Currently, the only supported app verb is \c B_OPEN + \param type Pointer to a NULL-terminated string containing the MIME type of interest + \param signature Pointer to a NULL-terminated string containing the MIME signature + of the new preferred application + \param verb \c app_verb action for which the new preferred application is applicable +*/ +status_t +Database::SetPreferredApp(const char *type, const char *signature, app_verb verb = B_OPEN) +{ + DBG(OUT("Database::SetPreferredApp()\n")); + bool didCreate = false; + status_t err = (type && signature && strlen(signature) < B_MIME_TYPE_LENGTH) ? B_OK : B_BAD_VALUE; + if (!err) + err = write_mime_attr(type, kPreferredAppAttr, signature, strlen(signature)+1, + kPreferredAppType, &didCreate); + if (!err) + err = SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +// SetSupportedTypes +status_t +Database::SetSupportedTypes(const char *type, const BMessage *types) +{ + DBG(OUT("Database::SetSupportedTypes()\n")); + bool didCreate = false; + status_t err = (type && types) ? B_OK : B_BAD_VALUE; + if (!err) + err = write_mime_attr_message(type, kSupportedTypesAttr, types, &didCreate); + if (!err) + err = SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_MODIFIED); + return err; +} + +status_t +Database::GetInstalledSupertypes(BMessage *supertypes) +{ +// return fInstalledTypes.GetInstalledSupertypes(supertypes); + return B_ERROR; +} + +status_t +Database::GetInstalledTypes(BMessage *types) +{ +// return fInstalledTypes.GetInstalledTypes(types); + return B_ERROR; +} + +status_t +Database::GetInstalledTypes(const char *supertype, BMessage *subtypes) +{ +// return fInstalledTypes.GetInstalledTypes(supertype, subtypes); + return B_ERROR; +} + +status_t +Database::GetSupportingApps(const char *type, BMessage *signatures) +{ + return B_ERROR; +} + + +// StartWatching +//! Subscribes the given BMessenger to the MIME monitor service +/*! Notification messages will be sent with a \c BMessage::what value + of \c B_META_MIME_CHANGED. Notification messages have the following + fields: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name Type Description
\c be:type \c B_STRING_TYPE The MIME type that was changed
\c be:which \c B_INT32_TYPE Bitmask describing which attributes were changed (see below)
\c be:extra_type \c B_STRING_TYPE Additional MIME type string (applicable to B_ICON_FOR_TYPE_CHANGED notifications only)
\c be:large_icon \c B_BOOL_TYPE \c true if the large icon was changed, \c false if the small icon + was changed (applicable to B_ICON_[FOR_TYPE_]CHANGED updates only)
+ + The \c be:which field of the message describes which attributes were updated, and + may be the bitwise \c OR of any of the following values: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Value Triggered By
\c B_ICON_CHANGED \c BMimeType::SetIcon()
\c B_PREFERRED_APP_CHANGED \c BMimeType::SetPreferredApp()
\c B_ATTR_INFO_CHANGED \c BMimeType::SetAttrInfo()
\c B_FILE_EXTENSIONS_CHANGED \c BMimeType::SetFileExtensions()
\c B_SHORT_DESCRIPTION_CHANGED \c BMimeType::SetShortDescription()
\c B_LONG_DESCRIPTION_CHANGED \c BMimeType::SetLongDescription()
\c B_ICON_FOR_TYPE_CHANGED \c BMimeType::SetIconForType()
\c B_APP_HINT_CHANGED \c BMimeType::SetAppHint()
+ + \param target The \c BMessenger to subscribe to the MIME monitor service +*/ +status_t +Database::StartWatching(BMessenger target) +{ + DBG(OUT("Database::StartWatching()\n")); + status_t err = target.IsValid() ? B_OK : B_BAD_VALUE; + if (!err) + fMonitorSet.insert(target); + return err; +} + +// StartWatching +//! Unsubscribes the given BMessenger from the MIME monitor service +/*! \param target The \c BMessenger to unsubscribe +*/ +status_t +Database::StopWatching(BMessenger target) +{ + DBG(OUT("Database::StopWatching()\n")); + status_t err = fMonitorSet.find(target) != fMonitorSet.end() ? B_OK : B_ENTRY_NOT_FOUND; + if (!err) + fMonitorSet.erase(target); + return err; +} + +status_t +Database::DeleteAppHint(const char *type) +{ + status_t err = delete_attribute(type, kAppHintAttr); + if (!err) + err = SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteAttrInfo(const char *type) +{ + status_t err = delete_attribute(type, kAttrInfoAttr); + if (!err) + err = SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteShortDescription(const char *type) +{ + status_t err = delete_attribute(type, kShortDescriptionAttr); + if (!err) + err = SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteLongDescription(const char *type) +{ + status_t err = delete_attribute(type, kLongDescriptionAttr); + if (!err) + err = SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteFileExtensions(const char *type) +{ + status_t err = delete_attribute(type, kFileExtensionsAttr); + if (!err) + err = SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteIcon(const char *type, icon_size which) +{ + const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; + status_t err = delete_attribute(type, attr); + if (!err) + err = SendMonitorUpdate(B_ICON_CHANGED, type, which, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteIconForType(const char *type, const char *fileType, icon_size which) +{ + std::string attr; + status_t err = fileType ? B_OK : B_BAD_VALUE; + if (!err) { + attr = (which == B_MINI_ICON ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType); + err = delete_attribute(type, attr.c_str()); + } + if (!err) + err = SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, + which == B_LARGE_ICON, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeletePreferredApp(const char *type, app_verb verb = B_OPEN) +{ + status_t err; + switch (verb) { + case B_OPEN: + err = delete_attribute(type, kPreferredAppAttr); + break; + + default: + err = B_BAD_VALUE; + break; + } + /*! \todo The R5 monitor makes no note of which app_verb value was updated. If + additional app_verb values besides \c B_OPEN are someday added, the format + of the MIME monitor messages will need to be augmented. + */ + if (!err) + err = SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_DELETED); +} + +status_t +Database::DeleteSnifferRule(const char *type) +{ + status_t err = delete_attribute(type, kSnifferRuleAttr); + if (!err) + err = SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::DeleteSupportedTypes(const char *type) +{ + status_t err = delete_attribute(type, kSupportedTypesAttr); + if (!err) + err = SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED); + return err; +} + +status_t +Database::SendInstallNotification(const char *type) +{ +// fInstalledTypes.AddType(type); + status_t err = SendMonitorUpdate(B_MIME_TYPE_CREATED, type, B_META_MIME_MODIFIED); + return err; +} + +status_t +Database::SendDeleteNotification(const char *type) +{ + // Tell the backend first +// fInstalledTypes.RemoveType(type); + status_t err = SendMonitorUpdate(B_MIME_TYPE_DELETED, type, B_META_MIME_MODIFIED); + return err; +} + +// SendMonitorUpdate +/*! \brief Sends an update notification to all BMessengers that have + subscribed to the MIME Monitor service + \param type The MIME type that was updated + \param which Bitmask describing which attribute was updated + \param extraType The MIME type to which the change is applies + \param largeIcon \true if the the large icon was updated, \false if the + small icon was updated +*/ +status_t +Database::SendMonitorUpdate(int32 which, const char *type, const char *extraType, bool largeIcon, int32 action) { + BMessage msg(B_META_MIME_CHANGED); + status_t err; + + err = msg.AddInt32("be:which", which); + if (!err) + err = msg.AddString("be:type", type); + if (!err) + err = msg.AddString("be:extra_type", extraType); + if (!err) + err = msg.AddBool("be:large_icon", largeIcon); + if (!err) + err = msg.AddInt32("be:action", action); + if (!err) + err = SendMonitorUpdate(msg); + return err; +} + +// SendMonitorUpdate +/*! \brief Sends an update notification to all BMessengers that have + subscribed to the MIME Monitor service + \param type The MIME type that was updated + \param which Bitmask describing which attribute was updated + \param extraType The MIME type to which the change is applies +*/ +status_t +Database::SendMonitorUpdate(int32 which, const char *type, const char *extraType, int32 action) { + BMessage msg(B_META_MIME_CHANGED); + status_t err; + + err = msg.AddInt32("be:which", which); + if (!err) + err = msg.AddString("be:type", type); + if (!err) + err = msg.AddString("be:extra_type", extraType); + if (!err) + err = msg.AddInt32("be:action", action); + if (!err) + err = SendMonitorUpdate(msg); + return err; +} + +// SendMonitorUpdate +/*! \brief Sends an update notification to all BMessengers that have + subscribed to the MIME Monitor service + \param type The MIME type that was updated + \param which Bitmask describing which attribute was updated + \param largeIcon \true if the the large icon was updated, \false if the + small icon was updated +*/ +status_t +Database::SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action) { + BMessage msg(B_META_MIME_CHANGED); + status_t err; + + err = msg.AddInt32("be:which", which); + if (!err) + err = msg.AddString("be:type", type); + if (!err) + err = msg.AddBool("be:large_icon", largeIcon); + if (!err) + err = msg.AddInt32("be:action", action); + if (!err) + err = SendMonitorUpdate(msg); + return err; +} + +// SendMonitorUpdate +/*! \brief Sends an update notification to all BMessengers that have + subscribed to the MIME Monitor service + \param type The MIME type that was updated + \param which Bitmask describing which attribute was updated +*/ +status_t +Database::SendMonitorUpdate(int32 which, const char *type, int32 action) { + BMessage msg(B_META_MIME_CHANGED); + status_t err; + + err = msg.AddInt32("be:which", which); + if (!err) + err = msg.AddString("be:type", type); + if (!err) + err = msg.AddInt32("be:action", action); + if (!err) + err = SendMonitorUpdate(msg); + return err; +} + +// SendMonitorUpdate +/*! \brief Sends an update notification to all BMessengers that have subscribed to + the MIME Monitor service + \param BMessage A preformatted MIME monitor message to be sent to all subscribers +*/ +status_t +Database::SendMonitorUpdate(BMessage &msg) { + DBG(OUT("Database::SendMonitorUpdate(BMessage&)\n")); + status_t err; + std::set::const_iterator i; + for (i = fMonitorSet.begin(); i != fMonitorSet.end(); i++) { + status_t err = (*i).SendMessage(&msg, (BHandler*)NULL); + if (err) + DBG(OUT("Database::SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, %p\n", err)); + } + DBG(OUT("Database::SendMonitorUpdate(BMessage&) done\n")); + err = B_OK; + return err; +} + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + diff --git a/src/kits/storage/mime/InstalledTypes.cpp b/src/kits/storage/mime/InstalledTypes.cpp new file mode 100644 index 0000000000..aeca70e028 --- /dev/null +++ b/src/kits/storage/mime/InstalledTypes.cpp @@ -0,0 +1,414 @@ +// mime/InstalledTypes.cpp + +#include "mime/InstalledTypes.h" + +#include + +#include + +#define DBG(x) x +//#define DBG(x) +#define OUT printf + +namespace BPrivate { +namespace Storage { +namespace Mime { + +InstalledTypes::InstalledTypes() + : fCachedMessage(NULL) +{ +} + +InstalledTypes::~InstalledTypes() +{ + delete fCachedMessage; +} + +/* +MimeDatabaseBackend::MimeDatabaseBackend() + : fCachedInstalledTypesMessage(NULL) + , fCachedInstalledSupertypesMessage(NULL) +{ +} + +MimeDatabaseBackend::~MimeDatabaseBackend() +{ + delete fCachedInstalledTypesMessage; + delete fCachedInstalledSupertypesMessage; +} + +status_t +MimeDatabaseBackend::GetInstalledTypes(BMessage *types) +{ + DBG(OUT("MimeDatabaseBackend::GetInstalledTypes(1)\n")); + status_t err = types ? B_OK : B_BAD_VALUE; + if (!err) { + if (!fCachedInstalledTypesMessage) { + if (fInstalledTypes.begin() == fInstalledTypes.end()) + err = BuildInstalledTypesList(&fCachedInstalledTypesMessage); + else + err = BuildInstalledTypesMessage(&fCachedInstalledTypesMessage); + } + *types = *fCachedInstalledTypesMessage; + } + DBG(OUT("MimeDatabaseBackend::GetInstalledTypes(1) done\n")); + return err; +} + +status_t +MimeDatabaseBackend::GetInstalledTypes(const char *supertype, BMessage *types) +{ + DBG(OUT("MimeDatabaseBackend::GetInstalledTypes(2)\n")); + status_t err = supertype && types && BMimeType::IsValid(supertype) ? B_OK : B_BAD_VALUE; + + // Types are not case sensitive, so we always use lowercase + char lowertype[B_PATH_NAME_LENGTH+1]; + BPrivate::Storage::to_lower(supertype, lowertype); + installed_subtypes_info *info; + + // See if we need to build the main list + if (!err && fSupertypesMap.empty()) + err = BuildInstalledTypesList(); + // See if the supertype even exists + if (!err) { + std::map::iterator i = fSupertypesMap.find(supertype); + err = i != fSupertypesMap.end() ? B_OK : B_BAD_VALUE; + if (!err) + info = &(i->second); + } + // Make sure there's a cached message waiting for us + if (!err && !info->cached_message) + err = BuildInstalledTypesMessage(info->subtypes, &(info->cached_message)); + // Copy the message into the result + if (!err) + *types = *info->cached_message; + DBG(OUT("MimeDatabaseBackend::GetInstalledTypes(2) done\n")); + return err; +} + +status_t +MimeDatabaseBackend::GetInstalledSupertypes(BMessage *types) +{ + DBG(OUT("MimeDatabaseBackend::GetInstalledSupertypes()\n")); + status_t err = types ? B_OK : B_BAD_VALUE; + + // See if we need to build the main list + if (!err && fSupertypesMap.empty()) + err = BuildInstalledTypesList(); + // Make sure there's a cached message waiting for us + if (!err && !fCachedInstalledSupertypesMessage) + err = BuildInstalledSupertypesMessage(fSupertypesMap, &fCachedInstalledSupertypesMessage); + // Copy the message into the result + if (!err) + *types = *fCachedInstalledSupertypesMessage; + DBG(OUT("MimeDatabaseBackend::GetInstalledSupertypes() done\n")); + return err; +} + +status_t +MimeDatabaseBackend::GetSupportingApps(const char *type, BMessage *signatures) +{ + return B_ERROR; // not implemented +} + +void +MimeDatabaseBackend::InstallType(const char *type) +{ + DBG(OUT("MimeDatabaseBackend::InstallType()\n")); + if (fInstalledTypes.empty()) + return; + // Remove any cached messages + if (fCachedInstalledTypesMessage) { + delete fCachedInstalledTypesMessage; + fCachedInstalledTypesMessage = NULL; + } + if (fCachedInstalledSupertypesMessage) { + delete fCachedInstalledSupertypesMessage; + fCachedInstalledSupertypesMessage = NULL; + } + char lowertype[B_PATH_NAME_LENGTH+1]; + char supertype[B_PATH_NAME_LENGTH+1]; + Storage::to_lower(type, lowertype); + fInstalledTypes.insert(lowertype); + BMimeType mime(lowertype); + BMimeType super; + status_t err = mime.InitCheck(); + if (!err) + err = mime.GetSupertype(&super); + if (!err) { + Storage::to_lower(super.Type(), supertype); + installed_subtypes_info &info = fSupertypesMap[supertype]; + delete info.cached_message; + info.cached_message = NULL; + info.subtypes.insert(lowertype); + } + DBG(OUT("MimeDatabaseBackend::InstallType() done\n")); +} + +void +MimeDatabaseBackend::DeleteType(const char *type) +{ + if (fInstalledTypes.empty()) + return; + printf("fuCK\n"); + // Remove any cached messages + if (fCachedInstalledTypesMessage) { + delete fCachedInstalledTypesMessage; + fCachedInstalledTypesMessage = NULL; + } + printf("fuCK\n"); + if (fCachedInstalledSupertypesMessage) { + delete fCachedInstalledSupertypesMessage; + fCachedInstalledSupertypesMessage = NULL; + } + printf("fuCK\n"); + char lowertype[B_PATH_NAME_LENGTH+1]; + char supertype[B_PATH_NAME_LENGTH+1]; + printf("fuCK\n"); + Storage::to_lower(type, lowertype); + fInstalledTypes.erase(lowertype); + printf("fuCK\n"); + BMimeType mime(lowertype); + BMimeType super; + printf("fuCK\n"); + status_t err = mime.InitCheck(); + printf("fuCK\n"); + if (!err) + err = mime.GetSupertype(&super); + printf("fuCK\n"); + if (!err) { + Storage::to_lower(super.Type(), supertype); + installed_subtypes_info &info = fSupertypesMap[supertype]; + printf("fuCK\n"); + delete info.cached_message; + printf("fuCK\n"); + info.cached_message = NULL; + printf("fuCK\n"); + info.subtypes.erase(lowertype); + } + printf("fuCK\n"); +} + +// BuildInstalledTypesList() +//! Builds an initial installed types list and (optionally) an installed types BMessage +status_t +MimeDatabaseBackend::BuildInstalledTypesList(BMessage **types) +{ + BMessage *msg; + if (types) { + *types = new BMessage; + msg = *types; + } else + msg = NULL; + + BDirectory root; + status_t err = root.SetTo(MimeDatabase::kDatabaseDir.c_str()); + if (!err) { + root.Rewind(); + while (true) { + BEntry entry; + err = root.GetNextEntry(&entry); + if (err) { + // If we've come to the end of list, it's not an error + if (err == B_ENTRY_NOT_FOUND) + err = B_OK; + break; + } else { + // Check that this entry is both a directory and a valid MIME string + char supertype[B_PATH_NAME_LENGTH+1]; + if (entry.IsDirectory() + && entry.GetName(supertype) == B_OK + && BMimeType::IsValid(supertype)) + { + // Make sure our string is all lowercase + BPrivate::Storage::to_lower(supertype); + + // Add this supertype + fInstalledTypes.insert(supertype); + fSupertypesMap[supertype] = installed_subtypes_info(); + installed_subtypes_info &info = fSupertypesMap[supertype]; + if (msg) + msg->AddString("types", supertype); + + // Now iterate through this supertype directory and add + // all of its subtypes + BDirectory dir; + if (dir.SetTo(&entry) == B_OK) { + dir.Rewind(); + while (true) { + BEntry subEntry; + err = dir.GetNextEntry(&subEntry); + if (err) { + // If we've come to the end of list, it's not an error + if (err == B_ENTRY_NOT_FOUND) + err = B_OK; + break; + } else { + // Get the subtype's name + char subtype[B_PATH_NAME_LENGTH+1]; + char mimetype[B_PATH_NAME_LENGTH+1]; + if (subEntry.GetName(subtype) == B_OK) { + BPrivate::Storage::to_lower(subtype); + sprintf(mimetype, "%s/%s", supertype, subtype); + + // Add the subtype + if (BMimeType::IsValid(mimetype)) { + fInstalledTypes.insert(mimetype); + info.subtypes.insert(mimetype); + if (msg) + msg->AddString("types", mimetype); + } + } + } + } + } else { + DBG(OUT("MimeDatabaseBackend::BuildInstalledTypesList(): " + "Failed opening supertype directory '%s'\n", + supertype)); + } + } + } + } + } else { + DBG(OUT("MimeDatabaseBackend::BuildInstalledTypesList(): " + "Failed opening mime database directory '%s'\n", + MimeDatabase::kDatabaseDir.c_str())); + } + return err; +} + +status_t +MimeDatabaseBackend::BuildInstalledTypesMessage(BMessage **result) +{ + status_t err = result ? B_OK : B_BAD_VALUE; + // Alloc the message + if (!err) { + *result = new BMessage; + if (!(*result)) + err = B_NO_MEMORY; + } + // Fill with types + if (!err) { + BMessage &msg = **result; + std::set::const_iterator i; + for (i = fInstalledTypes.begin(); i != fInstalledTypes.end(); i++) + msg.AddString("types", (*i).c_str()); + } + return err; +} + +status_t +MimeDatabaseBackend::BuildInstalledTypesMessage(const std::set &set, BMessage **result) +{ + status_t err = result ? B_OK : B_BAD_VALUE; + // Alloc the message + if (!err) { + *result = new BMessage; + if (!(*result)) + err = B_NO_MEMORY; + } + // Fill with types + if (!err) { + BMessage &msg = **result; + std::set::const_iterator i; + for (i = set.begin(); i != set.end(); i++) + msg.AddString("types", (*i).c_str()); + } + return err; +} + +status_t +MimeDatabaseBackend::BuildInstalledSupertypesMessage(const std::map &map, BMessage **result) +{ + status_t err = result ? B_OK : B_BAD_VALUE; + // Alloc the message + if (!err) { + *result = new BMessage; + if (!(*result)) + err = B_NO_MEMORY; + } + // Fill with types + if (!err) { + BMessage &msg = **result; + std::map::const_iterator i; + for (i = map.begin(); i != map.end(); i++) + msg.AddString("super_types", (i->first).c_str()); + } + return err; +} + + +status_t +MimeDatabaseBackend::BuildInstalledTypesList(const char *supertype, BMessage **types) +{ + return B_ERROR; + // I'm not going to work on this function anymore until we + // get to optimization, as BuildInstalledTypesList(Bmessage**) + // handles this already (just not as efficiently if we only + // want to build the types for a single supertype). I have + // no idea if this function works, as I've never tried it. + + BMessage *msg; + if (types) { + *types = new BMessage; + msg = *types; + } else + msg = NULL; + + status_t err = supertype && BMimeType::IsValid(supertype) ? B_OK : B_BAD_VALUE; + + // Check that this entry is both a directory and a valid MIME string + if (!err) + { + // Make sure our string is all lowercase + BPrivate::Storage::to_lower(supertype); + + // Clear any previous subtype info struct + fSupertypesMap[supertype] = installed_subtypes_info(); + installed_subtypes_info &info = fSupertypesMap[supertype]; + + // Iterate through the supertype directory and add + // all of its subtypes + BDirectory super; + if (super.SetTo((MimeDatabase::kDatabaseDir + supertype).c_str()) == B_OK) { + super.Rewind(); + while (true) { + BEntry entry; + err = super.GetNextEntry(&entry); + if (err) { + // If we've come to the end of list, it's not an error + if (err == B_ENTRY_NOT_FOUND) + err = B_OK; + break; + } else { + // Get the subtype's name + char subtype[B_PATH_NAME_LENGTH+1]; + char mimetype[B_PATH_NAME_LENGTH+1]; + if (entry.GetName(subtype) == B_OK) { + BPrivate::Storage::to_lower(subtype); + sprintf(mimetype, "%s/%s", supertype, subtype); + + // Add the subtype + if (BMimeType::IsValid(mimetype)) { + fInstalledTypes.insert(mimetype); + info.subtypes.insert(mimetype); + if (msg) + msg->AddString("types", mimetype); + } + } + } + } + } else { + DBG(OUT("MimeDatabaseBackend::BuildInstalledTypesList(): " + "Failed opening supertype directory '%s'\n", + supertype)); + } + } +} +*/ + + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + diff --git a/src/kits/storage/mime/Supertype.cpp b/src/kits/storage/mime/Supertype.cpp new file mode 100644 index 0000000000..610ca15f42 --- /dev/null +++ b/src/kits/storage/mime/Supertype.cpp @@ -0,0 +1,33 @@ +// mime/Supertype.cpp + +#include "mime/Supertype.h" + +#include + +#include + + +#define DBG(x) x +//#define DBG(x) +#define OUT printf + +namespace BPrivate { +namespace Storage { +namespace Mime { + +Supertype::Supertype(const char *super) + : fCachedMessage(NULL) + , fType(super) +{ +} + +Supertype::~Supertype() +{ + delete fCachedMessage; +} + + +} // namespace Mime +} // namespace Storage +} // namespace BPrivate + diff --git a/src/kits/storage/mime/database_access.cpp b/src/kits/storage/mime/database_access.cpp new file mode 100644 index 0000000000..ec5c386fe0 --- /dev/null +++ b/src/kits/storage/mime/database_access.cpp @@ -0,0 +1,425 @@ +// mime/Database.cpp + +#include +#include +#include +#include +#include +#include +#include + +#include // For struct attr_info +#include +#include // For new(nothrow) +#include +#include + +#include "mime/database_access.h" + +//#define DBG(x) x +#define DBG(x) +#define OUT printf + +namespace BPrivate { +namespace Storage { +namespace Mime { + +//------------------------------------------------------------------------------ +// Functions +//------------------------------------------------------------------------------ + +// get_app_hint +//! 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) +{ + char path[B_MIME_TYPE_LENGTH+1]; + BEntry entry; + ssize_t err = ref ? B_OK : B_BAD_VALUE; + if (!err) + err = read_mime_attr(type, kAppHintAttr, path, B_MIME_TYPE_LENGTH, kAppHintType); + if (err >= 0) + err = entry.SetTo(path); + if (!err) + err = entry.GetRef(ref); + return err; +} + +// get_attr_info +/*! \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) { + info->what = 233; // Don't know why, but that's what R5 does. + err = info->AddString("type", type); + } + return err; +} + +// get_short_description +//! 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+1 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+1 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 ; +} + +// get_file_extensions +//! 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) { + extensions->what = 234; // Don't know why, but that's what R5 does. + err = extensions->AddString("type", type); + } + return err; +} + +// get_icon +//! 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_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 type 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) +{ + std::string attr; + attr_info info; + ssize_t err; + BNode node; + uint32 attrType; + size_t attrSize; + BRect bounds; + char *buffer; + + err = type && icon ? B_OK : B_BAD_VALUE; + + // Figure out what kind of data we *should* find + 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 + 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; + if (!err) + err = open_type(type, &node); + 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; + ssize_t read; + if (otherColorSpace) { + // other color space than stored in attribute + buffer = new(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) ? B_OK : B_FILE_ERROR; + if (otherColorSpace) { + if (!err) { + icon->SetBits(buffer, attrSize, 0, B_CMAP8); + err = icon->InitCheck(); + } + delete[] buffer; + } + } + + return err; +} + +// get_preferred_app +//! 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+1 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 ; +} + +// get_supported_types +status_t +get_supported_types(const char *type, BMessage *types) +{ + status_t err = read_mime_attr_message(type, kSupportedTypesAttr, types); + if (!err) { + types->what = 0; + err = types->AddString("type", type); + } + return err; +} + +// is_installed +//! 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; +} + +// get_icon_data +/*! \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) +{ + ssize_t err = (icon && data && dataSize && icon->InitCheck() == B_OK) ? B_OK : B_BAD_VALUE; + + BRect bounds; + BBitmap *icon8 = NULL; + void *srcData = NULL; + bool otherColorSpace = false; + + // Figure out what kind of data we *should* have + if (!err) { + 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: + err = B_BAD_VALUE; + break; + } + } + // Check the icon + if (!err) + 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(nothrow) BBitmap(bounds, B_CMAP8); + if (!icon8) + err = B_NO_MEMORY; + if (!err) { + switch (icon->ColorSpace()) { + case B_RGB32: + { + // Set each pixel individually, since SetBits() for B_RGB32 takes + // 24-bit rgb pixel data... + char *bgra = (char*)icon->Bits(); + for (uint32 i = 0; i*4+3 < icon->BitsLength(); bgra += 4, i++) { + char rgb[3]; + rgb[0] = bgra[2]; // red + rgb[1] = bgra[1]; // green + rgb[2] = bgra[0]; // blue + icon8->SetBits(rgb, 3, i, B_RGB32); + } + break; + } + case B_GRAY1: + { + icon8->SetBits(icon->Bits(), icon->BitsLength(), 0, B_GRAY1); + break; + } + default: + err = B_BAD_VALUE; + } + if (!err) + err = icon8->InitCheck(); // I don't think this is actually useful, even if SetBits() fails... + } + if (!err) { + srcData = icon8->Bits(); + *dataSize = icon8->BitsLength(); + } + } else { + srcData = icon->Bits(); + *dataSize = icon->BitsLength(); + } + } + // Alloc a new data buffer + if (!err) { + *data = new(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 new file mode 100644 index 0000000000..b0738df1a9 --- /dev/null +++ b/src/kits/storage/mime/database_support.cpp @@ -0,0 +1,304 @@ +// database_support.cpp + +#include +#include +#include +#include +#include +#include +#include +#include + +#include // For struct attr_info +#include // For new(nothrow) +#include +#include + +#include "mime/database_support.h" + +//#define DBG(x) x +#define DBG(x) +#define OUT printf + +// icon types (which really ought to be publicly or semi-publicly declared somewhere...) +enum { + B_MINI_ICON_TYPE = 'MICN', + B_LARGE_ICON_TYPE = 'ICON', +}; + +namespace BPrivate { +namespace Storage { +namespace Mime { + +//const char* MimeDatabase::kDefaultDatabaseDir = "/boot/home/config/settings/beos_mime"; +const std::string kDatabaseDir = "/boot/home/config/settings/obos_mime"; + +#define ATTR_PREFIX "META:" +#define MINI_ICON_ATTR_PREFIX ATTR_PREFIX "M:" +#define LARGE_ICON_ATTR_PREFIX ATTR_PREFIX "L:" + +const char *kMiniIconAttrPrefix = MINI_ICON_ATTR_PREFIX; +const char *kLargeIconAttrPrefix = LARGE_ICON_ATTR_PREFIX; + +// attribute names +const char *kFileTypeAttr = "BEOS:TYPE"; +const char *kTypeAttr = ATTR_PREFIX "TYPE"; +const char *kAppHintAttr = ATTR_PREFIX "PPATH"; +const char *kAttrInfoAttr = ATTR_PREFIX "ATTR_INFO"; +const char *kShortDescriptionAttr = ATTR_PREFIX "S:DESC"; +const char *kLongDescriptionAttr = ATTR_PREFIX "L:DESC"; +const char *kFileExtensionsAttr = ATTR_PREFIX "EXTENS"; +const char *kMiniIconAttr = MINI_ICON_ATTR_PREFIX "STD_ICON"; +const char *kLargeIconAttr = LARGE_ICON_ATTR_PREFIX "STD_ICON"; +const char *kPreferredAppAttr = ATTR_PREFIX "PREF_APP"; +const char *kSnifferRuleAttr = ATTR_PREFIX "SNIFF_RULE"; +const char *kSupportedTypesAttr = ATTR_PREFIX "FILE_TYPES"; + +// attribute data types (as used in the R5 database) +const int32 kFileTypeType = 'MIMS'; // B_MIME_STRING_TYPE +const int32 kTypeType = B_STRING_TYPE; +const int32 kAppHintType = 'MPTH'; +const int32 kAttrInfoType = B_MESSAGE_TYPE; +const int32 kShortDescriptionType = 'MSDC'; +const int32 kLongDescriptionType = 'MLDC'; +const int32 kFileExtensionsType = B_MESSAGE_TYPE; +const int32 kMiniIconType = B_MINI_ICON_TYPE; +const int32 kLargeIconType = B_LARGE_ICON_TYPE; +const int32 kPreferredAppType = 'MSIG'; +const int32 kSnifferRuleType = B_STRING_TYPE; +const int32 kSupportedTypesType = B_MESSAGE_TYPE; + + + +// type_to_filename +//! Converts the given MIME type to an absolute path in the MIME database. +std::string +type_to_filename(const char *type) +{ + return kDatabaseDir + "/" + BPrivate::Storage::to_lower(type); +} + +// 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 +*/ +status_t +open_type(const char *type, BNode *result) +{ + status_t err = (type && result ? B_OK : B_BAD_VALUE); + if (!err) + err = result->SetTo(type_to_filename(type).c_str()); + return err; +} + +// 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; + std::string filename; + std::string typeLower = BPrivate::Storage::to_lower(type); + status_t err = (type && result ? B_OK : B_BAD_VALUE); + if (!err) { + filename = type_to_filename(type); + err = result->SetTo(filename.c_str()); + } + if (err == B_ENTRY_NOT_FOUND) { + // Figure out what type of node we need to create + // + Supertype == directory + // + Non-supertype == file + int32 pos = typeLower.find_first_of('/'); + if (pos == std::string::npos) { + // Supertype == directory + BDirectory parent(kDatabaseDir.c_str()); + err = parent.InitCheck(); + if (!err) + err = parent.CreateDirectory(typeLower.c_str(), NULL); + } else { + // Non-supertype == file + std::string super(typeLower, 0, pos); + std::string sub(typeLower, pos+1); + BDirectory parent((kDatabaseDir + "/" + super).c_str()); + err = parent.InitCheck(); + if (!err) + err = parent.CreateFile(sub.c_str(), NULL); + } + // Now try opening again + err = result->SetTo(filename.c_str()); + if (!err && didCreate) + *didCreate = true; + } + return err; +} + +// 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; + if (!err) { + buffer = new(nothrow) char[info.size]; + if (!buffer) + err = B_NO_MEMORY; + } + if (!err) + err = node.ReadAttr(attr, B_MESSAGE_TYPE, 0, buffer, info.size); + if (err >= 0) + err = err == info.size ? B_OK : B_FILE_ERROR; + if (!err) + err = msg->Unflatten(buffer); + delete [] buffer; + 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 != len ? B_FILE_ERROR : 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 == data.BufferLength() ? B_OK : 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 +} // namespace BPrivate + diff --git a/src/servers/registrar/MIMEManager.cpp b/src/servers/registrar/MIMEManager.cpp index a0e8b8aa1f..1c8e37197e 100644 --- a/src/servers/registrar/MIMEManager.cpp +++ b/src/servers/registrar/MIMEManager.cpp @@ -23,7 +23,7 @@ */ MIMEManager::MIMEManager() : BLooper("main_mime") - , fMimeDatabase() + , fDatabase() { } @@ -61,8 +61,8 @@ MIMEManager::MessageReceived(BMessage *message) err = message->FindMessenger("target", &messenger); if (!err) { err = message->what == B_REG_MIME_START_WATCHING - ? fMimeDatabase.StartWatching(messenger) - : fMimeDatabase.StopWatching(messenger); + ? fDatabase.StartWatching(messenger) + : fDatabase.StopWatching(messenger); } reply.what = B_REG_RESULT; @@ -78,13 +78,43 @@ MIMEManager::MessageReceived(BMessage *message) err = message->FindString("type", &type); if (!err) err = message->what == B_REG_MIME_INSTALL - ? fMimeDatabase.Install(type) - : fMimeDatabase.Delete(type); + ? fDatabase.Install(type) + : fDatabase.Delete(type); + reply.what = B_REG_RESULT; reply.AddInt32("result", err); message->SendReply(&reply, this); break; } + + case B_REG_MIME_GET_INSTALLED_TYPES: + { + BMessage types; + const char *supertype; + err = message->FindString("supertype", &supertype); + if (err == B_NAME_NOT_FOUND) + err = fDatabase.GetInstalledTypes(&types); + else if (!err) + err = fDatabase.GetInstalledTypes(supertype, &types); + + reply.what = B_REG_RESULT; + reply.AddInt32("result", err); + reply.AddMessage("types", &types); + message->SendReply(&reply, this); + break; + } + + case B_REG_MIME_GET_INSTALLED_SUPERTYPES: + { + BMessage types; + err = fDatabase.GetInstalledSupertypes(&types); + + reply.what = B_REG_RESULT; + reply.AddInt32("result", err); + reply.AddMessage("types", &types); + message->SendReply(&reply, this); + break; + } default: printf("MIMEMan: msg->what == %.4s\n", &(message->what)); @@ -112,7 +142,7 @@ MIMEManager::HandleSetParam(BMessage *message) entry_ref ref; err = message->FindRef("app hint", &ref); if (!err) - err = fMimeDatabase.SetAppHint(type, &ref); + err = fDatabase.SetAppHint(type, &ref); break; } @@ -121,7 +151,7 @@ MIMEManager::HandleSetParam(BMessage *message) BMessage info; err = message->FindMessage("attr info", &info); if (!err) - err = fMimeDatabase.SetAttrInfo(type, &info); + err = fDatabase.SetAttrInfo(type, &info); break; } @@ -134,8 +164,8 @@ MIMEManager::HandleSetParam(BMessage *message) err = message->FindString("description", &description); if (!err) err = (isLong - ? fMimeDatabase.SetLongDescription(type, description) - : fMimeDatabase.SetShortDescription(type, description)); + ? fDatabase.SetLongDescription(type, description) + : fDatabase.SetShortDescription(type, description)); break; } @@ -144,11 +174,10 @@ MIMEManager::HandleSetParam(BMessage *message) BMessage extensions; err = message->FindMessage("extensions", &extensions); if (!err) - err = fMimeDatabase.SetFileExtensions(type, &extensions); + err = fDatabase.SetFileExtensions(type, &extensions); break; } - case B_REG_MIME_ICON: case B_REG_MIME_ICON_FOR_TYPE: { @@ -163,11 +192,11 @@ MIMEManager::HandleSetParam(BMessage *message) if (!err) err = message->FindString("file type", &fileType); if (!err) - err = fMimeDatabase.SetIconForType(type, fileType, data, + err = fDatabase.SetIconForType(type, fileType, data, dataSize, (icon_size)size); } else { if (!err) - err = fMimeDatabase.SetIcon(type, data, dataSize, + err = fDatabase.SetIcon(type, data, dataSize, (icon_size)size); } break; @@ -182,10 +211,19 @@ MIMEManager::HandleSetParam(BMessage *message) if (!err) err = message->FindInt32("app verb", &verb); if (!err) - err = fMimeDatabase.SetPreferredApp(type, signature, (app_verb)verb); + err = fDatabase.SetPreferredApp(type, signature, (app_verb)verb); break; } + case B_REG_MIME_SUPPORTED_TYPES: + { + BMessage types; + err = message->FindMessage("types", &types); + if (!err) + err = fDatabase.SetSupportedTypes(type, &types); + break; + } + default: err = B_BAD_VALUE; break; @@ -214,11 +252,11 @@ MIMEManager::HandleDeleteParam(BMessage *message) if (!err) { switch (which) { case B_REG_MIME_APP_HINT: - err = fMimeDatabase.DeleteAppHint(type); + err = fDatabase.DeleteAppHint(type); break; case B_REG_MIME_ATTR_INFO: - err = fMimeDatabase.DeleteAttrInfo(type); + err = fDatabase.DeleteAttrInfo(type); break; case B_REG_MIME_DESCRIPTION: @@ -227,13 +265,13 @@ MIMEManager::HandleDeleteParam(BMessage *message) err = message->FindBool("long", &isLong); if (!err) err = isLong - ? fMimeDatabase.DeleteLongDescription(type) - : fMimeDatabase.DeleteShortDescription(type); + ? fDatabase.DeleteLongDescription(type) + : fDatabase.DeleteShortDescription(type); break; } case B_REG_MIME_FILE_EXTENSIONS: - err = fMimeDatabase.DeleteFileExtensions(type); + err = fDatabase.DeleteFileExtensions(type); break; case B_REG_MIME_ICON: @@ -246,10 +284,10 @@ MIMEManager::HandleDeleteParam(BMessage *message) if (!err) err = message->FindString("file type", &fileType); if (!err) - err = fMimeDatabase.DeleteIconForType(type, fileType, (icon_size)size); + err = fDatabase.DeleteIconForType(type, fileType, (icon_size)size); } else { if (!err) - err = fMimeDatabase.DeleteIcon(type, (icon_size)size); + err = fDatabase.DeleteIcon(type, (icon_size)size); } break; } @@ -259,12 +297,16 @@ MIMEManager::HandleDeleteParam(BMessage *message) int32 verb; err = message->FindInt32("app verb", &verb); if (!err) - err = fMimeDatabase.DeletePreferredApp(type, (app_verb)verb); + err = fDatabase.DeletePreferredApp(type, (app_verb)verb); break; } case B_REG_MIME_SNIFFER_RULE: - err = fMimeDatabase.DeleteSnifferRule(type); + err = fDatabase.DeleteSnifferRule(type); + break; + + case B_REG_MIME_SUPPORTED_TYPES: + err = fDatabase.DeleteSupportedTypes(type); break; default: diff --git a/src/servers/registrar/MIMEManager.h b/src/servers/registrar/MIMEManager.h index b99c1ac789..3fad018d52 100644 --- a/src/servers/registrar/MIMEManager.h +++ b/src/servers/registrar/MIMEManager.h @@ -4,7 +4,7 @@ #define MIME_MANAGER_H #include -#include +#include class MIMEManager : public BLooper { public: @@ -16,7 +16,7 @@ private: void HandleSetParam(BMessage *message); void HandleDeleteParam(BMessage *message); - BPrivate::MimeDatabase fMimeDatabase; + BPrivate::Storage::Mime::Database fDatabase; }; #endif // MIME_MANAGER_H