1/* 2 * Copyright 2002-2007, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 */ 8 9 10/*! 11 \file database_access.cpp 12 Mime database atomic read functions 13*/ 14 15#include <Bitmap.h> 16#include <Entry.h> 17#include <Directory.h> 18#include <IconUtils.h> 19#include <Message.h> 20#include <mime/database_support.h> 21#include <Node.h> 22#include <Path.h> 23#include <RegistrarDefs.h> 24#include <String.h> 25#include <storage_support.h> 26 27#include <fs_attr.h> // For struct attr_info 28#include <iostream> 29#include <new> // For new(nothrow) 30#include <stdio.h> 31#include <string> 32 33#include "mime/database_access.h" 34 35#define DBG(x) x 36//#define DBG(x) 37#define OUT printf 38 39namespace BPrivate { 40namespace Storage { 41namespace Mime { 42 43 44/*! \brief Fetches the application hint for the given MIME type. 45 46 The entry_ref pointed to by \c ref must be pre-allocated. 47 48 \param type The MIME type of interest 49 \param ref Pointer to a pre-allocated \c entry_ref struct into 50 which the location of the hint application is copied. 51 52 \return 53 - \c B_OK: Success 54 - \c B_ENTRY_NOT_FOUND: No app hint exists for the given type 55 - "error code": Failure 56*/ 57status_t 58get_app_hint(const char *type, entry_ref *ref) 59{ 60 if (type == NULL || ref == NULL) 61 return B_BAD_VALUE; 62 63 char path[B_PATH_NAME_LENGTH]; 64 BEntry entry; 65 ssize_t status = read_mime_attr(type, kAppHintAttr, path, 66 B_PATH_NAME_LENGTH, kAppHintType); 67 68 if (status >= B_OK) 69 status = entry.SetTo(path); 70 if (status == B_OK) 71 status = entry.GetRef(ref); 72 73 return status; 74} 75 76 77/*! \brief Fetches from the MIME database a BMessage describing the attributes 78 typically associated with files of the given MIME type 79 80 The attribute information is returned in a pre-allocated BMessage pointed to by 81 the \c info parameter (note that the any prior contents of the message 82 will be destroyed). Please see BMimeType::SetAttrInfo() for a description 83 of the expected format of such a message. 84 85 \param info Pointer to a pre-allocated BMessage into which information about 86 the MIME type's associated file attributes is stored. 87 \return 88 - \c B_OK: Success 89 - "error code": Failure 90*/ 91status_t 92get_attr_info(const char *type, BMessage *info) 93{ 94 status_t err = read_mime_attr_message(type, kAttrInfoAttr, info); 95 if (err == B_ENTRY_NOT_FOUND) { 96 // return an empty message 97 info->MakeEmpty(); 98 err = B_OK; 99 } 100 if (err == B_OK) { 101 info->what = 233; 102 // Don't know why, but that's what R5 does. 103 err = info->AddString("type", type); 104 } 105 return err; 106} 107 108 109/*! \brief Fetches the short description for the given MIME type. 110 111 The string pointed to by \c description must be long enough to 112 hold the short description; a length of \c B_MIME_TYPE_LENGTH is 113 recommended. 114 115 \param type The MIME type of interest 116 \param description Pointer to a pre-allocated string into which the short 117 description is copied. If the function fails, the contents 118 of the string are undefined. 119 120 \return 121 - \c B_OK: Success 122 - \c B_ENTRY_NOT_FOUND: No short description exists for the given type 123 - "error code": Failure 124*/ 125status_t 126get_short_description(const char *type, char *description) 127{ 128/// DBG(OUT("Mime::Database::get_short_description()\n")); 129 ssize_t err = read_mime_attr(type, kShortDescriptionAttr, description, 130 B_MIME_TYPE_LENGTH, kShortDescriptionType); 131 return err >= 0 ? B_OK : err ; 132} 133 134// get_long_description 135//! Fetches the long description for the given MIME type. 136/*! The string pointed to by \c description must be long enough to 137 hold the long description; a length of \c B_MIME_TYPE_LENGTH is 138 recommended. 139 140 \param type The MIME type of interest 141 \param description Pointer to a pre-allocated string into which the long 142 description is copied. If the function fails, the contents 143 of the string are undefined. 144 145 \return 146 - \c B_OK: Success 147 - \c B_ENTRY_NOT_FOUND: No long description exists for the given type 148 - "error code": Failure 149*/ 150status_t 151get_long_description(const char *type, char *description) 152{ 153// DBG(OUT("Mime::Database::get_long_description()\n")); 154 ssize_t err = read_mime_attr(type, kLongDescriptionAttr, description, 155 B_MIME_TYPE_LENGTH, kLongDescriptionType); 156 return err >= 0 ? B_OK : err ; 157} 158 159 160/*! \brief Fetches a BMessage describing the MIME type's associated filename 161 extensions 162 163 The list of extensions is returned in a pre-allocated BMessage pointed to 164 by the \c extensions parameter (note that the any prior contents of the 165 message will be destroyed). Please see BMimeType::GetFileExtensions() for 166 a description of the message format. 167 168 \param extensions Pointer to a pre-allocated BMessage into which the MIME 169 type's associated file extensions will be stored. 170 \return 171 - \c B_OK: Success 172 - "error code": Failure 173*/ 174status_t 175get_file_extensions(const char *type, BMessage *extensions) 176{ 177 status_t err = read_mime_attr_message(type, kFileExtensionsAttr, extensions); 178 if (err == B_ENTRY_NOT_FOUND) { 179 // return an empty message 180 extensions->MakeEmpty(); 181 err = B_OK; 182 } 183 if (err == B_OK) { 184 extensions->what = 234; // Don't know why, but that's what R5 does. 185 err = extensions->AddString("type", type); 186 } 187 return err; 188} 189 190 191/*! \brief Fetches the icon of given size associated with the given MIME type 192 193 The bitmap pointed to by \c icon must be of the proper size (\c 32x32 194 for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and color depth 195 (\c B_CMAP8). 196 197 \param type The mime type 198 \param icon Pointer to a pre-allocated bitmap of proper dimensions and color depth 199 \param size The size icon you're interested in (\c B_LARGE_ICON or \c B_MINI_ICON) 200*/ 201status_t 202get_icon(const char *type, BBitmap *icon, icon_size which) 203{ 204 return get_icon_for_type(type, NULL, icon, which); 205} 206 207// get_icon 208//! Fetches the vector icon associated with the given MIME type 209/* \param type The mime type 210 \param data Pointer in which the allocated icon data is returned. You need to 211 free the buffer once you're done with it. 212 \param size Pointer in which the size of the icon data is returned. 213*/ 214status_t 215get_icon(const char *type, uint8** data, size_t* size) 216{ 217 return get_icon_for_type(type, NULL, data, size); 218} 219 220// get_icon_for_type 221/*! \brief Fetches the large or mini icon used by an application of this type for files of the 222 given type. 223 224 The type of the \c BMimeType object is not required to actually be a subtype of 225 \c "application/"; that is the intended use however, and calling \c get_icon_for_type() 226 on a non-application type will likely return \c B_ENTRY_NOT_FOUND. 227 228 The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap must 229 be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon. 230 231 \param type The MIME type 232 \param fileType Pointer to a pre-allocated string containing the MIME type whose 233 custom icon you wish to fetch. If NULL, works just like get_icon(). 234 \param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace into 235 which the icon is copied. 236 \param icon_size Value that specifies which icon to return. Currently \c B_LARGE_ICON 237 and \c B_MINI_ICON are supported. 238 \return 239 - \c B_OK: Success 240 - \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type 241 - "error code": Failure 242 243*/ 244status_t 245get_icon_for_type(const char* type, const char* fileType, BBitmap* icon, 246 icon_size which) 247{ 248 if (!type || !icon) 249 return B_BAD_VALUE; 250 251 // open the node for the given type 252 BNode node; 253 ssize_t err = open_type(type, &node); 254 if (err < B_OK) 255 return (status_t)err; 256 257 // construct our attribute name 258 std::string vectorIconAttrName; 259 std::string smallIconAttrName; 260 std::string largeIconAttrName; 261 262 if (fileType) { 263 std::string lowerCaseFileType = BPrivate::Storage::to_lower(fileType); 264 265 vectorIconAttrName = kIconAttrPrefix + lowerCaseFileType; 266 smallIconAttrName = kMiniIconAttrPrefix + lowerCaseFileType; 267 largeIconAttrName = kLargeIconAttrPrefix + lowerCaseFileType; 268 } else { 269 vectorIconAttrName = kIconAttr; 270 smallIconAttrName = kMiniIconAttr; 271 largeIconAttrName = kLargeIconAttr; 272 } 273 274 return BIconUtils::GetIcon(&node, vectorIconAttrName.c_str(), 275 smallIconAttrName.c_str(), largeIconAttrName.c_str(), 276 which, icon); 277 278 279// ssize_t err = type && icon ? B_OK : B_BAD_VALUE; 280// 281// // Figure out what kind of data we *should* find 282// uint32 attrType = 0; 283// ssize_t attrSize = 0; 284// BRect bounds; 285// 286// if (!err) { 287// switch (which) { 288// case B_MINI_ICON: 289// bounds.Set(0, 0, 15, 15); 290// attrType = kMiniIconType; 291// attrSize = 16 * 16; 292// break; 293// case B_LARGE_ICON: 294// bounds.Set(0, 0, 31, 31); 295// attrType = kLargeIconType; 296// attrSize = 32 * 32; 297// break; 298// default: 299// err = B_BAD_VALUE; 300// break; 301// } 302// } 303// // Construct our attribute name 304// std::string attr; 305// if (fileType) { 306// attr = (which == B_MINI_ICON 307// ? kMiniIconAttrPrefix 308// : kLargeIconAttrPrefix) 309// + BPrivate::Storage::to_lower(fileType); 310// } else { 311// attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr; 312// } 313// // Check the icon and attribute to see if they match 314// if (!err) { 315// err = (icon->InitCheck() == B_OK 316// && icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE; 317// } 318// 319// BNode node; 320// if (!err) 321// err = open_type(type, &node); 322// 323// attr_info info; 324// if (!err) 325// err = node.GetAttrInfo(attr.c_str(), &info); 326// 327// if (!err) 328// err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE; 329// // read the attribute 330// if (!err) { 331// bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 332// char *buffer = NULL; 333// if (otherColorSpace) { 334// // other color space than stored in attribute 335// buffer = new(std::nothrow) char[attrSize]; 336// if (!buffer) 337// err = B_NO_MEMORY; 338// if (!err) 339// err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize); 340// } else { 341// // same color space, just read direct 342// err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize); 343// } 344// if (err >= 0) 345// err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR; 346// if (otherColorSpace) { 347// if (!err) { 348// err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, 349// 0, B_CMAP8); 350// } 351// delete[] buffer; 352// } 353// } 354// 355// return err; 356} 357 358// get_icon_for_type 359/*! \brief Fetches the vector icon used by an application of this type for files of the 360 given type. 361 362 The type of the \c BMimeType object is not required to actually be a subtype of 363 \c "application/"; that is the intended use however, and calling \c get_icon_for_type() 364 on a non-application type will likely return \c B_ENTRY_NOT_FOUND. 365 366 The icon data is allocated and returned in \a data. 367 368 \param type The MIME type 369 \param fileType Pointer to a pre-allocated string containing the MIME type whose 370 custom icon you wish to fetch. If NULL, works just like get_icon(). 371 \param data Pointer in which the icon data is returned on success. 372 \param size Pointer in which the size of the icon data is returned. 373 \return 374 - \c B_OK: Success 375 - \c B_ENTRY_NOT_FOUND: No vector icon exists for the given type 376 - "error code": Failure 377 378*/ 379status_t 380get_icon_for_type(const char* type, const char* fileType, uint8** data, 381 size_t* size) 382{ 383 if (!type || !data || !size) 384 return B_BAD_VALUE; 385 386 // open the node for the given type 387 BNode node; 388 ssize_t err = open_type(type, &node); 389 if (err < B_OK) 390 return (status_t)err; 391 392 // construct our attribute name 393 std::string iconAttrName; 394 395 if (fileType) 396 iconAttrName = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType); 397 else 398 iconAttrName = kIconAttr; 399 400 // get info about attribute for that name 401 attr_info info; 402 if (!err) 403 err = node.GetAttrInfo(iconAttrName.c_str(), &info); 404 405 // validate attribute type 406 if (!err) 407 err = (info.type == B_VECTOR_ICON_TYPE) ? B_OK : B_BAD_VALUE; 408 409 // allocate a buffer and read the attribute data into it 410 if (!err) { 411 uint8* buffer = new(std::nothrow) uint8[info.size]; 412 if (!buffer) 413 err = B_NO_MEMORY; 414 if (!err) { 415 err = node.ReadAttr(iconAttrName.c_str(), B_VECTOR_ICON_TYPE, 416 0, buffer, info.size); 417 } 418 419 if (err >= 0) 420 err = (err == info.size) ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; 421 422 if (!err) { 423 // success, set data pointer and size 424 *data = buffer; 425 *size = info.size; 426 } else { 427 delete[] buffer; 428 } 429 } 430 431 return err; 432} 433 434 435/*! \brief Fetches signature of the MIME type's preferred application for the 436 given action. 437 438 The string pointed to by \c signature must be long enough to 439 hold the short description; a length of \c B_MIME_TYPE_LENGTH is 440 recommended. 441 442 Currently, the only supported app verb is \c B_OPEN. 443 444 \param type The MIME type of interest 445 \param description Pointer to a pre-allocated string into which the 446 preferred application's signature is copied. If the function fails, 447 the contents of the string are undefined. 448 \param verb \c The action of interest 449 450 \return 451 - \c B_OK: Success 452 - \c B_ENTRY_NOT_FOUND: No such preferred application exists 453 - "error code": Failure 454*/ 455status_t 456get_preferred_app(const char *type, char *signature, app_verb verb = B_OPEN) 457{ 458 // Since B_OPEN is the currently the only app_verb, it is essentially ignored 459 ssize_t err = read_mime_attr(type, kPreferredAppAttr, signature, 460 B_MIME_TYPE_LENGTH, kPreferredAppType); 461 return err >= 0 ? B_OK : err ; 462} 463 464 465/*! \brief Fetches the sniffer rule for the given MIME type. 466 \param type The MIME type of interest 467 \param result Pointer to a pre-allocated BString into which the type's 468 sniffer rule is copied. 469 \return 470 - \c B_OK: Success 471 - \c B_ENTRY_NOT_FOUND: No such preferred application exists 472 - "error code": Failure 473*/ 474status_t 475get_sniffer_rule(const char *type, BString *result) 476{ 477 return read_mime_attr_string(type, kSnifferRuleAttr, result); 478} 479 480 481status_t 482get_supported_types(const char *type, BMessage *types) 483{ 484 status_t err = read_mime_attr_message(type, kSupportedTypesAttr, types); 485 if (err == B_ENTRY_NOT_FOUND) { 486 // return an empty message 487 types->MakeEmpty(); 488 err = B_OK; 489 } 490 if (err == B_OK) { 491 types->what = 0; 492 err = types->AddString("type", type); 493 } 494 return err; 495} 496 497 498//! Checks if the given MIME type is present in the database 499bool 500is_installed(const char *type) 501{ 502 BNode node; 503 return open_type(type, &node) == B_OK; 504} 505 506 507/*! \brief Returns properly formatted raw bitmap data, ready to be shipped off 508 to the hacked up 4-parameter version of Database::SetIcon() 509 510 This function exists as something of a hack until an OBOS::BBitmap 511 implementation is available. It takes the given bitmap, converts it to the 512 B_CMAP8 color space if necessary and able, and returns said bitmap data in 513 a newly allocated array pointed to by the pointer that's pointed to by 514 \c data. The length of the array is stored in the integer pointed to by 515 \c dataSize. The array is allocated with \c new[], and it's your 516 responsibility to \c delete[] it when you're finished. 517*/ 518status_t 519get_icon_data(const BBitmap *icon, icon_size which, void **data, 520 int32 *dataSize) 521{ 522 if (icon == NULL || data == NULL || dataSize == 0 523 || icon->InitCheck() != B_OK) 524 return B_BAD_VALUE; 525 526 BRect bounds; 527 BBitmap *icon8 = NULL; 528 void *srcData = NULL; 529 bool otherColorSpace = false; 530 531 // Figure out what kind of data we *should* have 532 switch (which) { 533 case B_MINI_ICON: 534 bounds.Set(0, 0, 15, 15); 535 break; 536 case B_LARGE_ICON: 537 bounds.Set(0, 0, 31, 31); 538 break; 539 default: 540 return B_BAD_VALUE; 541 } 542 543 // Check the icon 544 status_t err = icon->Bounds() == bounds ? B_OK : B_BAD_VALUE; 545 546 // Convert to B_CMAP8 if necessary 547 if (!err) { 548 otherColorSpace = (icon->ColorSpace() != B_CMAP8); 549 if (otherColorSpace) { 550 icon8 = new(std::nothrow) BBitmap(bounds, B_BITMAP_NO_SERVER_LINK, 551 B_CMAP8); 552 if (!icon8) 553 err = B_NO_MEMORY; 554 if (!err) 555 err = icon8->ImportBits(icon); 556 if (!err) { 557 srcData = icon8->Bits(); 558 *dataSize = icon8->BitsLength(); 559 } 560 } else { 561 srcData = icon->Bits(); 562 *dataSize = icon->BitsLength(); 563 } 564 } 565 566 // Alloc a new data buffer 567 if (!err) { 568 *data = new(std::nothrow) char[*dataSize]; 569 if (!*data) 570 err = B_NO_MEMORY; 571 } 572 573 // Copy the data into it. 574 if (!err) 575 memcpy(*data, srcData, *dataSize); 576 if (otherColorSpace) 577 delete icon8; 578 return err; 579} 580 581} // namespace Mime 582} // namespace Storage 583} // namespace BPrivate 584 585