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