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