1 /* 2 * Copyright 2002-2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, bonefish@users.sf.net 7 */ 8 9 10 #include <new> 11 #include <set> 12 #include <string> 13 14 #include <AppFileInfo.h> 15 #include <Bitmap.h> 16 #include <File.h> 17 #include <fs_attr.h> 18 #include <IconUtils.h> 19 #include <MimeType.h> 20 #include <RegistrarDefs.h> 21 #include <Resources.h> 22 #include <Roster.h> 23 #include <String.h> 24 25 using namespace std; 26 27 // attributes 28 static const char *kTypeAttribute = "BEOS:TYPE"; 29 static const char *kSignatureAttribute = "BEOS:APP_SIG"; 30 static const char *kAppFlagsAttribute = "BEOS:APP_FLAGS"; 31 static const char *kSupportedTypesAttribute = "BEOS:FILE_TYPES"; 32 static const char *kVersionInfoAttribute = "BEOS:APP_VERSION"; 33 static const char *kMiniIconAttribute = "BEOS:M:"; 34 static const char *kLargeIconAttribute = "BEOS:L:"; 35 static const char *kIconAttribute = "BEOS:"; 36 static const char *kStandardIconType = "STD_ICON"; 37 static const char *kIconType = "ICON"; 38 39 // resource IDs 40 static const int32 kTypeResourceID = 2; 41 static const int32 kSignatureResourceID = 1; 42 static const int32 kAppFlagsResourceID = 1; 43 static const int32 kSupportedTypesResourceID = 1; 44 static const int32 kMiniIconResourceID = 101; 45 static const int32 kLargeIconResourceID = 101; 46 static const int32 kIconResourceID = 101; 47 static const int32 kVersionInfoResourceID = 1; 48 static const int32 kMiniIconForTypeResourceID = 0; 49 static const int32 kLargeIconForTypeResourceID = 0; 50 static const int32 kIconForTypeResourceID = 0; 51 52 // type codes 53 enum { 54 B_APP_FLAGS_TYPE = 'APPF', 55 B_VERSION_INFO_TYPE = 'APPV', 56 }; 57 58 // R5 also exports these (Tracker is using them): 59 // (maybe we better want to drop them silently and declare 60 // the above in a public Haiku header - and use that one in 61 // Tracker when compiled for Haiku) 62 extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE; 63 const uint32 MINI_ICON_TYPE = 'MICN'; 64 const uint32 LARGE_ICON_TYPE = 'ICON'; 65 66 // debugging 67 //#define DBG(x) x 68 #define DBG(x) 69 #define OUT printf 70 71 // constructor 72 /*! \brief Creates an uninitialized BAppFileInfo object. 73 */ 74 BAppFileInfo::BAppFileInfo() 75 : fResources(NULL), 76 fWhere(B_USE_BOTH_LOCATIONS) 77 { 78 } 79 80 // constructor 81 /*! \brief Creates an BAppFileInfo object and initializes it to the supplied 82 file. 83 84 The caller retains ownership of the supplied BFile object. It must not 85 be deleted during the life time of the BAppFileInfo. It is not deleted 86 when the BAppFileInfo is destroyed. 87 88 \param file The file the object shall be initialized to. 89 */ 90 BAppFileInfo::BAppFileInfo(BFile *file) 91 : fResources(NULL), 92 fWhere(B_USE_BOTH_LOCATIONS) 93 { 94 SetTo(file); 95 } 96 97 // destructor 98 /*! \brief Frees all resources associated with this object. 99 100 The BFile the object is set to is not deleted. 101 */ 102 BAppFileInfo::~BAppFileInfo() 103 { 104 if (fResources) 105 delete fResources; 106 } 107 108 // SetTo 109 /*! \brief Initializes the BAppFileInfo to the supplied file. 110 111 The caller retains ownership of the supplied BFile object. It must not 112 be deleted during the life time of the BAppFileInfo. It is not deleted 113 when the BAppFileInfo is destroyed. 114 115 \param file The file the object shall be initialized to. 116 117 \return 118 - \c B_OK: Everything went fine. 119 - \c B_BAD_VALUE: \c NULL \a file or \a file is not properly initialized. 120 */ 121 status_t 122 BAppFileInfo::SetTo(BFile *file) 123 { 124 // unset the old file 125 BNodeInfo::SetTo(NULL); 126 if (fResources) { 127 delete fResources; 128 fResources = NULL; 129 } 130 131 // check param 132 status_t error = (file && file->InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 133 134 info_location where = B_USE_BOTH_LOCATIONS; 135 136 // create resources 137 if (error == B_OK) { 138 fResources = new(nothrow) BResources(); 139 if (fResources) { 140 error = fResources->SetTo(file); 141 if (error != B_OK) { 142 // no resources - this is no critical error, we'll just use 143 // attributes only, then 144 where = B_USE_ATTRIBUTES; 145 error = B_OK; 146 } 147 } else 148 error = B_NO_MEMORY; 149 } 150 151 // set node info 152 if (error == B_OK) 153 error = BNodeInfo::SetTo(file); 154 155 if (error != B_OK || (where & B_USE_RESOURCES) == 0) { 156 delete fResources; 157 fResources = NULL; 158 } 159 160 // clean up on error 161 if (error != B_OK) { 162 if (InitCheck() == B_OK) 163 BNodeInfo::SetTo(NULL); 164 } 165 166 // set data location 167 if (error == B_OK) 168 SetInfoLocation(where); 169 170 // set error 171 fCStatus = error; 172 return error; 173 } 174 175 // GetType 176 /*! \brief Gets the file's MIME type. 177 178 \param type A pointer to a pre-allocated character buffer of size 179 \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the 180 file shall be written. 181 \return 182 - \c B_OK: Everything went fine. 183 - \c B_NO_INIT: The object is not properly initialized. 184 - \c B_BAD_VALUE: \c NULL \a type or the type string stored in the 185 attribute/resources is longer than \c B_MIME_TYPE_LENGTH. 186 - \c B_BAD_TYPE: The attribute/resources the type string is stored in have 187 the wrong type. 188 - \c B_ENTRY_NOT_FOUND: No type is set on the file. 189 - other error codes 190 */ 191 status_t 192 BAppFileInfo::GetType(char *type) const 193 { 194 // check param and initialization 195 status_t error = (type ? B_OK : B_BAD_VALUE); 196 if (error == B_OK && InitCheck() != B_OK) 197 error = B_NO_INIT; 198 // read the data 199 size_t read = 0; 200 if (error == B_OK) { 201 error = _ReadData(kTypeAttribute, kTypeResourceID, B_MIME_STRING_TYPE, 202 type, B_MIME_TYPE_LENGTH, read); 203 } 204 // check the read data -- null terminate the string 205 if (error == B_OK && type[read - 1] != '\0') { 206 if (read == B_MIME_TYPE_LENGTH) 207 error = B_ERROR; 208 else 209 type[read] = '\0'; 210 } 211 return error; 212 } 213 214 // SetType 215 /*! \brief Sets the file's MIME type. 216 217 If \a type is \c NULL the file's MIME type is unset. 218 219 \param type The MIME type to be assigned to the file. Must not be longer 220 than \c B_MIME_TYPE_LENGTH (including the terminating null). 221 May be \c NULL. 222 \return 223 - \c B_OK: Everything went fine. 224 - \c B_NO_INIT: The object is not properly initialized. 225 - \c B_BAD_VALUE: \a type is longer than \c B_MIME_TYPE_LENGTH. 226 - other error codes 227 */ 228 status_t 229 BAppFileInfo::SetType(const char *type) 230 { 231 // check initialization 232 status_t error = B_OK; 233 if (error == B_OK && InitCheck() != B_OK) 234 error = B_NO_INIT; 235 if (error == B_OK) { 236 if (type) { 237 // check param 238 size_t typeLen = strlen(type); 239 if (error == B_OK && typeLen >= B_MIME_TYPE_LENGTH) 240 error = B_BAD_VALUE; 241 // write the data 242 if (error == B_OK) { 243 error = _WriteData(kTypeAttribute, kTypeResourceID, 244 B_MIME_STRING_TYPE, type, typeLen + 1); 245 } 246 } else 247 error = _RemoveData(kTypeAttribute, B_MIME_STRING_TYPE); 248 } 249 return error; 250 } 251 252 // GetSignature 253 /*! \brief Gets the file's application signature. 254 255 \param signature A pointer to a pre-allocated character buffer of size 256 \c B_MIME_TYPE_LENGTH or larger into which the application 257 signature of the file shall be written. 258 \return 259 - \c B_OK: Everything went fine. 260 - \c B_NO_INIT: The object is not properly initialized. 261 - \c B_BAD_VALUE: \c NULL \a signature or the signature stored in the 262 attribute/resources is longer than \c B_MIME_TYPE_LENGTH. 263 - \c B_BAD_TYPE: The attribute/resources the signature is stored in have 264 the wrong type. 265 - \c B_ENTRY_NOT_FOUND: No signature is set on the file. 266 - other error codes 267 */ 268 status_t 269 BAppFileInfo::GetSignature(char *signature) const 270 { 271 // check param and initialization 272 status_t error = (signature ? B_OK : B_BAD_VALUE); 273 if (error == B_OK && InitCheck() != B_OK) 274 error = B_NO_INIT; 275 // read the data 276 size_t read = 0; 277 if (error == B_OK) { 278 error = _ReadData(kSignatureAttribute, kSignatureResourceID, 279 B_MIME_STRING_TYPE, signature, B_MIME_TYPE_LENGTH, 280 read); 281 } 282 // check the read data -- null terminate the string 283 if (error == B_OK && signature[read - 1] != '\0') { 284 if (read == B_MIME_TYPE_LENGTH) 285 error = B_ERROR; 286 else 287 signature[read] = '\0'; 288 } 289 return error; 290 } 291 292 // SetSignature 293 /*! \brief Sets the file's application signature. 294 295 If \a signature is \c NULL the file's application signature is unset. 296 297 \param signature The application signature to be assigned to the file. 298 Must not be longer than \c B_MIME_TYPE_LENGTH (including the 299 terminating null). May be \c NULL. 300 \return 301 - \c B_OK: Everything went fine. 302 - \c B_NO_INIT: The object is not properly initialized. 303 - \c B_BAD_VALUE: \a signature is longer than \c B_MIME_TYPE_LENGTH. 304 - other error codes 305 */ 306 status_t 307 BAppFileInfo::SetSignature(const char *signature) 308 { 309 // check initialization 310 status_t error = B_OK; 311 if (error == B_OK && InitCheck() != B_OK) 312 error = B_NO_INIT; 313 if (error == B_OK) { 314 if (signature) { 315 // check param 316 size_t signatureLen = strlen(signature); 317 if (error == B_OK && signatureLen >= B_MIME_TYPE_LENGTH) 318 error = B_BAD_VALUE; 319 // write the data 320 if (error == B_OK) { 321 error = _WriteData(kSignatureAttribute, kSignatureResourceID, 322 B_MIME_STRING_TYPE, signature, 323 signatureLen + 1); 324 } 325 } else 326 error = _RemoveData(kSignatureAttribute, B_MIME_STRING_TYPE); 327 } 328 return error; 329 } 330 331 // GetAppFlags 332 /*! \brief Gets the file's application flags. 333 334 \param flags A pointer to a pre-allocated uint32 into which the application 335 flags of the file shall be written. 336 \return 337 - \c B_OK: Everything went fine. 338 - \c B_NO_INIT: The object is not properly initialized. 339 - \c B_BAD_VALUE: \c NULL \a flags. 340 - \c B_BAD_TYPE: The attribute/resources the flags are stored in have 341 the wrong type. 342 - \c B_ENTRY_NOT_FOUND: No application flags are set on the file. 343 - other error codes 344 */ 345 status_t 346 BAppFileInfo::GetAppFlags(uint32 *flags) const 347 { 348 // check param and initialization 349 status_t error = (flags ? B_OK : B_BAD_VALUE); 350 if (error == B_OK && InitCheck() != B_OK) 351 error = B_NO_INIT; 352 // read the data 353 size_t read = 0; 354 if (error == B_OK) { 355 error = _ReadData(kAppFlagsAttribute, kAppFlagsResourceID, 356 B_APP_FLAGS_TYPE, flags, sizeof(uint32), 357 read); 358 } 359 // check the read data 360 if (error == B_OK && read != sizeof(uint32)) 361 error = B_ERROR; 362 return error; 363 } 364 365 // SetAppFlags 366 /*! \brief Sets the file's application flags. 367 \param flags The application flags to be assigned to the file. 368 \return 369 - \c B_OK: Everything went fine. 370 - \c B_NO_INIT: The object is not properly initialized. 371 - other error codes 372 */ 373 status_t 374 BAppFileInfo::SetAppFlags(uint32 flags) 375 { 376 // check initialization 377 status_t error = B_OK; 378 if (error == B_OK && InitCheck() != B_OK) 379 error = B_NO_INIT; 380 if (error == B_OK) { 381 // write the data 382 if (error == B_OK) { 383 error = _WriteData(kAppFlagsAttribute, kAppFlagsResourceID, 384 B_APP_FLAGS_TYPE, &flags, sizeof(uint32)); 385 } 386 } 387 return error; 388 } 389 390 // GetSupportedTypes 391 /*! \brief Gets the MIME types supported by the application. 392 393 The supported MIME types are added to a field "types" of type 394 \c B_STRING_TYPE in \a types. 395 396 \param types A pointer to a pre-allocated BMessage into which the 397 MIME types supported by the appplication shall be written. 398 \return 399 - \c B_OK: Everything went fine. 400 - \c B_NO_INIT: The object is not properly initialized. 401 - \c B_BAD_VALUE: \c NULL \a types. 402 - \c B_BAD_TYPE: The attribute/resources the supported types are stored in 403 have the wrong type. 404 - \c B_ENTRY_NOT_FOUND: No supported types are set on the file. 405 - other error codes 406 */ 407 status_t 408 BAppFileInfo::GetSupportedTypes(BMessage *types) const 409 { 410 // check param and initialization 411 status_t error = (types ? B_OK : B_BAD_VALUE); 412 if (error == B_OK && InitCheck() != B_OK) 413 error = B_NO_INIT; 414 // read the data 415 size_t read = 0; 416 void *buffer = NULL; 417 if (error == B_OK) { 418 error = _ReadData(kSupportedTypesAttribute, kSupportedTypesResourceID, 419 B_MESSAGE_TYPE, NULL, 0, read, &buffer); 420 } 421 // unflatten the buffer 422 if (error == B_OK) 423 error = types->Unflatten((const char*)buffer); 424 // clean up 425 if (buffer) 426 free(buffer); 427 return error; 428 } 429 430 // SetSupportedTypes 431 /*! \brief Sets the MIME types supported by the application. 432 433 If \a types is \c NULL the application's supported types are unset. 434 435 The supported MIME types must be stored in a field "types" of type 436 \c B_STRING_TYPE in \a types. 437 438 The method informs the registrar about this news. 439 For each supported type the result of BMimeType::GetSupportingApps() will 440 afterwards include the signature of this application. That is, the 441 application file needs to have a signature set. 442 443 \a syncAll specifies whether the not longer supported types shall be 444 updated as well, i.e. whether this application shall be remove from the 445 lists of supporting applications. 446 447 \param types The supported types to be assigned to the file. 448 May be \c NULL. 449 \param syncAll \c true to also synchronize the not longer supported 450 types, \c false otherwise. 451 \return 452 - \c B_OK: Everything went fine. 453 - \c B_NO_INIT: The object is not properly initialized. 454 - other error codes 455 */ 456 status_t 457 BAppFileInfo::SetSupportedTypes(const BMessage *types, bool syncAll) 458 { 459 // check initialization 460 status_t error = B_OK; 461 if (error == B_OK && InitCheck() != B_OK) 462 error = B_NO_INIT; 463 BMimeType mimeType; 464 if (error == B_OK) 465 error = GetMetaMime(&mimeType); 466 if (error == B_OK || error == B_ENTRY_NOT_FOUND) { 467 error = B_OK; 468 if (types) { 469 // check param -- supported types must be valid 470 const char *type; 471 for (int32 i = 0; 472 error == B_OK && types->FindString("types", i, &type) == B_OK; 473 i++) { 474 if (!BMimeType::IsValid(type)) 475 error = B_BAD_VALUE; 476 } 477 // get flattened size 478 ssize_t size = 0; 479 if (error == B_OK) { 480 size = types->FlattenedSize(); 481 if (size < 0) 482 error = size; 483 } 484 // allocate a buffer for the flattened data 485 char *buffer = NULL; 486 if (error == B_OK) { 487 buffer = new(nothrow) char[size]; 488 if (!buffer) 489 error = B_NO_MEMORY; 490 } 491 // flatten the message 492 if (error == B_OK) 493 error = types->Flatten(buffer, size); 494 // write the data 495 if (error == B_OK) { 496 error = _WriteData(kSupportedTypesAttribute, 497 kSupportedTypesResourceID, B_MESSAGE_TYPE, 498 buffer, size); 499 } 500 // clean up 501 if (buffer) 502 delete[] buffer; 503 } else 504 error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE); 505 // update the MIME database, if the app signature is installed 506 if (error == B_OK && mimeType.IsInstalled()) 507 error = mimeType.SetSupportedTypes(types, syncAll); 508 } 509 return error; 510 } 511 512 // SetSupportedTypes 513 /*! \brief Sets the MIME types supported by the application. 514 515 This method is a short-hand for SetSupportedTypes(types, false). 516 \see SetSupportedType(const BMessage*, bool) for detailed information. 517 518 \param types The supported types to be assigned to the file. 519 May be \c NULL. 520 \return 521 - \c B_OK: Everything went fine. 522 - \c B_NO_INIT: The object is not properly initialized. 523 - other error codes 524 */ 525 status_t 526 BAppFileInfo::SetSupportedTypes(const BMessage *types) 527 { 528 return SetSupportedTypes(types, false); 529 } 530 531 // IsSupportedType 532 /*! \brief Returns whether the application supports the supplied MIME type. 533 534 If the application supports the wildcard type "application/octet-stream" 535 any this method returns \c true for any MIME type. 536 537 \param type The MIME type in question. 538 \return \c true, if \a type is a valid MIME type and it is supported by 539 the application, \c false otherwise. 540 */ 541 bool 542 BAppFileInfo::IsSupportedType(const char *type) const 543 { 544 status_t error = (type ? B_OK : B_BAD_VALUE); 545 // get the supported types 546 BMessage types; 547 if (error == B_OK) 548 error = GetSupportedTypes(&types); 549 // turn type into a BMimeType 550 BMimeType mimeType; 551 if (error == B_OK) 552 error = mimeType.SetTo(type); 553 // iterate through the supported types 554 bool found = false; 555 if (error == B_OK) { 556 const char *supportedType; 557 for (int32 i = 0; 558 !found && types.FindString("types", i, &supportedType) == B_OK; 559 i++) { 560 found = !strcmp(supportedType, "application/octet-stream") 561 || BMimeType(supportedType).Contains(&mimeType); 562 } 563 } 564 return found; 565 } 566 567 // Supports 568 /*! \brief Returns whether the application supports the supplied MIME type 569 explicitly. 570 571 Unlike IsSupportedType(), this method returns \c true, only if the type 572 is explicitly supported, regardless of whether it supports 573 "application/octet-stream". 574 575 \param type The MIME type in question. 576 \return \c true, if \a type is a valid MIME type and it is explicitly 577 supported by the application, \c false otherwise. 578 */ 579 bool 580 BAppFileInfo::Supports(BMimeType *type) const 581 { 582 status_t error = (type && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 583 // get the supported types 584 BMessage types; 585 if (error == B_OK) 586 error = GetSupportedTypes(&types); 587 // iterate through the supported types 588 bool found = false; 589 if (error == B_OK) { 590 const char *supportedType; 591 for (int32 i = 0; 592 !found && types.FindString("types", i, &supportedType) == B_OK; 593 i++) { 594 found = BMimeType(supportedType).Contains(type); 595 } 596 } 597 return found; 598 } 599 600 // GetIcon 601 /*! \brief Gets the file's icon. 602 \param icon A pointer to a pre-allocated BBitmap of the correct dimension 603 to store the requested icon (16x16 for the mini and 32x32 for the 604 large icon). 605 \param which Specifies the size of the icon to be retrieved: 606 \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon. 607 \return 608 - \c B_OK: Everything went fine. 609 - \c B_NO_INIT: The object is not properly initialized. 610 - \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a which or bitmap 611 dimensions (\a icon) and icon size (\a which) do not match. 612 - other error codes 613 */ 614 status_t 615 BAppFileInfo::GetIcon(BBitmap *icon, icon_size which) const 616 { 617 return GetIconForType(NULL, icon, which); 618 } 619 620 // GetIcon 621 /*! \brief Gets the file's icon. 622 \param data The pointer in which the flat icon data will be returned. 623 \param size The pointer in which the size of the data found will be returned. 624 \return 625 - \c B_OK: Everything went fine. 626 - \c B_NO_INIT: The object is not properly initialized. 627 - \c B_BAD_VALUE: \c NULL \a data or \c NULL size. 628 - other error codes 629 */ 630 status_t 631 BAppFileInfo::GetIcon(uint8** data, size_t* size) const 632 { 633 return GetIconForType(NULL, data, size); 634 } 635 636 // SetIcon 637 /*! \brief Sets the file's icon. 638 639 If \a icon is \c NULL the file's icon is unset. 640 641 \param icon A pointer to the BBitmap containing the icon to be set. 642 May be \c NULL. 643 \param which Specifies the size of the icon to be set: \c B_MINI_ICON 644 for the mini and \c B_LARGE_ICON for the large icon. 645 \return 646 - \c B_OK: Everything went fine. 647 - \c B_NO_INIT: The object is not properly initialized. 648 - \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon) 649 and icon size (\a which) do not match. 650 - other error codes 651 */ 652 status_t 653 BAppFileInfo::SetIcon(const BBitmap *icon, icon_size which) 654 { 655 return SetIconForType(NULL, icon, which); 656 } 657 658 // SetIcon 659 /*! \brief Sets the file's icon. 660 661 If \a icon is \c NULL the file's icon is unset. 662 663 \param data A pointer to the data buffer containing the vector icon 664 to be set. May be \c NULL. 665 \param size Specifies the size of buffer pointed to by \a data. 666 \return 667 - \c B_OK: Everything went fine. 668 - \c B_NO_INIT: The object is not properly initialized. 669 - \c B_BAD_VALUE: \c NULL data. 670 - other error codes 671 */ 672 status_t 673 BAppFileInfo::SetIcon(const uint8* data, size_t size) 674 { 675 return SetIconForType(NULL, data, size); 676 } 677 678 // GetVersionInfo 679 /*! \brief Gets the file's version info. 680 \param info A pointer to a pre-allocated version_info structure into which 681 the version info should be written. 682 \param kind Specifies the kind of the version info to be retrieved: 683 \c B_APP_VERSION_KIND for the application's version info and 684 \c B_SYSTEM_VERSION_KIND for the suite's info the application 685 belongs to. 686 \return 687 - \c B_OK: Everything went fine. 688 - \c B_NO_INIT: The object is not properly initialized. 689 - \c B_BAD_VALUE: \c NULL \a info. 690 - other error codes 691 */ 692 status_t 693 BAppFileInfo::GetVersionInfo(version_info *info, version_kind kind) const 694 { 695 // check params and initialization 696 if (!info) 697 return B_BAD_VALUE; 698 699 int32 index = 0; 700 switch (kind) { 701 case B_APP_VERSION_KIND: 702 index = 0; 703 break; 704 case B_SYSTEM_VERSION_KIND: 705 index = 1; 706 break; 707 default: 708 return B_BAD_VALUE; 709 } 710 711 if (InitCheck() != B_OK) 712 return B_NO_INIT; 713 714 // read the data 715 size_t read = 0; 716 version_info infos[2]; 717 status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 718 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read); 719 if (error != B_OK) 720 return error; 721 722 // check the read data 723 if (read == sizeof(version_info)) { 724 // only the app version info is there -- return a cleared system info 725 if (index == 0) 726 *info = infos[index]; 727 else if (index == 1) 728 memset(info, 0, sizeof(version_info)); 729 } else if (read == 2 * sizeof(version_info)) { 730 *info = infos[index]; 731 } else 732 return B_ERROR; 733 734 // return result 735 return B_OK; 736 } 737 738 // SetVersionInfo 739 /*! \brief Sets the file's version info. 740 741 If \a info is \c NULL the file's version info is unset. 742 743 \param info The version info to be set. May be \c NULL. 744 \param kind Specifies kind of version info to be set: 745 \c B_APP_VERSION_KIND for the application's version info and 746 \c B_SYSTEM_VERSION_KIND for the suite's info the application 747 belongs to. 748 \return 749 - \c B_OK: Everything went fine. 750 - \c B_NO_INIT: The object is not properly initialized. 751 - other error codes 752 */ 753 status_t 754 BAppFileInfo::SetVersionInfo(const version_info *info, version_kind kind) 755 { 756 // check initialization 757 status_t error = B_OK; 758 if (error == B_OK && InitCheck() != B_OK) 759 error = B_NO_INIT; 760 if (error == B_OK) { 761 if (info) { 762 // check param 763 int32 index = 0; 764 if (error == B_OK) { 765 switch (kind) { 766 case B_APP_VERSION_KIND: 767 index = 0; 768 break; 769 case B_SYSTEM_VERSION_KIND: 770 index = 1; 771 break; 772 default: 773 error = B_BAD_VALUE; 774 break; 775 } 776 } 777 // read both infos 778 version_info infos[2]; 779 if (error == B_OK) { 780 size_t read; 781 if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 782 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), 783 read) == B_OK) { 784 // clear the part that hasn't been read 785 if (read < sizeof(infos)) 786 memset((char*)infos + read, 0, sizeof(infos) - read); 787 } else { 788 // failed to read -- clear 789 memset(infos, 0, sizeof(infos)); 790 } 791 } 792 infos[index] = *info; 793 // write the data 794 if (error == B_OK) { 795 error = _WriteData(kVersionInfoAttribute, 796 kVersionInfoResourceID, 797 B_VERSION_INFO_TYPE, infos, 798 2 * sizeof(version_info)); 799 } 800 } else 801 error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE); 802 } 803 return error; 804 } 805 806 // GetIconForType 807 /*! \brief Gets the icon the application provides for a given MIME type. 808 809 If \a type is \c NULL, the application's icon is retrieved. 810 811 \param type The MIME type in question. May be \c NULL. 812 \param icon A pointer to a pre-allocated BBitmap of the correct dimension 813 to store the requested icon (16x16 for the mini and 32x32 for the 814 large icon). 815 \param which Specifies the size of the icon to be retrieved: 816 \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon. 817 \return 818 - \c B_OK: Everything went fine. 819 - \c B_NO_INIT: The object is not properly initialized. 820 - \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size 821 \a which or bitmap dimensions (\a icon) and icon size (\a which) do 822 not match. 823 - other error codes 824 */ 825 status_t 826 BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, 827 icon_size which) const 828 { 829 if (InitCheck() != B_OK) 830 return B_NO_INIT; 831 832 if (!icon || icon->InitCheck() != B_OK) 833 return B_BAD_VALUE; 834 835 // try vector icon first 836 BString vectorAttributeName(kIconAttribute); 837 838 // check type param 839 if (type) { 840 if (BMimeType::IsValid(type)) 841 vectorAttributeName += type; 842 else 843 return B_BAD_VALUE; 844 } else { 845 vectorAttributeName += kIconType; 846 } 847 const char* attribute = vectorAttributeName.String(); 848 849 size_t bytesRead; 850 void* allocatedBuffer; 851 status_t error = _ReadData(attribute, -1, B_RAW_TYPE, NULL, 0, 852 bytesRead, &allocatedBuffer); 853 if (error == B_OK) { 854 error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer, 855 bytesRead, icon); 856 free(allocatedBuffer); 857 return error; 858 } 859 860 // no vector icon if we got this far 861 862 error = B_OK; 863 // set some icon size related variables 864 BString attributeString; 865 BRect bounds; 866 uint32 attrType = 0; 867 size_t attrSize = 0; 868 switch (which) { 869 case B_MINI_ICON: 870 attributeString = kMiniIconAttribute; 871 bounds.Set(0, 0, 15, 15); 872 attrType = B_MINI_ICON_TYPE; 873 attrSize = 16 * 16; 874 break; 875 case B_LARGE_ICON: 876 attributeString = kLargeIconAttribute; 877 bounds.Set(0, 0, 31, 31); 878 attrType = B_LARGE_ICON_TYPE; 879 attrSize = 32 * 32; 880 break; 881 default: 882 return B_BAD_VALUE; 883 } 884 // check type param 885 if (type) { 886 if (BMimeType::IsValid(type)) 887 attributeString += type; 888 else 889 return B_BAD_VALUE; 890 } else 891 attributeString += kStandardIconType; 892 893 attribute = attributeString.String(); 894 895 // check parameter and initialization 896 if (icon->Bounds() != bounds) 897 return B_BAD_VALUE; 898 899 // read the data 900 if (error == B_OK) { 901 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 902 char *buffer = NULL; 903 size_t read; 904 if (otherColorSpace) { 905 // other color space than stored in attribute 906 buffer = new(nothrow) char[attrSize]; 907 if (!buffer) 908 error = B_NO_MEMORY; 909 if (error == B_OK) { 910 error = _ReadData(attribute, -1, attrType, buffer, attrSize, 911 read); 912 } 913 } else { 914 error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize, 915 read); 916 } 917 if (error == B_OK && read != attrSize) 918 error = B_ERROR; 919 if (otherColorSpace) { 920 // other color space than stored in attribute 921 if (error == B_OK) { 922 error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, 923 0, B_CMAP8); 924 } 925 delete[] buffer; 926 } 927 } 928 return error; 929 } 930 931 // GetIconForType 932 /*! \brief Gets the icon the application provides for a given MIME type. 933 934 If \a type is \c NULL, the application's icon is retrieved. 935 936 \param type The MIME type in question. May be \c NULL. 937 \param data A pointer in which the icon data will be returned. When you 938 are done with the data, you should use free() to deallocate it. 939 \param size A pointer in which the size of the retrieved data is returned. 940 \return 941 - \c B_OK: Everything went fine. 942 - \c B_NO_INIT: The object is not properly initialized. 943 - \c B_BAD_VALUE: \c NULL \a data and/or \a size. Or the supplied 944 \a type is not a valid MIME type. 945 - other error codes 946 */ 947 status_t 948 BAppFileInfo::GetIconForType(const char *type, uint8** data, 949 size_t* size) const 950 { 951 if (InitCheck() != B_OK) 952 return B_NO_INIT; 953 954 if (!data || !size) 955 return B_BAD_VALUE; 956 957 // get vector icon 958 BString attributeName(kIconAttribute); 959 960 // check type param 961 if (type) { 962 if (BMimeType::IsValid(type)) 963 attributeName += type; 964 else 965 return B_BAD_VALUE; 966 } else { 967 attributeName += kIconType; 968 } 969 970 void* allocatedBuffer = NULL; 971 status_t ret = _ReadData(attributeName.String(), -1, 972 B_RAW_TYPE, NULL, 0, *size, &allocatedBuffer); 973 974 if (ret < B_OK) 975 return ret; 976 977 *data = (uint8*)allocatedBuffer; 978 return B_OK; 979 } 980 981 // SetIconForType 982 /*! \brief Sets the icon the application provides for a given MIME type. 983 984 If \a type is \c NULL, the application's icon is set. 985 If \a icon is \c NULL the icon is unset. 986 987 If the file has a signature, then the icon is also set on the MIME type. 988 If the type for the signature has not been installed yet, it is installed 989 before. 990 991 \param type The MIME type in question. May be \c NULL. 992 \param icon A pointer to the BBitmap containing the icon to be set. 993 May be \c NULL. 994 \param which Specifies the size of the icon to be set: \c B_MINI_ICON 995 for the mini and \c B_LARGE_ICON for the large icon. 996 \return 997 - \c B_OK: Everything went fine. 998 - \c B_NO_INIT: The object is not properly initialized. 999 - \c B_BAD_VALUE: Either the icon size \a which is unkown, bitmap dimensions (\a icon) 1000 and icon size (\a which) do not match, or the provided \a type is 1001 not a valid MIME type. 1002 - other error codes 1003 */ 1004 status_t 1005 BAppFileInfo::SetIconForType(const char *type, const BBitmap *icon, 1006 icon_size which) 1007 { 1008 status_t error = B_OK; 1009 // set some icon size related variables 1010 BString attributeString; 1011 BRect bounds; 1012 uint32 attrType = 0; 1013 size_t attrSize = 0; 1014 int32 resourceID = 0; 1015 switch (which) { 1016 case B_MINI_ICON: 1017 attributeString = kMiniIconAttribute; 1018 bounds.Set(0, 0, 15, 15); 1019 attrType = B_MINI_ICON_TYPE; 1020 attrSize = 16 * 16; 1021 resourceID = (type ? kMiniIconForTypeResourceID 1022 : kMiniIconResourceID); 1023 break; 1024 case B_LARGE_ICON: 1025 attributeString = kLargeIconAttribute; 1026 bounds.Set(0, 0, 31, 31); 1027 attrType = B_LARGE_ICON_TYPE; 1028 attrSize = 32 * 32; 1029 resourceID = (type ? kLargeIconForTypeResourceID 1030 : kLargeIconResourceID); 1031 break; 1032 default: 1033 error = B_BAD_VALUE; 1034 break; 1035 } 1036 // check type param 1037 if (error == B_OK) { 1038 if (type) { 1039 if (BMimeType::IsValid(type)) 1040 attributeString += type; 1041 else 1042 error = B_BAD_VALUE; 1043 } else 1044 attributeString += kStandardIconType; 1045 } 1046 const char *attribute = attributeString.String(); 1047 // check parameter and initialization 1048 if (error == B_OK && icon 1049 && (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { 1050 error = B_BAD_VALUE; 1051 } 1052 if (error == B_OK && InitCheck() != B_OK) 1053 error = B_NO_INIT; 1054 // write/remove the attribute 1055 if (error == B_OK) { 1056 if (icon) { 1057 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 1058 if (otherColorSpace) { 1059 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8); 1060 error = bitmap.InitCheck(); 1061 if (error == B_OK) 1062 error = bitmap.ImportBits(icon); 1063 if (error == B_OK) { 1064 error = _WriteData(attribute, resourceID, attrType, 1065 bitmap.Bits(), attrSize, true); 1066 } 1067 } else { 1068 error = _WriteData(attribute, resourceID, attrType, 1069 icon->Bits(), attrSize, true); 1070 } 1071 } else // no icon given => remove 1072 error = _RemoveData(attribute, attrType); 1073 } 1074 // set the attribute on the MIME type, if the file has a signature 1075 BMimeType mimeType; 1076 if (error == B_OK && GetMetaMime(&mimeType) == B_OK) { 1077 if (!mimeType.IsInstalled()) 1078 error = mimeType.Install(); 1079 if (error == B_OK) 1080 error = mimeType.SetIconForType(type, icon, which); 1081 } 1082 return error; 1083 } 1084 1085 // SetIconForType 1086 /*! \brief Sets the icon the application provides for a given MIME type. 1087 1088 If \a type is \c NULL, the application's icon is set. 1089 If \a data is \c NULL the icon is unset. 1090 1091 If the file has a signature, then the icon is also set on the MIME type. 1092 If the type for the signature has not been installed yet, it is installed 1093 before. 1094 1095 \param type The MIME type in question. May be \c NULL. 1096 \param data A pointer to the data containing the icon to be set. 1097 May be \c NULL. 1098 \param size Specifies the size of buffer provided in \a data. 1099 \return 1100 - \c B_OK: Everything went fine. 1101 - \c B_NO_INIT: The object is not properly initialized. 1102 - \c B_BAD_VALUE: The provided \a type is not a valid MIME type. 1103 - other error codes 1104 */ 1105 status_t 1106 BAppFileInfo::SetIconForType(const char* type, const uint8* data, 1107 size_t size) 1108 { 1109 if (InitCheck() != B_OK) 1110 return B_NO_INIT; 1111 1112 // set some icon related variables 1113 BString attributeString = kIconAttribute; 1114 int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID; 1115 uint32 attrType = B_RAW_TYPE; 1116 1117 // check type param 1118 if (type) { 1119 if (BMimeType::IsValid(type)) 1120 attributeString += type; 1121 else 1122 return B_BAD_VALUE; 1123 } else 1124 attributeString += kIconType; 1125 1126 const char *attribute = attributeString.String(); 1127 1128 status_t error; 1129 // write/remove the attribute 1130 if (data) 1131 error = _WriteData(attribute, resourceID, attrType, data, size, true); 1132 else // no icon given => remove 1133 error = _RemoveData(attribute, attrType); 1134 1135 // set the attribute on the MIME type, if the file has a signature 1136 BMimeType mimeType; 1137 if (error == B_OK && GetMetaMime(&mimeType) == B_OK) { 1138 if (!mimeType.IsInstalled()) 1139 error = mimeType.Install(); 1140 if (error == B_OK) 1141 error = mimeType.SetIconForType(type, data, size); 1142 } 1143 return error; 1144 } 1145 1146 // SetInfoLocation 1147 /*! \brief Specifies the location where the meta data shall be stored. 1148 1149 The options for \a location are: 1150 - \c B_USE_ATTRIBUTES: Store the data in the attributes. 1151 - \c B_USE_RESOURCES: Store the data in the resources. 1152 - \c B_USE_BOTH_LOCATIONS: Store the data in attributes and resources. 1153 1154 \param location The location where the meta data shall be stored. 1155 */ 1156 void 1157 BAppFileInfo::SetInfoLocation(info_location location) 1158 { 1159 fWhere = location; 1160 } 1161 1162 // IsUsingAttributes 1163 /*! \brief Returns whether the object stores the meta data (also) in the 1164 file's attributes. 1165 \return \c true, if the meta data are (also) stored in the file's 1166 attributes, \c false otherwise. 1167 */ 1168 bool 1169 BAppFileInfo::IsUsingAttributes() const 1170 { 1171 return (fWhere & B_USE_ATTRIBUTES); 1172 } 1173 1174 // IsUsingResources 1175 /*! \brief Returns whether the object stores the meta data (also) in the 1176 file's resources. 1177 \return \c true, if the meta data are (also) stored in the file's 1178 resources, \c false otherwise. 1179 */ 1180 bool 1181 BAppFileInfo::IsUsingResources() const 1182 { 1183 return (fWhere & B_USE_RESOURCES); 1184 } 1185 1186 // FBC 1187 void BAppFileInfo::_ReservedAppFileInfo1() {} 1188 void BAppFileInfo::_ReservedAppFileInfo2() {} 1189 void BAppFileInfo::_ReservedAppFileInfo3() {} 1190 1191 // = 1192 /*! \brief Privatized assignment operator to prevent usage. 1193 */ 1194 BAppFileInfo & 1195 BAppFileInfo::operator=(const BAppFileInfo &) 1196 { 1197 return *this; 1198 } 1199 1200 // copy constructor 1201 /*! \brief Privatized copy constructor to prevent usage. 1202 */ 1203 BAppFileInfo::BAppFileInfo(const BAppFileInfo &) 1204 { 1205 } 1206 1207 // GetMetaMime 1208 /*! \brief Initializes a BMimeType to the file's signature. 1209 1210 The parameter \a meta is not checked. 1211 1212 \param meta A pointer to a pre-allocated BMimeType that shall be 1213 initialized to the file's signature. 1214 \return 1215 - \c B_OK: Everything went fine. 1216 - \c B_BAD_VALUE: \c NULL \a meta 1217 - \c B_ENTRY_NOT_FOUND: The file has not signature or the signature is 1218 ( not installed in the MIME database.) 1219 no valid MIME string. 1220 - other error codes 1221 */ 1222 status_t 1223 BAppFileInfo::GetMetaMime(BMimeType *meta) const 1224 { 1225 char signature[B_MIME_TYPE_LENGTH]; 1226 status_t error = GetSignature(signature); 1227 if (error == B_OK) 1228 error = meta->SetTo(signature); 1229 else if (error == B_BAD_VALUE) 1230 error = B_ENTRY_NOT_FOUND; 1231 if (error == B_OK && !meta->IsValid()) 1232 error = B_BAD_VALUE; 1233 return error; 1234 } 1235 1236 // _ReadData 1237 /*! \brief Reads data from an attribute or resource. 1238 1239 The data are read from the location specified by \a fWhere. 1240 1241 The object must be properly initialized. The parameters are NOT checked. 1242 1243 \param name The name of the attribute/resource to be read. 1244 \param id The resource ID of the resource to be read. Is ignored, when 1245 < 0. 1246 \param type The type of the attribute/resource to be read. 1247 \param buffer A pre-allocated buffer for the data to be read. 1248 \param bufferSize The size of the supplied buffer. 1249 \param bytesRead A reference parameter, set to the number of bytes 1250 actually read. 1251 \param allocatedBuffer If not \c NULL, the method allocates a buffer 1252 large enough too store the whole data and writes a pointer to it 1253 into this variable. If \c NULL, the supplied buffer is used. 1254 \return 1255 - \c B_OK: Everything went fine. 1256 - error code 1257 */ 1258 status_t 1259 BAppFileInfo::_ReadData(const char *name, int32 id, type_code type, 1260 void *buffer, size_t bufferSize, 1261 size_t &bytesRead, void **allocatedBuffer) const 1262 { 1263 status_t error = B_OK; 1264 1265 if (allocatedBuffer) 1266 buffer = NULL; 1267 1268 bool foundData = false; 1269 1270 if (IsUsingAttributes()) { 1271 // get an attribute info 1272 attr_info info; 1273 if (error == B_OK) 1274 error = fNode->GetAttrInfo(name, &info); 1275 1276 // check type and size, allocate a buffer, if required 1277 if (error == B_OK && info.type != type) 1278 error = B_BAD_VALUE; 1279 if (error == B_OK && allocatedBuffer) { 1280 buffer = malloc(info.size); 1281 if (!buffer) 1282 error = B_NO_MEMORY; 1283 bufferSize = info.size; 1284 } 1285 if (error == B_OK && bufferSize < info.size) 1286 error = B_BAD_VALUE; 1287 1288 // read the data 1289 if (error == B_OK) { 1290 ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size); 1291 if (read < 0) 1292 error = read; 1293 else if (read != info.size) 1294 error = B_ERROR; 1295 else 1296 bytesRead = read; 1297 } 1298 1299 foundData = (error == B_OK); 1300 1301 // free the allocated buffer on error 1302 if (!foundData && allocatedBuffer && buffer) { 1303 free(buffer); 1304 buffer = NULL; 1305 } 1306 } 1307 1308 if (!foundData && IsUsingResources()) { 1309 // get a resource info 1310 error = B_OK; 1311 int32 idFound; 1312 size_t sizeFound; 1313 if (error == B_OK) { 1314 if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1315 error = B_ENTRY_NOT_FOUND; 1316 } 1317 1318 // check id and size, allocate a buffer, if required 1319 if (error == B_OK && id >= 0 && idFound != id) 1320 error = B_ENTRY_NOT_FOUND; 1321 if (error == B_OK && allocatedBuffer) { 1322 buffer = malloc(sizeFound); 1323 if (!buffer) 1324 error = B_NO_MEMORY; 1325 bufferSize = sizeFound; 1326 } 1327 if (error == B_OK && bufferSize < sizeFound) 1328 error = B_BAD_VALUE; 1329 1330 // load resource 1331 const void *resourceData = NULL; 1332 if (error == B_OK) { 1333 resourceData = fResources->LoadResource(type, name, &bytesRead); 1334 if (resourceData && sizeFound == bytesRead) 1335 memcpy(buffer, resourceData, bytesRead); 1336 else 1337 error = B_ERROR; 1338 } 1339 } else if (!foundData) 1340 error = B_BAD_VALUE; 1341 1342 // return the allocated buffer, or free it on error 1343 if (allocatedBuffer) { 1344 if (error == B_OK) 1345 *allocatedBuffer = buffer; 1346 else 1347 free(buffer); 1348 } 1349 1350 return error; 1351 } 1352 1353 // _WriteData 1354 /*! \brief Writes data to an attribute or resource. 1355 1356 The data are written to the location(s) specified by \a fWhere. 1357 1358 The object must be properly initialized. The parameters are NOT checked. 1359 1360 \param name The name of the attribute/resource to be written. 1361 \param id The resource ID of the resource to be written. 1362 \param type The type of the attribute/resource to be written. 1363 \param buffer A buffer containing the data to be written. 1364 \param bufferSize The size of the supplied buffer. 1365 \param findID If set to \c true use the ID that is already assigned to the 1366 \a name / \a type pair or take the first unused ID >= \a id. 1367 If \c false, \a id is used. 1368 If \a id is already in use and . 1369 \return 1370 - \c B_OK: Everything went fine. 1371 - error code 1372 */ 1373 status_t 1374 BAppFileInfo::_WriteData(const char *name, int32 id, type_code type, 1375 const void *buffer, size_t bufferSize, bool findID) 1376 { 1377 status_t error = B_OK; 1378 // write to attribute 1379 if (IsUsingAttributes() && error == B_OK) { 1380 ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize); 1381 if (written < 0) 1382 error = written; 1383 else if (written != (ssize_t)bufferSize) 1384 error = B_ERROR; 1385 } 1386 // write to resource 1387 if (IsUsingResources() && error == B_OK) { 1388 if (findID) { 1389 // get the resource info 1390 int32 idFound; 1391 size_t sizeFound; 1392 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1393 id = idFound; 1394 else { 1395 // type-name pair doesn't exist yet -- find unused ID 1396 while (fResources->HasResource(type, id)) 1397 id++; 1398 } 1399 } 1400 error = fResources->AddResource(type, id, buffer, bufferSize, name); 1401 } 1402 return error; 1403 } 1404 1405 // _RemoveData 1406 /*! \brief Removes an attribute or resource. 1407 1408 The removal location is specified by \a fWhere. 1409 1410 The object must be properly initialized. The parameters are NOT checked. 1411 1412 \param name The name of the attribute/resource to be remove. 1413 \param type The type of the attribute/resource to be removed. 1414 \return 1415 - \c B_OK: Everything went fine. 1416 - error code 1417 */ 1418 status_t 1419 BAppFileInfo::_RemoveData(const char *name, type_code type) 1420 { 1421 status_t error = B_OK; 1422 // remove the attribute 1423 if (IsUsingAttributes() && error == B_OK) { 1424 error = fNode->RemoveAttr(name); 1425 // It's no error, if there has been no attribute. 1426 if (error == B_ENTRY_NOT_FOUND) 1427 error = B_OK; 1428 } 1429 // remove the resource 1430 if (IsUsingResources() && error == B_OK) { 1431 // get a resource info 1432 int32 idFound; 1433 size_t sizeFound; 1434 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1435 error = fResources->RemoveResource(type, idFound); 1436 } 1437 return error; 1438 } 1439 1440