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