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