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