1 //---------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 //--------------------------------------------------------------------- 5 /*! 6 \file database_support.cpp 7 Private mime database functions and constants 8 */ 9 10 #include <AppMisc.h> 11 #include <DataIO.h> 12 #include <Directory.h> 13 #include <Entry.h> 14 #include <FindDirectory.h> 15 #include <Message.h> 16 #include <Node.h> 17 #include <Path.h> 18 #include <storage_support.h> 19 #include <TypeConstants.h> 20 21 #include <fs_attr.h> // For struct attr_info 22 #include <new> // For new(nothrow) 23 #include <stdio.h> 24 #include <string> 25 26 #include "mime/database_support.h" 27 28 //#define DBG(x) x 29 #define DBG(x) 30 #define OUT printf 31 32 // icon types (which really ought to be publicly or semi-publicly declared somewhere...) 33 enum { 34 B_MINI_ICON_TYPE = 'MICN', 35 B_LARGE_ICON_TYPE = 'ICON', 36 }; 37 38 namespace BPrivate { 39 namespace Storage { 40 namespace Mime { 41 42 static const char *get_user_settings_dir(BPath &path); 43 44 static BPath sSettingsDirPath; 45 static const std::string sSettingsDir = get_user_settings_dir(sSettingsDirPath); 46 47 static const char *sHaikuDBDirName = "beos_mime"; 48 // when running natively under Haiku 49 static const char *sBeOSDBDirName = "obos_mime"; 50 // when running under BeOS 51 const std::string kDatabaseDir = sSettingsDir + "/" 52 + (is_running_on_haiku() ? sHaikuDBDirName : sBeOSDBDirName); 53 const std::string kApplicationDatabaseDir = kDatabaseDir + "/application"; 54 55 #define ATTR_PREFIX "META:" 56 #define MINI_ICON_ATTR_PREFIX ATTR_PREFIX "M:" 57 #define LARGE_ICON_ATTR_PREFIX ATTR_PREFIX "L:" 58 59 const char *kMiniIconAttrPrefix = MINI_ICON_ATTR_PREFIX; 60 const char *kLargeIconAttrPrefix = LARGE_ICON_ATTR_PREFIX; 61 62 // attribute names 63 const char *kFileTypeAttr = "BEOS:TYPE"; 64 const char *kTypeAttr = ATTR_PREFIX "TYPE"; 65 const char *kAppHintAttr = ATTR_PREFIX "PPATH"; 66 const char *kAttrInfoAttr = ATTR_PREFIX "ATTR_INFO"; 67 const char *kShortDescriptionAttr = ATTR_PREFIX "S:DESC"; 68 const char *kLongDescriptionAttr = ATTR_PREFIX "L:DESC"; 69 const char *kFileExtensionsAttr = ATTR_PREFIX "EXTENS"; 70 const char *kMiniIconAttr = MINI_ICON_ATTR_PREFIX "STD_ICON"; 71 const char *kLargeIconAttr = LARGE_ICON_ATTR_PREFIX "STD_ICON"; 72 const char *kPreferredAppAttr = ATTR_PREFIX "PREF_APP"; 73 const char *kSnifferRuleAttr = ATTR_PREFIX "SNIFF_RULE"; 74 const char *kSupportedTypesAttr = ATTR_PREFIX "FILE_TYPES"; 75 76 // attribute data types (as used in the R5 database) 77 const int32 kFileTypeType = 'MIMS'; // B_MIME_STRING_TYPE 78 const int32 kTypeType = B_STRING_TYPE; 79 const int32 kAppHintType = 'MPTH'; 80 const int32 kAttrInfoType = B_MESSAGE_TYPE; 81 const int32 kShortDescriptionType = 'MSDC'; 82 const int32 kLongDescriptionType = 'MLDC'; 83 const int32 kFileExtensionsType = B_MESSAGE_TYPE; 84 const int32 kMiniIconType = B_MINI_ICON_TYPE; 85 const int32 kLargeIconType = B_LARGE_ICON_TYPE; 86 const int32 kPreferredAppType = 'MSIG'; 87 const int32 kSnifferRuleType = B_STRING_TYPE; 88 const int32 kSupportedTypesType = B_MESSAGE_TYPE; 89 90 // Message fields 91 const char *kApplicationsField = "applications"; 92 const char *kExtensionsField = "extensions"; 93 const char *kSupertypesField = "super_types"; 94 const char *kSupportingAppsSubCountField = "be:sub"; 95 const char *kSupportingAppsSuperCountField = "be:super"; 96 const char *kTypesField = "types"; 97 98 // Mime types 99 const char *kGenericFileType = "application/octet-stream"; 100 const char *kDirectoryType = "application/x-vnd.Be-directory"; 101 const char *kSymlinkType = "application/x-vnd.Be-symlink"; 102 const char *kMetaMimeType = "application/x-vnd.Be-meta-mime"; 103 104 // Error codes 105 const status_t kMimeGuessFailureError = B_ERRORS_END+1; 106 107 // get_settings_dir 108 /*! \brief Sets the supplied BPath to the user settings directory and returns 109 it as C string. 110 \param path BPath to be set to the user settings path. 111 \return the user settings path as C string (\code path.Path() \endcode). 112 */ 113 static 114 const char* 115 get_user_settings_dir(BPath &path) 116 { 117 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 118 path.SetTo("/boot/home/config/settings"); 119 return path.Path(); 120 } 121 122 // type_to_filename 123 //! Converts the given MIME type to an absolute path in the MIME database. 124 std::string 125 type_to_filename(const char *type) 126 { 127 return kDatabaseDir + "/" + BPrivate::Storage::to_lower(type); 128 } 129 130 // open_type 131 /*! \brief Opens a BNode on the given type, failing if the type has no 132 corresponding file in the database. 133 \param type The MIME type to open 134 \param result Pointer to a pre-allocated BNode into which 135 is opened on the given MIME type 136 */ 137 status_t 138 open_type(const char *type, BNode *result) 139 { 140 status_t err = (type && result ? B_OK : B_BAD_VALUE); 141 if (!err) 142 err = result->SetTo(type_to_filename(type).c_str()); 143 return err; 144 } 145 146 // open_or_create_type 147 /*! \brief Opens a BNode on the given type, creating a node of the 148 appropriate flavor if necessary. 149 150 All MIME types are converted to lowercase for use in the filesystem. 151 \param type The MIME type to open 152 \param result Pointer to a pre-allocated BNode into which 153 is opened on the given MIME type 154 */ 155 status_t 156 open_or_create_type(const char *type, BNode *result, bool *didCreate) 157 { 158 if (didCreate) 159 *didCreate = false; 160 std::string filename; 161 std::string typeLower = BPrivate::Storage::to_lower(type); 162 status_t err = (type && result ? B_OK : B_BAD_VALUE); 163 if (!err) { 164 filename = type_to_filename(type); 165 err = result->SetTo(filename.c_str()); 166 } 167 if (err == B_ENTRY_NOT_FOUND) { 168 // Figure out what type of node we need to create 169 // + Supertype == directory 170 // + Non-supertype == file 171 uint32 pos = typeLower.find_first_of('/'); 172 if (pos == std::string::npos) { 173 // Supertype == directory 174 BDirectory parent(kDatabaseDir.c_str()); 175 err = parent.InitCheck(); 176 if (!err) 177 err = parent.CreateDirectory(typeLower.c_str(), NULL); 178 } else { 179 // Non-supertype == file 180 std::string super(typeLower, 0, pos); 181 std::string sub(typeLower, pos+1); 182 BDirectory parent((kDatabaseDir + "/" + super).c_str()); 183 err = parent.InitCheck(); 184 if (!err) 185 err = parent.CreateFile(sub.c_str(), NULL); 186 } 187 // Now try opening again 188 err = result->SetTo(filename.c_str()); 189 if (!err && didCreate) 190 *didCreate = true; 191 } 192 return err; 193 } 194 195 // read_mime_attr 196 /*! \brief Reads up to \c len bytes of the given data from the given attribute 197 for the given MIME type. 198 199 If no entry for the given type exists in the database, the function fails, 200 and the contents of \c data are undefined. 201 202 \param type The MIME type 203 \param attr The attribute name 204 \param data Pointer to a memory buffer into which the data should be copied 205 \param len The maximum number of bytes to read 206 \param datatype The expected data type 207 \return If successful, the number of bytes read is returned, otherwise, an 208 error code is returned. 209 */ 210 ssize_t 211 read_mime_attr(const char *type, const char *attr, void *data, 212 size_t len, type_code datatype) 213 { 214 BNode node; 215 ssize_t err = (type && attr && data ? B_OK : B_BAD_VALUE); 216 if (!err) 217 err = open_type(type, &node); 218 if (!err) 219 err = node.ReadAttr(attr, datatype, 0, data, len); 220 return err; 221 } 222 223 // read_mime_attr_message 224 /*! \brief Reads a flattened BMessage from the given attribute of the given 225 MIME type. 226 227 If no entry for the given type exists in the database, or if the data 228 stored in the attribute is not a flattened BMessage, the function fails 229 and the contents of \c msg are undefined. 230 231 \param type The MIME type 232 \param attr The attribute name 233 \param data Pointer to a pre-allocated BMessage into which the attribute 234 data is unflattened. 235 */ 236 status_t 237 read_mime_attr_message(const char *type, const char *attr, BMessage *msg) 238 { 239 BNode node; 240 attr_info info; 241 char *buffer = NULL; 242 ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE); 243 if (!err) 244 err = open_type(type, &node); 245 if (!err) 246 err = node.GetAttrInfo(attr, &info); 247 if (!err) 248 err = info.type == B_MESSAGE_TYPE ? B_OK : B_BAD_VALUE; 249 if (!err) { 250 buffer = new(std::nothrow) char[info.size]; 251 if (!buffer) 252 err = B_NO_MEMORY; 253 } 254 if (!err) 255 err = node.ReadAttr(attr, B_MESSAGE_TYPE, 0, buffer, info.size); 256 if (err >= 0) 257 err = err == info.size ? (status_t)B_OK : (status_t)B_FILE_ERROR; 258 if (!err) 259 err = msg->Unflatten(buffer); 260 delete [] buffer; 261 return err; 262 } 263 264 // read_mime_attr_string 265 /*! \brief Reads a BString from the given attribute of the given 266 MIME type. 267 268 If no entry for the given type exists in the database, the function fails 269 and the contents of \c str are undefined. 270 271 \param type The MIME type 272 \param attr The attribute name 273 \param str Pointer to a pre-allocated BString into which the attribute 274 data stored. 275 */ 276 status_t 277 read_mime_attr_string(const char *type, const char *attr, BString *str) 278 { 279 BNode node; 280 status_t err = (type && attr && str ? B_OK : B_BAD_VALUE); 281 if (!err) 282 err = open_type(type, &node); 283 if (!err) 284 err = node.ReadAttrString(attr, str); 285 return err; 286 } 287 288 // write_mime_attr 289 /*! \brief Writes \c len bytes of the given data to the given attribute 290 for the given MIME type. 291 292 If no entry for the given type exists in the database, it is created. 293 294 \param type The MIME type 295 \param attr The attribute name 296 \param data Pointer to the data to write 297 \param len The number of bytes to write 298 \param datatype The data type of the given data 299 */ 300 status_t 301 write_mime_attr(const char *type, const char *attr, const void *data, 302 size_t len, type_code datatype, bool *didCreate) 303 { 304 BNode node; 305 status_t err = (type && attr && data ? B_OK : B_BAD_VALUE); 306 if (!err) 307 err = open_or_create_type(type, &node, didCreate); 308 if (!err) { 309 ssize_t bytes = node.WriteAttr(attr, datatype, 0, data, len); 310 if (bytes < B_OK) 311 err = bytes; 312 else 313 err = (bytes != (ssize_t)len ? (status_t)B_FILE_ERROR : (status_t)B_OK); 314 } 315 return err; 316 } 317 318 // write_mime_attr_message 319 /*! \brief Flattens the given \c BMessage and writes it to the given attribute 320 of the given MIME type. 321 322 If no entry for the given type exists in the database, it is created. 323 324 \param type The MIME type 325 \param attr The attribute name 326 \param msg The BMessage to flatten and write 327 */ 328 status_t 329 write_mime_attr_message(const char *type, const char *attr, const BMessage *msg, bool *didCreate) 330 { 331 BNode node; 332 BMallocIO data; 333 ssize_t bytes; 334 ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE); 335 if (!err) 336 err = data.SetSize(msg->FlattenedSize()); 337 if (!err) 338 err = msg->Flatten(&data, &bytes); 339 if (!err) 340 err = bytes == msg->FlattenedSize() ? B_OK : B_ERROR; 341 if (!err) 342 err = open_or_create_type(type, &node, didCreate); 343 if (!err) 344 err = node.WriteAttr(attr, B_MESSAGE_TYPE, 0, data.Buffer(), data.BufferLength()); 345 if (err >= 0) 346 err = err == (ssize_t)data.BufferLength() ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; 347 return err; 348 } 349 350 // delete_attribute 351 //! Deletes the given attribute for the given type 352 /*! 353 \param type The mime type 354 \param attr The attribute name 355 \return 356 - B_OK: success 357 - B_ENTRY_NOT_FOUND: no such type or attribute 358 - "error code": failure 359 */ 360 status_t 361 delete_attribute(const char *type, const char *attr) 362 { 363 status_t err = type ? B_OK : B_BAD_VALUE; 364 BNode node; 365 if (!err) 366 err = open_type(type, &node); 367 if (!err) 368 err = node.RemoveAttr(attr); 369 return err; 370 } 371 372 373 374 } // namespace Mime 375 } // namespace Storage 376 } // namespace BPrivate 377 378