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 || error == B_ENTRY_NOT_FOUND) { 449 error = B_OK; 450 if (types) { 451 // check param -- supported types must be valid 452 const char *type; 453 for (int32 i = 0; 454 error == B_OK && types->FindString("types", i, &type) == B_OK; 455 i++) { 456 if (!BMimeType::IsValid(type)) 457 error = B_BAD_VALUE; 458 } 459 // get flattened size 460 ssize_t size = 0; 461 if (error == B_OK) { 462 size = types->FlattenedSize(); 463 if (size < 0) 464 error = size; 465 } 466 // allocate a buffer for the flattened data 467 char *buffer = NULL; 468 if (error == B_OK) { 469 buffer = new(nothrow) char[size]; 470 if (!buffer) 471 error = B_NO_MEMORY; 472 } 473 // flatten the message 474 if (error == B_OK) 475 error = types->Flatten(buffer, size); 476 // write the data 477 if (error == B_OK) { 478 error = _WriteData(kSupportedTypesAttribute, 479 kSupportedTypesResourceID, B_MESSAGE_TYPE, 480 buffer, size); 481 } 482 // clean up 483 if (buffer) 484 delete[] buffer; 485 } else 486 error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE); 487 // update the MIME database, if the app signature is installed 488 // if (error == B_OK && mimeType.IsInstalled()) 489 // error = mimeType.SetSupportedTypes(types, syncAll); 490 } 491 return error; 492 } 493 494 // SetSupportedTypes 495 /*! \brief Sets the MIME types supported by the application. 496 497 This method is a short-hand for SetSupportedTypes(types, false). 498 \see SetSupportedType(const BMessage*, bool) for detailed information. 499 500 \param types The supported types to be assigned to the file. 501 May be \c NULL. 502 \return 503 - \c B_OK: Everything went fine. 504 - \c B_NO_INIT: The object is not properly initialized. 505 - other error codes 506 */ 507 status_t 508 BAppFileInfo::SetSupportedTypes(const BMessage *types) 509 { 510 return SetSupportedTypes(types, false); 511 } 512 513 // IsSupportedType 514 /*! \brief Returns whether the application supports the supplied MIME type. 515 516 If the application supports the wildcard type "application/octet-stream" 517 any this method returns \c true for any MIME type. 518 519 \param type The MIME type in question. 520 \return \c true, if \a type is a valid MIME type and it is supported by 521 the application, \c false otherwise. 522 */ 523 bool 524 BAppFileInfo::IsSupportedType(const char *type) const 525 { 526 status_t error = (type ? B_OK : B_BAD_VALUE); 527 // get the supported types 528 BMessage types; 529 if (error == B_OK) 530 error = GetSupportedTypes(&types); 531 // turn type into a BMimeType 532 BMimeType mimeType; 533 if (error == B_OK) 534 error = mimeType.SetTo(type); 535 // iterate through the supported types 536 bool found = false; 537 if (error == B_OK) { 538 const char *supportedType; 539 for (int32 i = 0; 540 !found && types.FindString("types", i, &supportedType) == B_OK; 541 i++) { 542 found = !strcmp(supportedType, "application/octet-stream") 543 || BMimeType(supportedType).Contains(&mimeType); 544 } 545 } 546 return found; 547 } 548 549 // Supports 550 /*! \brief Returns whether the application supports the supplied MIME type 551 explicitly. 552 553 Unlike IsSupportedType(), this method returns \c true, only if the type 554 is explicitly supported, regardless of whether it supports 555 "application/octet-stream". 556 557 \param type The MIME type in question. 558 \return \c true, if \a type is a valid MIME type and it is explicitly 559 supported by the application, \c false otherwise. 560 */ 561 bool 562 BAppFileInfo::Supports(BMimeType *type) const 563 { 564 status_t error = (type && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 565 // get the supported types 566 BMessage types; 567 if (error == B_OK) 568 error = GetSupportedTypes(&types); 569 // iterate through the supported types 570 bool found = false; 571 if (error == B_OK) { 572 const char *supportedType; 573 for (int32 i = 0; 574 !found && types.FindString("types", i, &supportedType) == B_OK; 575 i++) { 576 found = BMimeType(supportedType).Contains(type); 577 } 578 } 579 return found; 580 } 581 582 // GetIcon 583 /*! \brief Gets the file's icon. 584 \param icon A pointer to a pre-allocated BBitmap of the correct dimension 585 to store the requested icon (16x16 for the mini and 32x32 for the 586 large icon). 587 \param which Specifies the size of the icon to be retrieved: 588 \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon. 589 \return 590 - \c B_OK: Everything went fine. 591 - \c B_NO_INIT: The object is not properly initialized. 592 - \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a which or bitmap 593 dimensions (\a icon) and icon size (\a which) do not match. 594 - other error codes 595 */ 596 status_t 597 BAppFileInfo::GetIcon(BBitmap *icon, icon_size which) const 598 { 599 return GetIconForType(NULL, icon, which); 600 } 601 602 // SetIcon 603 /*! \brief Sets the file's icon. 604 605 If \a icon is \c NULL the file's icon is unset. 606 607 \param icon A pointer to the BBitmap containing the icon to be set. 608 May be \c NULL. 609 \param which Specifies the size of the icon to be set: \c B_MINI_ICON 610 for the mini and \c B_LARGE_ICON for the large icon. 611 \return 612 - \c B_OK: Everything went fine. 613 - \c B_NO_INIT: The object is not properly initialized. 614 - \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon) 615 and icon size (\a which) do not match. 616 - other error codes 617 */ 618 status_t 619 BAppFileInfo::SetIcon(const BBitmap *icon, icon_size which) 620 { 621 return SetIconForType(NULL, icon, which); 622 } 623 624 // GetVersionInfo 625 /*! \brief Gets the file's version info. 626 \param info A pointer to a pre-allocated version_info structure into which 627 the version info should be written. 628 \param kind Specifies the kind of the version info to be retrieved: 629 \c B_APP_VERSION_KIND for the application's version info and 630 \c B_SYSTEM_VERSION_KIND for the suite's info the application 631 belongs to. 632 \return 633 - \c B_OK: Everything went fine. 634 - \c B_NO_INIT: The object is not properly initialized. 635 - \c B_BAD_VALUE: \c NULL \a info. 636 - other error codes 637 */ 638 status_t 639 BAppFileInfo::GetVersionInfo(version_info *info, version_kind kind) const 640 { 641 // check params and initialization 642 if (!info) 643 return B_BAD_VALUE; 644 645 int32 index = 0; 646 switch (kind) { 647 case B_APP_VERSION_KIND: 648 index = 0; 649 break; 650 case B_SYSTEM_VERSION_KIND: 651 index = 1; 652 break; 653 default: 654 return B_BAD_VALUE; 655 } 656 657 if (InitCheck() != B_OK) 658 return B_NO_INIT; 659 660 // read the data 661 size_t read = 0; 662 version_info infos[2]; 663 status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 664 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read); 665 if (error != B_OK) 666 return error; 667 668 // check the read data 669 if (read == sizeof(version_info)) { 670 // only the app version info is there -- return a cleared system info 671 if (index == 0) 672 *info = infos[index]; 673 else if (index == 1) 674 memset(info, 0, sizeof(version_info)); 675 } else if (read == 2 * sizeof(version_info)) { 676 *info = infos[index]; 677 } else 678 return B_ERROR; 679 680 // return result 681 return B_OK; 682 } 683 684 // SetVersionInfo 685 /*! \brief Sets the file's version info. 686 687 If \a info is \c NULL the file's version info is unset. 688 689 \param info The version info to be set. May be \c NULL. 690 \param kind Specifies kind of version info to be set: 691 \c B_APP_VERSION_KIND for the application's version info and 692 \c B_SYSTEM_VERSION_KIND for the suite's info the application 693 belongs to. 694 \return 695 - \c B_OK: Everything went fine. 696 - \c B_NO_INIT: The object is not properly initialized. 697 - other error codes 698 */ 699 status_t 700 BAppFileInfo::SetVersionInfo(const version_info *info, version_kind kind) 701 { 702 // check initialization 703 status_t error = B_OK; 704 if (error == B_OK && InitCheck() != B_OK) 705 error = B_NO_INIT; 706 if (error == B_OK) { 707 if (info) { 708 // check param 709 int32 index = 0; 710 if (error == B_OK) { 711 switch (kind) { 712 case B_APP_VERSION_KIND: 713 index = 0; 714 break; 715 case B_SYSTEM_VERSION_KIND: 716 index = 1; 717 break; 718 default: 719 error = B_BAD_VALUE; 720 break; 721 } 722 } 723 // read both infos 724 version_info infos[2]; 725 if (error == B_OK) { 726 size_t read; 727 if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 728 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), 729 read) == B_OK) { 730 // clear the part that hasn't been read 731 if (read < sizeof(infos)) 732 memset((char*)infos + read, 0, sizeof(infos) - read); 733 } else { 734 // failed to read -- clear 735 memset(infos, 0, sizeof(infos)); 736 } 737 } 738 infos[index] = *info; 739 // write the data 740 if (error == B_OK) { 741 error = _WriteData(kVersionInfoAttribute, 742 kVersionInfoResourceID, 743 B_VERSION_INFO_TYPE, infos, 744 2 * sizeof(version_info)); 745 } 746 } else 747 error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE); 748 } 749 return error; 750 } 751 752 // GetIconForType 753 /*! \brief Gets the icon the application provides for a given MIME type. 754 755 If \a type is \c NULL, the application's icon is retrieved. 756 757 \param type The MIME type in question. May be \c NULL. 758 \param icon A pointer to a pre-allocated BBitmap of the correct dimension 759 to store the requested icon (16x16 for the mini and 32x32 for the 760 large icon). 761 \param which Specifies the size of the icon to be retrieved: 762 \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon. 763 \return 764 - \c B_OK: Everything went fine. 765 - \c B_NO_INIT: The object is not properly initialized. 766 - \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size 767 \a which or bitmap dimensions (\a icon) and icon size (\a which) do 768 not match. 769 - other error codes 770 */ 771 status_t 772 BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, 773 icon_size which) const 774 { 775 status_t error = B_OK; 776 // set some icon size related variables 777 BString attributeString; 778 BRect bounds; 779 uint32 attrType = 0; 780 size_t attrSize = 0; 781 switch (which) { 782 case B_MINI_ICON: 783 attributeString = kMiniIconAttribute; 784 bounds.Set(0, 0, 15, 15); 785 attrType = B_MINI_ICON_TYPE; 786 attrSize = 16 * 16; 787 break; 788 case B_LARGE_ICON: 789 attributeString = kLargeIconAttribute; 790 bounds.Set(0, 0, 31, 31); 791 attrType = B_LARGE_ICON_TYPE; 792 attrSize = 32 * 32; 793 break; 794 default: 795 error = B_BAD_VALUE; 796 break; 797 } 798 // check type param 799 if (error == B_OK) { 800 if (type) { 801 if (BMimeType::IsValid(type)) 802 attributeString += type; 803 else 804 error = B_BAD_VALUE; 805 } else 806 attributeString += kStandardIconType; 807 } 808 const char *attribute = attributeString.String(); 809 810 // check parameter and initialization 811 if (error == B_OK 812 && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { 813 error = B_BAD_VALUE; 814 } 815 if (error == B_OK && InitCheck() != B_OK) 816 error = B_NO_INIT; 817 // read the data 818 if (error == B_OK) { 819 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 820 char *buffer = NULL; 821 size_t read; 822 if (otherColorSpace) { 823 // other color space than stored in attribute 824 buffer = new(nothrow) char[attrSize]; 825 if (!buffer) 826 error = B_NO_MEMORY; 827 if (error == B_OK) { 828 error = _ReadData(attribute, -1, attrType, buffer, attrSize, 829 read); 830 } 831 } else { 832 error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize, 833 read); 834 } 835 if (error == B_OK && read != attrSize) 836 error = B_ERROR; 837 if (otherColorSpace) { 838 // other color space than stored in attribute 839 if (error == B_OK) { 840 error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, 841 0, B_CMAP8); 842 } 843 delete[] buffer; 844 } 845 } 846 return error; 847 } 848 849 // SetIconForType 850 /*! \brief Sets the icon the application provides for a given MIME type. 851 852 If \a type is \c NULL, the application's icon is set. 853 If \a icon is \c NULL the icon is unset. 854 855 If the file has a signature, then the icon is also set on the MIME type. 856 If the type for the signature has not been installed yet, it is installed 857 before. 858 859 \param type The MIME type in question. May be \c NULL. 860 \param icon A pointer to the BBitmap containing the icon to be set. 861 May be \c NULL. 862 \param which Specifies the size of the icon to be set: \c B_MINI_ICON 863 for the mini and \c B_LARGE_ICON for the large icon. 864 \return 865 - \c B_OK: Everything went fine. 866 - \c B_NO_INIT: The object is not properly initialized. 867 - \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon) 868 and icon size (\a which) do not match. 869 - other error codes 870 */ 871 status_t 872 BAppFileInfo::SetIconForType(const char *type, const BBitmap *icon, 873 icon_size which) 874 { 875 status_t error = B_OK; 876 // set some icon size related variables 877 BString attributeString; 878 BRect bounds; 879 uint32 attrType = 0; 880 size_t attrSize = 0; 881 int32 resourceID = 0; 882 switch (which) { 883 case B_MINI_ICON: 884 attributeString = kMiniIconAttribute; 885 bounds.Set(0, 0, 15, 15); 886 attrType = B_MINI_ICON_TYPE; 887 attrSize = 16 * 16; 888 resourceID = (type ? kMiniIconForTypeResourceID 889 : kMiniIconResourceID); 890 break; 891 case B_LARGE_ICON: 892 attributeString = kLargeIconAttribute; 893 bounds.Set(0, 0, 31, 31); 894 attrType = B_LARGE_ICON_TYPE; 895 attrSize = 32 * 32; 896 resourceID = (type ? kLargeIconForTypeResourceID 897 : kLargeIconResourceID); 898 break; 899 default: 900 error = B_BAD_VALUE; 901 break; 902 } 903 // check type param 904 if (error == B_OK) { 905 if (type) { 906 if (BMimeType::IsValid(type)) 907 attributeString += type; 908 else 909 error = B_BAD_VALUE; 910 } else 911 attributeString += kStandardIconType; 912 } 913 const char *attribute = attributeString.String(); 914 // check parameter and initialization 915 if (error == B_OK && icon 916 && (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { 917 error = B_BAD_VALUE; 918 } 919 if (error == B_OK && InitCheck() != B_OK) 920 error = B_NO_INIT; 921 // write/remove the attribute 922 if (error == B_OK) { 923 if (icon) { 924 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 925 if (otherColorSpace) { 926 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8); 927 error = bitmap.InitCheck(); 928 if (error == B_OK) 929 error = bitmap.ImportBits(icon); 930 if (error == B_OK) { 931 error = _WriteData(attribute, resourceID, attrType, 932 bitmap.Bits(), attrSize, true); 933 } 934 } else { 935 error = _WriteData(attribute, resourceID, attrType, 936 icon->Bits(), attrSize, true); 937 } 938 } else // no icon given => remove 939 error = _RemoveData(attribute, attrType); 940 } 941 // set the attribute on the MIME type, if the file has a signature 942 BMimeType mimeType; 943 if (error == B_OK && GetMetaMime(&mimeType) == B_OK) { 944 // if (!mimeType.IsInstalled()) 945 // error = mimeType.Install(); 946 // if (error == B_OK) 947 // error = mimeType.SetIconForType(type, icon, which); 948 } 949 return error; 950 } 951 952 // SetInfoLocation 953 /*! \brief Specifies the location where the meta data shall be stored. 954 955 The options for \a location are: 956 - \c B_USE_ATTRIBUTES: Store the data in the attributes. 957 - \c B_USE_RESOURCES: Store the data in the resources. 958 - \c B_USE_BOTH_LOCATIONS: Store the data in attributes and resources. 959 960 \param location The location where the meta data shall be stored. 961 */ 962 void 963 BAppFileInfo::SetInfoLocation(info_location location) 964 { 965 fWhere = location; 966 } 967 968 // IsUsingAttributes 969 /*! \brief Returns whether the object stores the meta data (also) in the 970 file's attributes. 971 \return \c true, if the meta data are (also) stored in the file's 972 attributes, \c false otherwise. 973 */ 974 bool 975 BAppFileInfo::IsUsingAttributes() const 976 { 977 return (fWhere & B_USE_ATTRIBUTES); 978 } 979 980 // IsUsingResources 981 /*! \brief Returns whether the object stores the meta data (also) in the 982 file's resources. 983 \return \c true, if the meta data are (also) stored in the file's 984 resources, \c false otherwise. 985 */ 986 bool 987 BAppFileInfo::IsUsingResources() const 988 { 989 return (fWhere & B_USE_RESOURCES); 990 } 991 992 // FBC 993 void BAppFileInfo::_ReservedAppFileInfo1() {} 994 void BAppFileInfo::_ReservedAppFileInfo2() {} 995 void BAppFileInfo::_ReservedAppFileInfo3() {} 996 997 // = 998 /*! \brief Privatized assignment operator to prevent usage. 999 */ 1000 BAppFileInfo & 1001 BAppFileInfo::operator=(const BAppFileInfo &) 1002 { 1003 return *this; 1004 } 1005 1006 // copy constructor 1007 /*! \brief Privatized copy constructor to prevent usage. 1008 */ 1009 BAppFileInfo::BAppFileInfo(const BAppFileInfo &) 1010 { 1011 } 1012 1013 // GetMetaMime 1014 /*! \brief Initializes a BMimeType to the file's signature. 1015 1016 The parameter \a meta is not checked. 1017 1018 \param meta A pointer to a pre-allocated BMimeType that shall be 1019 initialized to the file's signature. 1020 \return 1021 - \c B_OK: Everything went fine. 1022 - \c B_BAD_VALUE: \c NULL \a meta 1023 - \c B_ENTRY_NOT_FOUND: The file has not signature or the signature is 1024 ( not installed in the MIME database.) 1025 no valid MIME string. 1026 - other error codes 1027 */ 1028 status_t 1029 BAppFileInfo::GetMetaMime(BMimeType *meta) const 1030 { 1031 char signature[B_MIME_TYPE_LENGTH]; 1032 status_t error = GetSignature(signature); 1033 if (error == B_OK) 1034 error = meta->SetTo(signature); 1035 else if (error == B_BAD_VALUE) 1036 error = B_ENTRY_NOT_FOUND; 1037 if (error == B_OK && !meta->IsValid()) 1038 error = B_BAD_VALUE; 1039 return error; 1040 } 1041 1042 // _ReadData 1043 /*! \brief Reads data from an attribute or resource. 1044 1045 The data are read from the location specified by \a fWhere. 1046 1047 The object must be properly initialized. The parameters are NOT checked. 1048 1049 \param name The name of the attribute/resource to be read. 1050 \param id The resource ID of the resource to be read. Is ignored, when 1051 < 0. 1052 \param type The type of the attribute/resource to be read. 1053 \param buffer A pre-allocated buffer for the data to be read. 1054 \param bufferSize The size of the supplied buffer. 1055 \param bytesRead A reference parameter, set to the number of bytes 1056 actually read. 1057 \param allocatedBuffer If not \c NULL, the method allocates a buffer 1058 large enough too store the whole data and writes a pointer to it 1059 into this variable. If \c NULL, the supplied buffer is used. 1060 \return 1061 - \c B_OK: Everything went fine. 1062 - error code 1063 */ 1064 status_t 1065 BAppFileInfo::_ReadData(const char *name, int32 id, type_code type, 1066 void *buffer, size_t bufferSize, 1067 size_t &bytesRead, void **allocatedBuffer) const 1068 { 1069 status_t error = B_OK; 1070 1071 if (allocatedBuffer) 1072 buffer = NULL; 1073 1074 bool foundData = false; 1075 1076 if (IsUsingAttributes()) { 1077 // get an attribute info 1078 attr_info info; 1079 if (error == B_OK) 1080 error = fNode->GetAttrInfo(name, &info); 1081 1082 // check type and size, allocate a buffer, if required 1083 if (error == B_OK && info.type != type) 1084 error = B_BAD_VALUE; 1085 if (error == B_OK && allocatedBuffer) { 1086 buffer = malloc(info.size); 1087 if (!buffer) 1088 error = B_NO_MEMORY; 1089 bufferSize = info.size; 1090 } 1091 if (error == B_OK && bufferSize < info.size) 1092 error = B_BAD_VALUE; 1093 1094 // read the data 1095 if (error == B_OK) { 1096 ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size); 1097 if (read < 0) 1098 error = read; 1099 else if (read != info.size) 1100 error = B_ERROR; 1101 else 1102 bytesRead = read; 1103 } 1104 1105 foundData = (error == B_OK); 1106 1107 // free the allocated buffer on error 1108 if (!foundData && allocatedBuffer && buffer) { 1109 free(buffer); 1110 buffer = NULL; 1111 } 1112 } 1113 1114 if (!foundData && IsUsingResources()) { 1115 // get a resource info 1116 error = B_OK; 1117 int32 idFound; 1118 size_t sizeFound; 1119 if (error == B_OK) { 1120 if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1121 error = B_ENTRY_NOT_FOUND; 1122 } 1123 1124 // check id and size, allocate a buffer, if required 1125 if (error == B_OK && id >= 0 && idFound != id) 1126 error = B_ENTRY_NOT_FOUND; 1127 if (error == B_OK && allocatedBuffer) { 1128 buffer = malloc(sizeFound); 1129 if (!buffer) 1130 error = B_NO_MEMORY; 1131 bufferSize = sizeFound; 1132 } 1133 if (error == B_OK && bufferSize < sizeFound) 1134 error = B_BAD_VALUE; 1135 1136 // load resource 1137 const void *resourceData = NULL; 1138 if (error == B_OK) { 1139 resourceData = fResources->LoadResource(type, name, &bytesRead); 1140 if (resourceData && sizeFound == bytesRead) 1141 memcpy(buffer, resourceData, bytesRead); 1142 else 1143 error = B_ERROR; 1144 } 1145 1146 } else if (!foundData) 1147 error = B_BAD_VALUE; 1148 1149 // return the allocated buffer, or free it on error 1150 if (allocatedBuffer) { 1151 if (error == B_OK) 1152 *allocatedBuffer = buffer; 1153 else 1154 free(buffer); 1155 } 1156 1157 return error; 1158 } 1159 1160 // _WriteData 1161 /*! \brief Writes data to an attribute or resource. 1162 1163 The data are written to the location(s) specified by \a fWhere. 1164 1165 The object must be properly initialized. The parameters are NOT checked. 1166 1167 \param name The name of the attribute/resource to be written. 1168 \param id The resource ID of the resource to be written. 1169 \param type The type of the attribute/resource to be written. 1170 \param buffer A buffer containing the data to be written. 1171 \param bufferSize The size of the supplied buffer. 1172 \param findID If set to \c true use the ID that is already assigned to the 1173 \a name / \a type pair or take the first unused ID >= \a id. 1174 If \c false, \a id is used. 1175 If \a id is already in use and . 1176 \return 1177 - \c B_OK: Everything went fine. 1178 - error code 1179 */ 1180 status_t 1181 BAppFileInfo::_WriteData(const char *name, int32 id, type_code type, 1182 const void *buffer, size_t bufferSize, bool findID) 1183 { 1184 status_t error = B_OK; 1185 // write to attribute 1186 if (IsUsingAttributes() && error == B_OK) { 1187 ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize); 1188 if (written < 0) 1189 error = written; 1190 else if (written != (ssize_t)bufferSize) 1191 error = B_ERROR; 1192 } 1193 // write to resource 1194 if (IsUsingResources() && error == B_OK) { 1195 if (findID) { 1196 // get the resource info 1197 int32 idFound; 1198 size_t sizeFound; 1199 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1200 id = idFound; 1201 else { 1202 // type-name pair doesn't exist yet -- find unused ID 1203 while (fResources->HasResource(type, id)) 1204 id++; 1205 } 1206 } 1207 error = fResources->AddResource(type, id, buffer, bufferSize, name); 1208 } 1209 return error; 1210 } 1211 1212 // _RemoveData 1213 /*! \brief Removes an attribute or resource. 1214 1215 The removal location is specified by \a fWhere. 1216 1217 The object must be properly initialized. The parameters are NOT checked. 1218 1219 \param name The name of the attribute/resource to be remove. 1220 \param type The type of the attribute/resource to be removed. 1221 \return 1222 - \c B_OK: Everything went fine. 1223 - error code 1224 */ 1225 status_t 1226 BAppFileInfo::_RemoveData(const char *name, type_code type) 1227 { 1228 status_t error = B_OK; 1229 // remove the attribute 1230 if (IsUsingAttributes() && error == B_OK) { 1231 error = fNode->RemoveAttr(name); 1232 // It's no error, if there has been no attribute. 1233 if (error == B_ENTRY_NOT_FOUND) 1234 error = B_OK; 1235 } 1236 // remove the resource 1237 if (IsUsingResources() && error == B_OK) { 1238 // get a resource info 1239 int32 idFound; 1240 size_t sizeFound; 1241 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1242 error = fResources->RemoveResource(type, idFound); 1243 } 1244 return error; 1245 } 1246 1247