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