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