1 /* 2 * Copyright 2002-2014, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Rene Gollent, rene@gollent.com. 8 * Ingo Weinhold <ingo_weinhold@gmx.de> 9 */ 10 11 12 #include <mime/DatabaseLocation.h> 13 14 #include <stdlib.h> 15 #include <syslog.h> 16 17 #include <new> 18 19 #include <Bitmap.h> 20 #include <DataIO.h> 21 #include <Directory.h> 22 #include <File.h> 23 #include <fs_attr.h> 24 #include <IconUtils.h> 25 #include <Message.h> 26 #include <Node.h> 27 28 #include <AutoDeleter.h> 29 #include <mime/database_support.h> 30 31 32 namespace BPrivate { 33 namespace Storage { 34 namespace Mime { 35 36 37 DatabaseLocation::DatabaseLocation() 38 : 39 fDirectories() 40 { 41 } 42 43 44 DatabaseLocation::~DatabaseLocation() 45 { 46 } 47 48 49 bool 50 DatabaseLocation::AddDirectory(const BString& directory) 51 { 52 return !directory.IsEmpty() && fDirectories.Add(directory); 53 } 54 55 56 /*! \brief Opens a BNode on the given type, failing if the type has no 57 corresponding file in the database. 58 \param type The MIME type to open. 59 \param _node Node opened on the given MIME type. 60 */ 61 status_t 62 DatabaseLocation::OpenType(const char* type, BNode& _node) const 63 { 64 if (type == NULL) 65 return B_BAD_VALUE; 66 67 int32 index; 68 return _OpenType(type, _node, index); 69 } 70 71 72 /*! \brief Opens a BNode on the given type, creating a node of the 73 appropriate flavor if requested (and necessary). 74 All MIME types are converted to lowercase for use in the filesystem. 75 \param type The MIME type to open. 76 \param _node Node opened on the given MIME type. 77 \param _didCreate If not \c NULL, the variable the pointer refers to is 78 set to \c true, if the node has been newly created, to \c false 79 otherwise. 80 */ 81 status_t 82 DatabaseLocation::OpenWritableType(const char* type, BNode& _node, bool create, 83 bool* _didCreate) const 84 { 85 if (_didCreate) 86 *_didCreate = false; 87 88 // See, if the type already exists. 89 int32 index; 90 status_t error = _OpenType(type, _node, index); 91 if (error == B_OK) { 92 if (index == 0) 93 return B_OK; 94 else if (!create) 95 return B_ENTRY_NOT_FOUND; 96 97 // The caller wants a editable node, but the node found is not in the 98 // user's settings directory. Copy the node. 99 BNode nodeToClone(_node); 100 if (nodeToClone.InitCheck() != B_OK) 101 return nodeToClone.InitCheck(); 102 103 error = _CopyTypeNode(nodeToClone, type, _node); 104 if (error != B_OK) { 105 _node.Unset(); 106 return error; 107 } 108 109 if (_didCreate != NULL) 110 *_didCreate = true; 111 return error; 112 } else if (!create) 113 return B_ENTRY_NOT_FOUND; 114 115 // type doesn't exist yet -- create the respective node 116 error = _CreateTypeNode(type, _node); 117 if (error != B_OK) 118 return error; 119 120 // write the type attribute 121 size_t toWrite = strlen(type) + 1; 122 ssize_t bytesWritten = _node.WriteAttr(kTypeAttr, B_STRING_TYPE, 0, type, 123 toWrite); 124 if (bytesWritten < 0) 125 error = bytesWritten; 126 else if ((size_t)bytesWritten != toWrite) 127 error = B_FILE_ERROR; 128 129 if (error != B_OK) { 130 _node.Unset(); 131 return error; 132 } 133 134 if (_didCreate != NULL) 135 *_didCreate = true; 136 return B_OK; 137 } 138 139 140 /*! \brief Reads up to \c len bytes of the given data from the given attribute 141 for the given MIME type. 142 143 If no entry for the given type exists in the database, the function fails, 144 and the contents of \c data are undefined. 145 146 \param type The MIME type 147 \param attribute The attribute name 148 \param data Pointer to a memory buffer into which the data should be copied 149 \param length The maximum number of bytes to read 150 \param datatype The expected data type 151 \return If successful, the number of bytes read is returned, otherwise, an 152 error code is returned. 153 */ 154 ssize_t 155 DatabaseLocation::ReadAttribute(const char* type, const char* attribute, 156 void* data, size_t length, type_code datatype) const 157 { 158 if (type == NULL || attribute == NULL || data == NULL) 159 return B_BAD_VALUE; 160 161 BNode node; 162 status_t error = OpenType(type, node); 163 if (error != B_OK) 164 return error; 165 166 return node.ReadAttr(attribute, datatype, 0, data, length); 167 } 168 169 170 /*! \brief Reads a flattened BMessage from the given attribute of the given 171 MIME type. 172 173 If no entry for the given type exists in the database, or if the data 174 stored in the attribute is not a flattened BMessage, the function fails 175 and the contents of \c msg are undefined. 176 177 \param type The MIME type 178 \param attribute The attribute name 179 \param data Reference to a pre-allocated BMessage into which the attribute 180 data is unflattened. 181 */ 182 status_t 183 DatabaseLocation::ReadMessageAttribute(const char* type, const char* attribute, 184 BMessage& _message) const 185 { 186 if (type == NULL || attribute == NULL) 187 return B_BAD_VALUE; 188 189 BNode node; 190 attr_info info; 191 192 status_t error = OpenType(type, node); 193 if (error != B_OK) 194 return error; 195 196 error = node.GetAttrInfo(attribute, &info); 197 if (error != B_OK) 198 return error; 199 200 if (info.type != B_MESSAGE_TYPE) 201 return B_BAD_VALUE; 202 203 void* buffer = malloc(info.size); 204 if (buffer == NULL) 205 return B_NO_MEMORY; 206 MemoryDeleter bufferDeleter(buffer); 207 208 ssize_t bytesRead = node.ReadAttr(attribute, B_MESSAGE_TYPE, 0, buffer, 209 info.size); 210 if (bytesRead != info.size) 211 return bytesRead < 0 ? (status_t)bytesRead : (status_t)B_FILE_ERROR; 212 213 return _message.Unflatten((const char*)buffer); 214 } 215 216 217 /*! \brief Reads a BString from the given attribute of the given 218 MIME type. 219 220 If no entry for the given type exists in the database, the function fails 221 and the contents of \c str are undefined. 222 223 \param type The MIME type 224 \param attribute The attribute name 225 \param _string Reference to a pre-allocated BString into which the attribute 226 data stored. 227 */ 228 status_t 229 DatabaseLocation::ReadStringAttribute(const char* type, const char* attribute, 230 BString& _string) const 231 { 232 if (type == NULL || attribute == NULL) 233 return B_BAD_VALUE; 234 235 BNode node; 236 status_t error = OpenType(type, node); 237 if (error != B_OK) 238 return error; 239 240 return node.ReadAttrString(attribute, &_string); 241 } 242 243 244 /*! \brief Writes \c len bytes of the given data to the given attribute 245 for the given MIME type. 246 247 If no entry for the given type exists in the database, it is created. 248 249 \param type The MIME type 250 \param attribute The attribute name 251 \param data Pointer to the data to write 252 \param length The number of bytes to write 253 \param datatype The data type of the given data 254 */ 255 status_t 256 DatabaseLocation::WriteAttribute(const char* type, const char* attribute, 257 const void* data, size_t length, type_code datatype, bool* _didCreate) const 258 { 259 if (type == NULL || attribute == NULL || data == NULL) 260 return B_BAD_VALUE; 261 262 BNode node; 263 status_t error = OpenWritableType(type, node, true, _didCreate); 264 if (error != B_OK) 265 return error; 266 267 ssize_t bytesWritten = node.WriteAttr(attribute, datatype, 0, data, length); 268 if (bytesWritten < 0) 269 return bytesWritten; 270 return bytesWritten == (ssize_t)length 271 ? (status_t)B_OK : (status_t)B_FILE_ERROR; 272 } 273 274 275 /*! \brief Flattens the given \c BMessage and writes it to the given attribute 276 of the given MIME type. 277 278 If no entry for the given type exists in the database, it is created. 279 280 \param type The MIME type 281 \param attribute The attribute name 282 \param message The BMessage to flatten and write 283 */ 284 status_t 285 DatabaseLocation::WriteMessageAttribute(const char* type, const char* attribute, 286 const BMessage& message, bool* _didCreate) const 287 { 288 BMallocIO data; 289 status_t error = data.SetSize(message.FlattenedSize()); 290 if (error != B_OK) 291 return error; 292 293 ssize_t bytes; 294 error = message.Flatten(&data, &bytes); 295 if (error != B_OK) 296 return error; 297 298 return WriteAttribute(type, attribute, data.Buffer(), data.BufferLength(), 299 B_MESSAGE_TYPE, _didCreate); 300 } 301 302 303 //! Deletes the given attribute for the given type 304 /*! 305 \param type The mime type 306 \param attribute The attribute name 307 \return 308 - B_OK: success 309 - B_ENTRY_NOT_FOUND: no such type or attribute 310 - "error code": failure 311 */ 312 status_t 313 DatabaseLocation::DeleteAttribute(const char* type, const char* attribute) const 314 { 315 if (type == NULL || attribute == NULL) 316 return B_BAD_VALUE; 317 318 BNode node; 319 status_t error = OpenWritableType(type, node, false); 320 if (error != B_OK) 321 return error; 322 323 return node.RemoveAttr(attribute); 324 } 325 326 327 /*! \brief Fetches the application hint for the given MIME type. 328 329 The entry_ref pointed to by \c ref must be pre-allocated. 330 331 \param type The MIME type of interest 332 \param _ref Reference to a pre-allocated \c entry_ref struct into 333 which the location of the hint application is copied. 334 335 \return 336 - \c B_OK: Success 337 - \c B_ENTRY_NOT_FOUND: No app hint exists for the given type 338 - "error code": Failure 339 */ 340 status_t 341 DatabaseLocation::GetAppHint(const char* type, entry_ref& _ref) 342 { 343 if (type == NULL) 344 return B_BAD_VALUE; 345 346 char path[B_PATH_NAME_LENGTH]; 347 BEntry entry; 348 ssize_t status = ReadAttribute(type, kAppHintAttr, path, B_PATH_NAME_LENGTH, 349 kAppHintType); 350 351 if (status >= B_OK) 352 status = entry.SetTo(path); 353 if (status == B_OK) 354 status = entry.GetRef(&_ref); 355 356 return status; 357 } 358 359 360 /*! \brief Fetches from the MIME database a BMessage describing the attributes 361 typically associated with files of the given MIME type 362 363 The attribute information is returned in a pre-allocated BMessage pointed to 364 by the \c info parameter (note that the any prior contents of the message 365 will be destroyed). Please see BMimeType::SetAttrInfo() for a description 366 of the expected format of such a message. 367 368 \param _info Reference to a pre-allocated BMessage into which information 369 about the MIME type's associated file attributes is stored. 370 \return 371 - \c B_OK: Success 372 - "error code": Failure 373 */ 374 status_t 375 DatabaseLocation::GetAttributesInfo(const char* type, BMessage& _info) 376 { 377 status_t err = ReadMessageAttribute(type, kAttrInfoAttr, _info); 378 if (err == B_ENTRY_NOT_FOUND) { 379 // return an empty message 380 _info.MakeEmpty(); 381 err = B_OK; 382 } 383 if (err == B_OK) { 384 _info.what = 233; 385 // Don't know why, but that's what R5 does. 386 err = _info.AddString("type", type); 387 } 388 return err; 389 } 390 391 392 /*! \brief Fetches the short description for the given MIME type. 393 394 The string pointed to by \c description must be long enough to 395 hold the short description; a length of \c B_MIME_TYPE_LENGTH is 396 recommended. 397 398 \param type The MIME type of interest 399 \param description Pointer to a pre-allocated string into which the short 400 description is copied. If the function fails, the contents of the string 401 are undefined. 402 403 \return 404 - \c B_OK: Success 405 - \c B_ENTRY_NOT_FOUND: No short description exists for the given type 406 - "error code": Failure 407 */ 408 status_t 409 DatabaseLocation::GetShortDescription(const char* type, char* description) 410 { 411 ssize_t err = ReadAttribute(type, kShortDescriptionAttr, description, 412 B_MIME_TYPE_LENGTH, kShortDescriptionType); 413 return err >= 0 ? B_OK : err ; 414 } 415 416 417 //! Fetches the long description for the given MIME type. 418 /*! The string pointed to by \c description must be long enough to 419 hold the long description; a length of \c B_MIME_TYPE_LENGTH is 420 recommended. 421 422 \param type The MIME type of interest 423 \param description Pointer to a pre-allocated string into which the long 424 description is copied. If the function fails, the contents of the string 425 are undefined. 426 427 \return 428 - \c B_OK: Success 429 - \c B_ENTRY_NOT_FOUND: No long description exists for the given type 430 - "error code": Failure 431 */ 432 status_t 433 DatabaseLocation::GetLongDescription(const char* type, char* description) 434 { 435 ssize_t err = ReadAttribute(type, kLongDescriptionAttr, description, 436 B_MIME_TYPE_LENGTH, kLongDescriptionType); 437 return err >= 0 ? B_OK : err ; 438 } 439 440 441 /*! \brief Fetches a BMessage describing the MIME type's associated filename 442 extensions 443 444 The list of extensions is returned in a pre-allocated BMessage pointed to 445 by the \c extensions parameter (note that the any prior contents of the 446 message will be destroyed). Please see BMimeType::GetFileExtensions() for 447 a description of the message format. 448 449 \param extensions Reference to a pre-allocated BMessage into which the MIME 450 type's associated file extensions will be stored. 451 \return 452 - \c B_OK: Success 453 - "error code": Failure 454 */ 455 status_t 456 DatabaseLocation::GetFileExtensions(const char* type, BMessage& _extensions) 457 { 458 status_t err = ReadMessageAttribute(type, kFileExtensionsAttr, _extensions); 459 if (err == B_ENTRY_NOT_FOUND) { 460 // return an empty message 461 _extensions.MakeEmpty(); 462 err = B_OK; 463 } 464 if (err == B_OK) { 465 _extensions.what = 234; // Don't know why, but that's what R5 does. 466 err = _extensions.AddString("type", type); 467 } 468 return err; 469 } 470 471 472 /*! \brief Fetches the icon of given size associated with the given MIME type 473 474 The bitmap pointed to by \c icon must be of the proper size (\c 32x32 475 for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and color depth 476 (\c B_CMAP8). 477 478 \param type The mime type 479 \param icon Reference to a pre-allocated bitmap of proper dimensions and 480 color depth 481 \param size The size icon you're interested in (\c B_LARGE_ICON or 482 \c B_MINI_ICON) 483 */ 484 status_t 485 DatabaseLocation::GetIcon(const char* type, BBitmap& _icon, icon_size size) 486 { 487 return GetIconForType(type, NULL, _icon, size); 488 } 489 490 491 //! Fetches the vector icon associated with the given MIME type 492 /** \param type The mime type 493 \param _data Reference via which the allocated icon data is returned. You 494 need to free the buffer once you're done with it. 495 \param _size Reference via which the size of the icon data is returned. 496 */ 497 status_t 498 DatabaseLocation::GetIcon(const char* type, uint8*& _data, size_t& _size) 499 { 500 return GetIconForType(type, NULL, _data, _size); 501 } 502 503 504 /*! \brief Fetches the large or mini icon used by an application of this type 505 for files of the given type. 506 507 The type of the \c BMimeType object is not required to actually be a subtype 508 of \c "application/"; that is the intended use however, and calling 509 \c GetIconForType() on a non-application type will likely return 510 \c B_ENTRY_NOT_FOUND. 511 512 The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap 513 must be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini 514 icon. 515 516 \param type The MIME type 517 \param fileType Pointer to a pre-allocated string containing the MIME type 518 whose custom icon you wish to fetch. If NULL, works just like 519 GetIcon(). 520 \param icon Reference to a pre-allocated \c BBitmap of proper size and 521 colorspace into which the icon is copied. 522 \param icon_size Value that specifies which icon to return. Currently 523 \c B_LARGE_ICON and \c B_MINI_ICON are supported. 524 \return 525 - \c B_OK: Success 526 - \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type 527 - "error code": Failure 528 529 */ 530 status_t 531 DatabaseLocation::GetIconForType(const char* type, const char* fileType, 532 BBitmap& _icon, icon_size which) 533 { 534 if (type == NULL) 535 return B_BAD_VALUE; 536 537 // open the node for the given type 538 BNode node; 539 ssize_t err = OpenType(type, node); 540 if (err < B_OK) 541 return (status_t)err; 542 543 // construct our attribute name 544 BString vectorIconAttrName; 545 BString smallIconAttrName; 546 BString largeIconAttrName; 547 548 if (fileType) { 549 BString lowerCaseFileType(fileType); 550 lowerCaseFileType.ToLower(); 551 552 vectorIconAttrName << kIconAttrPrefix << lowerCaseFileType; 553 smallIconAttrName << kMiniIconAttrPrefix << lowerCaseFileType; 554 largeIconAttrName << kLargeIconAttrPrefix << lowerCaseFileType; 555 } else { 556 vectorIconAttrName = kIconAttr; 557 smallIconAttrName = kMiniIconAttr; 558 largeIconAttrName = kLargeIconAttr; 559 } 560 561 return BIconUtils::GetIcon(&node, vectorIconAttrName, smallIconAttrName, 562 largeIconAttrName, which, &_icon); 563 564 // ssize_t err = type && icon ? B_OK : B_BAD_VALUE; 565 // 566 // // Figure out what kind of data we *should* find 567 // uint32 attrType = 0; 568 // ssize_t attrSize = 0; 569 // BRect bounds; 570 // 571 // if (!err) { 572 // switch (which) { 573 // case B_MINI_ICON: 574 // bounds.Set(0, 0, 15, 15); 575 // attrType = kMiniIconType; 576 // attrSize = 16 * 16; 577 // break; 578 // case B_LARGE_ICON: 579 // bounds.Set(0, 0, 31, 31); 580 // attrType = kLargeIconType; 581 // attrSize = 32 * 32; 582 // break; 583 // default: 584 // err = B_BAD_VALUE; 585 // break; 586 // } 587 // } 588 // // Construct our attribute name 589 // std::string attr; 590 // if (fileType) { 591 // attr = (which == B_MINI_ICON 592 // ? kMiniIconAttrPrefix 593 // : kLargeIconAttrPrefix) 594 // + BPrivate::Storage::to_lower(fileType); 595 // } else { 596 // attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr; 597 // } 598 // // Check the icon and attribute to see if they match 599 // if (!err) { 600 // err = (icon->InitCheck() == B_OK 601 // && icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE; 602 // } 603 // 604 // BNode node; 605 // if (!err) 606 // err = open_type(type, &node); 607 // 608 // attr_info info; 609 // if (!err) 610 // err = node.GetAttrInfo(attr.c_str(), &info); 611 // 612 // if (!err) 613 // err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE; 614 // // read the attribute 615 // if (!err) { 616 // bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 617 // char *buffer = NULL; 618 // if (otherColorSpace) { 619 // // other color space than stored in attribute 620 // buffer = new(std::nothrow) char[attrSize]; 621 // if (!buffer) 622 // err = B_NO_MEMORY; 623 // if (!err) 624 // err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize); 625 // } else { 626 // // same color space, just read direct 627 // err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize); 628 // } 629 // if (err >= 0) 630 // err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR; 631 // if (otherColorSpace) { 632 // if (!err) { 633 // err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, 634 // 0, B_CMAP8); 635 // } 636 // delete[] buffer; 637 // } 638 // } 639 // 640 // return err; 641 } 642 643 644 /*! \brief Fetches the vector icon used by an application of this type for files 645 of the given type. 646 647 The type of the \c BMimeType object is not required to actually be a subtype 648 of \c "application/"; that is the intended use however, and calling 649 \c GetIconForType() on a non-application type will likely return 650 \c B_ENTRY_NOT_FOUND. 651 652 The icon data is allocated and returned in \a _data. 653 654 \param type The MIME type 655 \param fileType Reference to a pre-allocated string containing the MIME type 656 whose custom icon you wish to fetch. If NULL, works just like GetIcon(). 657 \param _data Reference via which the icon data is returned on success. 658 \param _size Reference via which the size of the icon data is returned. 659 \return 660 - \c B_OK: Success 661 - \c B_ENTRY_NOT_FOUND: No vector icon exists for the given type 662 - "error code": Failure 663 */ 664 status_t 665 DatabaseLocation::GetIconForType(const char* type, const char* fileType, 666 uint8*& _data, size_t& _size) 667 { 668 if (type == NULL) 669 return B_BAD_VALUE; 670 671 // open the node for the given type 672 BNode node; 673 ssize_t err = OpenType(type, node); 674 if (err < B_OK) 675 return (status_t)err; 676 677 // construct our attribute name 678 BString iconAttrName; 679 680 if (fileType) 681 iconAttrName << kIconAttrPrefix << BString(fileType).ToLower(); 682 else 683 iconAttrName = kIconAttr; 684 685 // get info about attribute for that name 686 attr_info info; 687 if (!err) 688 err = node.GetAttrInfo(iconAttrName, &info); 689 690 // validate attribute type 691 if (!err) 692 err = (info.type == B_VECTOR_ICON_TYPE) ? B_OK : B_BAD_VALUE; 693 694 // allocate a buffer and read the attribute data into it 695 if (!err) { 696 uint8* buffer = new(std::nothrow) uint8[info.size]; 697 if (!buffer) 698 err = B_NO_MEMORY; 699 if (!err) { 700 err = node.ReadAttr(iconAttrName, B_VECTOR_ICON_TYPE, 0, buffer, 701 info.size); 702 } 703 704 if (err >= 0) 705 err = (err == info.size) ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR; 706 707 if (!err) { 708 // success, set data pointer and size 709 _data = buffer; 710 _size = info.size; 711 } else { 712 delete[] buffer; 713 } 714 } 715 716 return err; 717 } 718 719 720 /*! \brief Fetches signature of the MIME type's preferred application for the 721 given action. 722 723 The string pointed to by \c signature must be long enough to 724 hold the short description; a length of \c B_MIME_TYPE_LENGTH is 725 recommended. 726 727 Currently, the only supported app verb is \c B_OPEN. 728 729 \param type The MIME type of interest 730 \param description Pointer to a pre-allocated string into which the 731 preferred application's signature is copied. If the function fails, 732 the contents of the string are undefined. 733 \param verb \c The action of interest 734 735 \return 736 - \c B_OK: Success 737 - \c B_ENTRY_NOT_FOUND: No such preferred application exists 738 - "error code": Failure 739 */ 740 status_t 741 DatabaseLocation::GetPreferredApp(const char* type, char* signature, 742 app_verb verb) 743 { 744 // Since B_OPEN is the currently the only app_verb, it is essentially 745 // ignored 746 ssize_t err = ReadAttribute(type, kPreferredAppAttr, signature, 747 B_MIME_TYPE_LENGTH, kPreferredAppType); 748 return err >= 0 ? B_OK : err ; 749 } 750 751 752 /*! \brief Fetches the sniffer rule for the given MIME type. 753 \param type The MIME type of interest 754 \param _result Pointer to a pre-allocated BString into which the type's 755 sniffer rule is copied. 756 \return 757 - \c B_OK: Success 758 - \c B_ENTRY_NOT_FOUND: No such preferred application exists 759 - "error code": Failure 760 */ 761 status_t 762 DatabaseLocation::GetSnifferRule(const char* type, BString& _result) 763 { 764 return ReadStringAttribute(type, kSnifferRuleAttr, _result); 765 } 766 767 768 status_t 769 DatabaseLocation::GetSupportedTypes(const char* type, BMessage& _types) 770 { 771 status_t err = ReadMessageAttribute(type, kSupportedTypesAttr, _types); 772 if (err == B_ENTRY_NOT_FOUND) { 773 // return an empty message 774 _types.MakeEmpty(); 775 err = B_OK; 776 } 777 if (err == B_OK) { 778 _types.what = 0; 779 err = _types.AddString("type", type); 780 } 781 return err; 782 } 783 784 785 //! Checks if the given MIME type is present in the database 786 bool 787 DatabaseLocation::IsInstalled(const char* type) 788 { 789 BNode node; 790 return OpenType(type, node) == B_OK; 791 } 792 793 794 BString 795 DatabaseLocation::_TypeToFilename(const char* type, int32 index) const 796 { 797 BString path = fDirectories.StringAt(index); 798 return path << '/' << BString(type).ToLower(); 799 } 800 801 802 status_t 803 DatabaseLocation::_OpenType(const char* type, BNode& _node, int32& _index) const 804 { 805 int32 count = fDirectories.CountStrings(); 806 for (int32 i = 0; i < count; i++) { 807 status_t error = _node.SetTo(_TypeToFilename(type, i)); 808 attr_info attrInfo; 809 if (error == B_OK && _node.GetAttrInfo(kTypeAttr, &attrInfo) == B_OK) { 810 _index = i; 811 return B_OK; 812 } 813 } 814 815 return B_ENTRY_NOT_FOUND; 816 } 817 818 819 status_t 820 DatabaseLocation::_CreateTypeNode(const char* type, BNode& _node) const 821 { 822 const char* slash = strchr(type, '/'); 823 BString superTypeName; 824 if (slash != NULL) 825 superTypeName.SetTo(type, slash - type); 826 else 827 superTypeName = type; 828 superTypeName.ToLower(); 829 830 // open/create the directory for the supertype 831 BDirectory parent(WritableDirectory()); 832 status_t error = parent.InitCheck(); 833 if (error != B_OK) 834 return error; 835 836 BDirectory superTypeDirectory; 837 if (BEntry(&parent, superTypeName).Exists()) 838 error = superTypeDirectory.SetTo(&parent, superTypeName); 839 else 840 error = parent.CreateDirectory(superTypeName, &superTypeDirectory); 841 if (error != B_OK) 842 return error; 843 844 // create the subtype 845 BFile subTypeFile; 846 if (slash != NULL) { 847 error = superTypeDirectory.CreateFile(BString(slash + 1).ToLower(), 848 &subTypeFile); 849 if (error != B_OK) 850 return error; 851 } 852 853 // assign the result 854 if (slash != NULL) 855 _node = subTypeFile; 856 else 857 _node = superTypeDirectory; 858 return _node.InitCheck(); 859 } 860 861 862 status_t 863 DatabaseLocation::_CopyTypeNode(BNode& source, const char* type, BNode& _target) 864 const 865 { 866 status_t error = _CreateTypeNode(type, _target); 867 if (error != B_OK) 868 return error; 869 870 // copy the attributes 871 MemoryDeleter bufferDeleter; 872 size_t bufferSize = 0; 873 874 source.RewindAttrs(); 875 char attribute[B_ATTR_NAME_LENGTH]; 876 while (source.GetNextAttrName(attribute) == B_OK) { 877 attr_info info; 878 error = source.GetAttrInfo(attribute, &info); 879 if (error != B_OK) { 880 syslog(LOG_ERR, "Failed to get info for attribute \"%s\" of MIME " 881 "type \"%s\": %s", attribute, type, strerror(error)); 882 continue; 883 } 884 885 // resize our buffer, if necessary 886 if (info.size > (off_t)bufferSize) { 887 bufferDeleter.SetTo(malloc(info.size)); 888 if (bufferDeleter.Get() == NULL) 889 return B_NO_MEMORY; 890 bufferSize = info.size; 891 } 892 893 ssize_t bytesRead = source.ReadAttr(attribute, info.type, 0, 894 bufferDeleter.Get(), info.size); 895 if (bytesRead != info.size) { 896 syslog(LOG_ERR, "Failed to read attribute \"%s\" of MIME " 897 "type \"%s\": %s", attribute, type, 898 bytesRead < 0 ? strerror(bytesRead) : "short read"); 899 continue; 900 } 901 902 ssize_t bytesWritten = _target.WriteAttr(attribute, info.type, 0, 903 bufferDeleter.Get(), info.size); 904 if (bytesWritten < 0) { 905 syslog(LOG_ERR, "Failed to write attribute \"%s\" of MIME " 906 "type \"%s\": %s", attribute, type, 907 bytesWritten < 0 ? strerror(bytesWritten) : "short write"); 908 continue; 909 } 910 } 911 912 return B_OK; 913 } 914 915 916 } // namespace Mime 917 } // namespace Storage 918 } // namespace BPrivate 919