1 /* 2 * Copyright 2002-2014, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, ingo_weinhold@gmx.de 7 */ 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 <IconUtils.h> 20 #include <MimeType.h> 21 #include <RegistrarDefs.h> 22 #include <Resources.h> 23 #include <Roster.h> 24 #include <String.h> 25 26 27 // debugging 28 //#define DBG(x) x 29 #define DBG(x) 30 #define OUT printf 31 32 33 // type codes 34 enum { 35 B_APP_FLAGS_TYPE = 'APPF', 36 B_VERSION_INFO_TYPE = 'APPV', 37 }; 38 39 40 // attributes 41 static const char* kTypeAttribute = "BEOS:TYPE"; 42 static const char* kSignatureAttribute = "BEOS:APP_SIG"; 43 static const char* kAppFlagsAttribute = "BEOS:APP_FLAGS"; 44 static const char* kSupportedTypesAttribute = "BEOS:FILE_TYPES"; 45 static const char* kVersionInfoAttribute = "BEOS:APP_VERSION"; 46 static const char* kMiniIconAttribute = "BEOS:M:"; 47 static const char* kLargeIconAttribute = "BEOS:L:"; 48 static const char* kIconAttribute = "BEOS:"; 49 static const char* kStandardIconType = "STD_ICON"; 50 static const char* kIconType = "ICON"; 51 static const char* kCatalogEntryAttribute = "SYS:NAME"; 52 53 // resource IDs 54 static const int32 kTypeResourceID = 2; 55 static const int32 kSignatureResourceID = 1; 56 static const int32 kAppFlagsResourceID = 1; 57 static const int32 kSupportedTypesResourceID = 1; 58 static const int32 kMiniIconResourceID = 101; 59 static const int32 kLargeIconResourceID = 101; 60 static const int32 kIconResourceID = 101; 61 static const int32 kVersionInfoResourceID = 1; 62 static const int32 kMiniIconForTypeResourceID = 0; 63 static const int32 kLargeIconForTypeResourceID = 0; 64 static const int32 kIconForTypeResourceID = 0; 65 static const int32 kCatalogEntryResourceID = 1; 66 67 // R5 also exports these (Tracker is using them): 68 // (maybe we better want to drop them silently and declare 69 // the above in a public Haiku header - and use that one in 70 // Tracker when compiled for Haiku) 71 extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE; 72 const uint32 MINI_ICON_TYPE = 'MICN'; 73 const uint32 LARGE_ICON_TYPE = 'ICON'; 74 75 76 BAppFileInfo::BAppFileInfo() 77 : 78 fResources(NULL), 79 fWhere(B_USE_BOTH_LOCATIONS) 80 { 81 } 82 83 84 BAppFileInfo::BAppFileInfo(BFile* file) 85 : 86 fResources(NULL), 87 fWhere(B_USE_BOTH_LOCATIONS) 88 { 89 SetTo(file); 90 } 91 92 93 BAppFileInfo::~BAppFileInfo() 94 { 95 delete fResources; 96 } 97 98 99 status_t 100 BAppFileInfo::SetTo(BFile* file) 101 { 102 // unset the old file 103 BNodeInfo::SetTo(NULL); 104 if (fResources) { 105 delete fResources; 106 fResources = NULL; 107 } 108 109 // check param 110 status_t error 111 = file != NULL && file->InitCheck() == B_OK ? B_OK : B_BAD_VALUE; 112 113 info_location where = B_USE_BOTH_LOCATIONS; 114 115 // create resources 116 if (error == B_OK) { 117 fResources = new(std::nothrow) BResources(); 118 if (fResources) { 119 error = fResources->SetTo(file); 120 if (error != B_OK) { 121 // no resources - this is no critical error, we'll just use 122 // attributes only, then 123 where = B_USE_ATTRIBUTES; 124 error = B_OK; 125 } 126 } else 127 error = B_NO_MEMORY; 128 } 129 130 // set node info 131 if (error == B_OK) 132 error = BNodeInfo::SetTo(file); 133 134 if (error != B_OK || (where & B_USE_RESOURCES) == 0) { 135 delete fResources; 136 fResources = NULL; 137 } 138 139 // clean up on error 140 if (error != B_OK) { 141 if (InitCheck() == B_OK) 142 BNodeInfo::SetTo(NULL); 143 } 144 145 // set data location 146 if (error == B_OK) 147 SetInfoLocation(where); 148 149 // set error 150 fCStatus = error; 151 return error; 152 } 153 154 155 status_t 156 BAppFileInfo::GetType(char* type) const 157 { 158 // check param and initialization 159 status_t error = type != NULL ? B_OK : B_BAD_VALUE; 160 if (error == B_OK && InitCheck() != B_OK) 161 error = B_NO_INIT; 162 // read the data 163 size_t read = 0; 164 if (error == B_OK) { 165 error = _ReadData(kTypeAttribute, kTypeResourceID, B_MIME_STRING_TYPE, 166 type, B_MIME_TYPE_LENGTH, read); 167 } 168 // check the read data -- null terminate the string 169 if (error == B_OK && type[read - 1] != '\0') { 170 if (read == B_MIME_TYPE_LENGTH) 171 error = B_ERROR; 172 else 173 type[read] = '\0'; 174 } 175 return error; 176 } 177 178 179 status_t 180 BAppFileInfo::SetType(const char* type) 181 { 182 // check initialization 183 status_t error = B_OK; 184 if (error == B_OK && InitCheck() != B_OK) 185 error = B_NO_INIT; 186 if (error == B_OK) { 187 if (type != NULL) { 188 // check param 189 size_t typeLen = strlen(type); 190 if (error == B_OK && typeLen >= B_MIME_TYPE_LENGTH) 191 error = B_BAD_VALUE; 192 // write the data 193 if (error == B_OK) { 194 error = _WriteData(kTypeAttribute, kTypeResourceID, 195 B_MIME_STRING_TYPE, type, typeLen + 1); 196 } 197 } else 198 error = _RemoveData(kTypeAttribute, B_MIME_STRING_TYPE); 199 } 200 return error; 201 } 202 203 204 status_t 205 BAppFileInfo::GetSignature(char* signature) const 206 { 207 // check param and initialization 208 status_t error = (signature ? B_OK : B_BAD_VALUE); 209 if (error == B_OK && InitCheck() != B_OK) 210 error = B_NO_INIT; 211 // read the data 212 size_t read = 0; 213 if (error == B_OK) { 214 error = _ReadData(kSignatureAttribute, kSignatureResourceID, 215 B_MIME_STRING_TYPE, signature, B_MIME_TYPE_LENGTH, read); 216 } 217 // check the read data -- null terminate the string 218 if (error == B_OK && signature[read - 1] != '\0') { 219 if (read == B_MIME_TYPE_LENGTH) 220 error = B_ERROR; 221 else 222 signature[read] = '\0'; 223 } 224 return error; 225 } 226 227 228 status_t 229 BAppFileInfo::SetSignature(const char* signature) 230 { 231 // check initialization 232 status_t error = B_OK; 233 if (error == B_OK && InitCheck() != B_OK) 234 error = B_NO_INIT; 235 if (error == B_OK) { 236 if (signature) { 237 // check param 238 size_t signatureLen = strlen(signature); 239 if (error == B_OK && signatureLen >= B_MIME_TYPE_LENGTH) 240 error = B_BAD_VALUE; 241 // write the data 242 if (error == B_OK) { 243 error = _WriteData(kSignatureAttribute, kSignatureResourceID, 244 B_MIME_STRING_TYPE, signature, signatureLen + 1); 245 } 246 } else 247 error = _RemoveData(kSignatureAttribute, B_MIME_STRING_TYPE); 248 } 249 return error; 250 } 251 252 253 status_t 254 BAppFileInfo::GetCatalogEntry(char* catalogEntry) const 255 { 256 if (catalogEntry == NULL) 257 return B_BAD_VALUE; 258 259 if (InitCheck() != B_OK) 260 return B_NO_INIT; 261 262 size_t read = 0; 263 status_t error = _ReadData(kCatalogEntryAttribute, kCatalogEntryResourceID, 264 B_STRING_TYPE, catalogEntry, B_MIME_TYPE_LENGTH * 3, read); 265 266 if (error != B_OK) 267 return error; 268 269 if (read >= B_MIME_TYPE_LENGTH * 3) 270 return B_ERROR; 271 272 catalogEntry[read] = '\0'; 273 274 return B_OK; 275 } 276 277 278 status_t 279 BAppFileInfo::SetCatalogEntry(const char* catalogEntry) 280 { 281 if (InitCheck() != B_OK) 282 return B_NO_INIT; 283 284 if (catalogEntry == NULL) 285 return _RemoveData(kCatalogEntryAttribute, B_STRING_TYPE); 286 287 size_t nameLength = strlen(catalogEntry); 288 if (nameLength > B_MIME_TYPE_LENGTH * 3) 289 return B_BAD_VALUE; 290 291 return _WriteData(kCatalogEntryAttribute, kCatalogEntryResourceID, 292 B_STRING_TYPE, catalogEntry, nameLength + 1); 293 } 294 295 296 status_t 297 BAppFileInfo::GetAppFlags(uint32* flags) const 298 { 299 // check param and initialization 300 status_t error = flags != NULL ? B_OK : B_BAD_VALUE; 301 if (error == B_OK && InitCheck() != B_OK) 302 error = B_NO_INIT; 303 // read the data 304 size_t read = 0; 305 if (error == B_OK) { 306 error = _ReadData(kAppFlagsAttribute, kAppFlagsResourceID, 307 B_APP_FLAGS_TYPE, flags, sizeof(uint32), read); 308 } 309 // check the read data 310 if (error == B_OK && read != sizeof(uint32)) 311 error = B_ERROR; 312 return error; 313 } 314 315 316 status_t 317 BAppFileInfo::SetAppFlags(uint32 flags) 318 { 319 // check initialization 320 status_t error = B_OK; 321 if (error == B_OK && InitCheck() != B_OK) 322 error = B_NO_INIT; 323 if (error == B_OK) { 324 // write the data 325 error = _WriteData(kAppFlagsAttribute, kAppFlagsResourceID, 326 B_APP_FLAGS_TYPE, &flags, sizeof(uint32)); 327 } 328 return error; 329 } 330 331 332 status_t 333 BAppFileInfo::RemoveAppFlags() 334 { 335 // check initialization 336 status_t error = B_OK; 337 if (error == B_OK && InitCheck() != B_OK) 338 error = B_NO_INIT; 339 if (error == B_OK) { 340 // remove the data 341 error = _RemoveData(kAppFlagsAttribute, B_APP_FLAGS_TYPE); 342 } 343 return error; 344 } 345 346 347 status_t 348 BAppFileInfo::GetSupportedTypes(BMessage* types) const 349 { 350 // check param and initialization 351 status_t error = types != NULL ? B_OK : B_BAD_VALUE; 352 if (error == B_OK && InitCheck() != B_OK) 353 error = B_NO_INIT; 354 // read the data 355 size_t read = 0; 356 void* buffer = NULL; 357 if (error == B_OK) { 358 error = _ReadData(kSupportedTypesAttribute, kSupportedTypesResourceID, 359 B_MESSAGE_TYPE, NULL, 0, read, &buffer); 360 } 361 // unflatten the buffer 362 if (error == B_OK) 363 error = types->Unflatten((const char*)buffer); 364 // clean up 365 free(buffer); 366 return error; 367 } 368 369 370 status_t 371 BAppFileInfo::SetSupportedTypes(const BMessage* types, bool updateMimeDB, 372 bool syncAll) 373 { 374 // check initialization 375 status_t error = B_OK; 376 if (error == B_OK && InitCheck() != B_OK) 377 error = B_NO_INIT; 378 379 BMimeType mimeType; 380 if (error == B_OK) 381 error = GetMetaMime(&mimeType); 382 383 if (error == B_OK || error == B_ENTRY_NOT_FOUND) { 384 error = B_OK; 385 if (types) { 386 // check param -- supported types must be valid 387 const char* type; 388 for (int32 i = 0; 389 error == B_OK && types->FindString("types", i, &type) == B_OK; 390 i++) { 391 if (!BMimeType::IsValid(type)) 392 error = B_BAD_VALUE; 393 } 394 395 // get flattened size 396 ssize_t size = 0; 397 if (error == B_OK) { 398 size = types->FlattenedSize(); 399 if (size < 0) 400 error = size; 401 } 402 403 // allocate a buffer for the flattened data 404 char* buffer = NULL; 405 if (error == B_OK) { 406 buffer = new(std::nothrow) char[size]; 407 if (!buffer) 408 error = B_NO_MEMORY; 409 } 410 411 // flatten the message 412 if (error == B_OK) 413 error = types->Flatten(buffer, size); 414 415 // write the data 416 if (error == B_OK) { 417 error = _WriteData(kSupportedTypesAttribute, 418 kSupportedTypesResourceID, B_MESSAGE_TYPE, buffer, size); 419 } 420 421 delete[] buffer; 422 } else 423 error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE); 424 425 // update the MIME database, if the app signature is installed 426 if (updateMimeDB && error == B_OK && mimeType.IsInstalled()) 427 error = mimeType.SetSupportedTypes(types, syncAll); 428 } 429 return error; 430 } 431 432 433 status_t 434 BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll) 435 { 436 return SetSupportedTypes(types, true, syncAll); 437 } 438 439 440 status_t 441 BAppFileInfo::SetSupportedTypes(const BMessage* types) 442 { 443 return SetSupportedTypes(types, true, false); 444 } 445 446 447 bool 448 BAppFileInfo::IsSupportedType(const char* type) const 449 { 450 status_t error = type != NULL ? B_OK : B_BAD_VALUE; 451 // get the supported types 452 BMessage types; 453 if (error == B_OK) 454 error = GetSupportedTypes(&types); 455 // turn type into a BMimeType 456 BMimeType mimeType; 457 if (error == B_OK) 458 error = mimeType.SetTo(type); 459 // iterate through the supported types 460 bool found = false; 461 if (error == B_OK) { 462 const char* supportedType; 463 for (int32 i = 0; 464 !found && types.FindString("types", i, &supportedType) == B_OK; 465 i++) { 466 found = strcmp(supportedType, "application/octet-stream") == 0 467 || BMimeType(supportedType).Contains(&mimeType); 468 } 469 } 470 return found; 471 } 472 473 474 bool 475 BAppFileInfo::Supports(BMimeType* type) const 476 { 477 status_t error 478 = type != NULL && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE; 479 // get the supported types 480 BMessage types; 481 if (error == B_OK) 482 error = GetSupportedTypes(&types); 483 // iterate through the supported types 484 bool found = false; 485 if (error == B_OK) { 486 const char* supportedType; 487 for (int32 i = 0; 488 !found && types.FindString("types", i, &supportedType) == B_OK; 489 i++) { 490 found = BMimeType(supportedType).Contains(type); 491 } 492 } 493 return found; 494 } 495 496 497 status_t 498 BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const 499 { 500 return GetIconForType(NULL, icon, which); 501 } 502 503 504 status_t 505 BAppFileInfo::GetIcon(uint8** data, size_t* size) const 506 { 507 return GetIconForType(NULL, data, size); 508 } 509 510 511 status_t 512 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB) 513 { 514 return SetIconForType(NULL, icon, which, updateMimeDB); 515 } 516 517 518 status_t 519 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which) 520 { 521 return SetIconForType(NULL, icon, which, true); 522 } 523 524 525 status_t 526 BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB) 527 { 528 return SetIconForType(NULL, data, size, updateMimeDB); 529 } 530 531 532 status_t 533 BAppFileInfo::SetIcon(const uint8* data, size_t size) 534 { 535 return SetIconForType(NULL, data, size, true); 536 } 537 538 539 status_t 540 BAppFileInfo::GetVersionInfo(version_info* info, version_kind kind) const 541 { 542 // check params and initialization 543 if (info == NULL) 544 return B_BAD_VALUE; 545 546 int32 index = 0; 547 switch (kind) { 548 case B_APP_VERSION_KIND: 549 index = 0; 550 break; 551 case B_SYSTEM_VERSION_KIND: 552 index = 1; 553 break; 554 default: 555 return B_BAD_VALUE; 556 } 557 558 if (InitCheck() != B_OK) 559 return B_NO_INIT; 560 561 // read the data 562 size_t read = 0; 563 version_info infos[2]; 564 status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 565 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read); 566 if (error != B_OK) 567 return error; 568 569 // check the read data 570 if (read == sizeof(version_info)) { 571 // only the app version info is there -- return a cleared system info 572 if (index == 0) 573 *info = infos[index]; 574 else if (index == 1) 575 memset(info, 0, sizeof(version_info)); 576 } else if (read == 2 * sizeof(version_info)) { 577 *info = infos[index]; 578 } else 579 return B_ERROR; 580 581 // return result 582 return B_OK; 583 } 584 585 586 status_t 587 BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind) 588 { 589 // check initialization 590 status_t error = B_OK; 591 if (error == B_OK && InitCheck() != B_OK) 592 error = B_NO_INIT; 593 if (error == B_OK) { 594 if (info != NULL) { 595 // check param 596 int32 index = 0; 597 if (error == B_OK) { 598 switch (kind) { 599 case B_APP_VERSION_KIND: 600 index = 0; 601 break; 602 case B_SYSTEM_VERSION_KIND: 603 index = 1; 604 break; 605 default: 606 error = B_BAD_VALUE; 607 break; 608 } 609 } 610 // read both infos 611 version_info infos[2]; 612 if (error == B_OK) { 613 size_t read; 614 if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 615 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), 616 read) == B_OK) { 617 // clear the part that hasn't been read 618 if (read < sizeof(infos)) 619 memset((char*)infos + read, 0, sizeof(infos) - read); 620 } else { 621 // failed to read -- clear 622 memset(infos, 0, sizeof(infos)); 623 } 624 } 625 infos[index] = *info; 626 // write the data 627 if (error == B_OK) { 628 error = _WriteData(kVersionInfoAttribute, 629 kVersionInfoResourceID, B_VERSION_INFO_TYPE, infos, 630 2 * sizeof(version_info)); 631 } 632 } else 633 error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE); 634 } 635 return error; 636 } 637 638 639 status_t 640 BAppFileInfo::GetIconForType(const char* type, BBitmap* icon, icon_size size) 641 const 642 { 643 if (InitCheck() != B_OK) 644 return B_NO_INIT; 645 646 if (icon == NULL || icon->InitCheck() != B_OK) 647 return B_BAD_VALUE; 648 649 // TODO: for consistency with attribute based icon reading, we 650 // could also prefer B_CMAP8 icons here if the provided bitmap 651 // is in that format. Right now, an existing B_CMAP8 icon resource 652 // would be ignored as soon as a vector icon is present. On the other 653 // hand, maybe this still results in a more consistent user interface, 654 // since Tracker/Deskbar would surely show the vector icon. 655 656 // try vector icon first 657 BString vectorAttributeName(kIconAttribute); 658 659 // check type param 660 if (type != NULL) { 661 if (BMimeType::IsValid(type)) 662 vectorAttributeName += type; 663 else 664 return B_BAD_VALUE; 665 } else { 666 vectorAttributeName += kIconType; 667 } 668 const char* attribute = vectorAttributeName.String(); 669 670 size_t bytesRead; 671 void* allocatedBuffer; 672 status_t error = _ReadData(attribute, -1, B_VECTOR_ICON_TYPE, NULL, 0, 673 bytesRead, &allocatedBuffer); 674 if (error == B_OK) { 675 error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer, 676 bytesRead, icon); 677 free(allocatedBuffer); 678 return error; 679 } 680 681 // no vector icon if we got this far, 682 // align size argument just in case 683 if (size < B_LARGE_ICON) 684 size = B_MINI_ICON; 685 else 686 size = B_LARGE_ICON; 687 688 error = B_OK; 689 // set some icon size related variables 690 BString attributeString; 691 BRect bounds; 692 uint32 attrType = 0; 693 size_t attrSize = 0; 694 switch (size) { 695 case B_MINI_ICON: 696 attributeString = kMiniIconAttribute; 697 bounds.Set(0, 0, 15, 15); 698 attrType = B_MINI_ICON_TYPE; 699 attrSize = 16 * 16; 700 break; 701 case B_LARGE_ICON: 702 attributeString = kLargeIconAttribute; 703 bounds.Set(0, 0, 31, 31); 704 attrType = B_LARGE_ICON_TYPE; 705 attrSize = 32 * 32; 706 break; 707 default: 708 return B_BAD_VALUE; 709 } 710 711 // compose attribute name 712 attributeString += type != NULL ? type : kStandardIconType; 713 attribute = attributeString.String(); 714 715 // check parameters 716 // currently, scaling B_CMAP8 icons is not supported 717 if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds) 718 return B_BAD_VALUE; 719 720 // read the data 721 if (error == B_OK) { 722 bool tempBuffer 723 = icon->ColorSpace() != B_CMAP8 || icon->Bounds() != bounds; 724 uint8* buffer = NULL; 725 size_t read; 726 if (tempBuffer) { 727 // other color space or bitmap size than stored in attribute 728 buffer = new(std::nothrow) uint8[attrSize]; 729 if (!buffer) { 730 error = B_NO_MEMORY; 731 } else { 732 error = _ReadData(attribute, -1, attrType, buffer, attrSize, 733 read); 734 } 735 } else { 736 error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize, 737 read); 738 } 739 if (error == B_OK && read != attrSize) 740 error = B_ERROR; 741 if (tempBuffer) { 742 // other color space than stored in attribute 743 if (error == B_OK) { 744 error = BIconUtils::ConvertFromCMAP8(buffer, (uint32)size, 745 (uint32)size, (uint32)size, icon); 746 } 747 delete[] buffer; 748 } 749 } 750 return error; 751 } 752 753 754 status_t 755 BAppFileInfo::GetIconForType(const char* type, uint8** data, size_t* size) const 756 { 757 if (InitCheck() != B_OK) 758 return B_NO_INIT; 759 760 if (data == NULL || size == NULL) 761 return B_BAD_VALUE; 762 763 // get vector icon 764 BString attributeName(kIconAttribute); 765 766 // check type param 767 if (type != NULL) { 768 if (BMimeType::IsValid(type)) 769 attributeName += type; 770 else 771 return B_BAD_VALUE; 772 } else 773 attributeName += kIconType; 774 775 void* allocatedBuffer = NULL; 776 status_t ret = _ReadData(attributeName.String(), -1, B_VECTOR_ICON_TYPE, 777 NULL, 0, *size, &allocatedBuffer); 778 779 if (ret < B_OK) 780 return ret; 781 782 *data = (uint8*)allocatedBuffer; 783 return B_OK; 784 } 785 786 787 status_t 788 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon, 789 icon_size which, bool updateMimeDB) 790 { 791 status_t error = B_OK; 792 793 // set some icon size related variables 794 BString attributeString; 795 BRect bounds; 796 uint32 attrType = 0; 797 size_t attrSize = 0; 798 int32 resourceID = 0; 799 switch (which) { 800 case B_MINI_ICON: 801 attributeString = kMiniIconAttribute; 802 bounds.Set(0, 0, 15, 15); 803 attrType = B_MINI_ICON_TYPE; 804 attrSize = 16 * 16; 805 resourceID = type != NULL 806 ? kMiniIconForTypeResourceID : kMiniIconResourceID; 807 break; 808 case B_LARGE_ICON: 809 attributeString = kLargeIconAttribute; 810 bounds.Set(0, 0, 31, 31); 811 attrType = B_LARGE_ICON_TYPE; 812 attrSize = 32 * 32; 813 resourceID = type != NULL 814 ? kLargeIconForTypeResourceID : kLargeIconResourceID; 815 break; 816 default: 817 error = B_BAD_VALUE; 818 break; 819 } 820 821 // check type param 822 if (error == B_OK) { 823 if (type != NULL) { 824 if (BMimeType::IsValid(type)) 825 attributeString += type; 826 else 827 error = B_BAD_VALUE; 828 } else 829 attributeString += kStandardIconType; 830 } 831 const char* attribute = attributeString.String(); 832 833 // check parameter and initialization 834 if (error == B_OK && icon != NULL 835 && (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { 836 error = B_BAD_VALUE; 837 } 838 if (error == B_OK && InitCheck() != B_OK) 839 error = B_NO_INIT; 840 841 // write/remove the attribute 842 if (error == B_OK) { 843 if (icon != NULL) { 844 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 845 if (otherColorSpace) { 846 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8); 847 error = bitmap.InitCheck(); 848 if (error == B_OK) 849 error = bitmap.ImportBits(icon); 850 if (error == B_OK) { 851 error = _WriteData(attribute, resourceID, attrType, 852 bitmap.Bits(), attrSize, true); 853 } 854 } else { 855 error = _WriteData(attribute, resourceID, attrType, 856 icon->Bits(), attrSize, true); 857 } 858 } else // no icon given => remove 859 error = _RemoveData(attribute, attrType); 860 } 861 862 // set the attribute on the MIME type, if the file has a signature 863 BMimeType mimeType; 864 if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) { 865 if (!mimeType.IsInstalled()) 866 error = mimeType.Install(); 867 if (error == B_OK) 868 error = mimeType.SetIconForType(type, icon, which); 869 } 870 return error; 871 } 872 873 874 status_t 875 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon, 876 icon_size which) 877 { 878 return SetIconForType(type, icon, which, true); 879 } 880 881 882 status_t 883 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size, 884 bool updateMimeDB) 885 { 886 if (InitCheck() != B_OK) 887 return B_NO_INIT; 888 889 // set some icon related variables 890 BString attributeString = kIconAttribute; 891 int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID; 892 uint32 attrType = B_VECTOR_ICON_TYPE; 893 894 // check type param 895 if (type != NULL) { 896 if (BMimeType::IsValid(type)) 897 attributeString += type; 898 else 899 return B_BAD_VALUE; 900 } else 901 attributeString += kIconType; 902 903 const char* attribute = attributeString.String(); 904 905 status_t error; 906 // write/remove the attribute 907 if (data != NULL) 908 error = _WriteData(attribute, resourceID, attrType, data, size, true); 909 else // no icon given => remove 910 error = _RemoveData(attribute, attrType); 911 912 // set the attribute on the MIME type, if the file has a signature 913 BMimeType mimeType; 914 if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) { 915 if (!mimeType.IsInstalled()) 916 error = mimeType.Install(); 917 if (error == B_OK) 918 error = mimeType.SetIconForType(type, data, size); 919 } 920 return error; 921 } 922 923 924 status_t 925 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size) 926 { 927 return SetIconForType(type, data, size, true); 928 } 929 930 931 void 932 BAppFileInfo::SetInfoLocation(info_location location) 933 { 934 // if the resources failed to initialize, we must not use them 935 if (fResources == NULL) 936 location = info_location(location & ~B_USE_RESOURCES); 937 938 fWhere = location; 939 } 940 941 bool 942 BAppFileInfo::IsUsingAttributes() const 943 { 944 return (fWhere & B_USE_ATTRIBUTES) != 0; 945 } 946 947 948 bool 949 BAppFileInfo::IsUsingResources() const 950 { 951 return (fWhere & B_USE_RESOURCES) != 0; 952 } 953 954 955 // FBC 956 void BAppFileInfo::_ReservedAppFileInfo1() {} 957 void BAppFileInfo::_ReservedAppFileInfo2() {} 958 void BAppFileInfo::_ReservedAppFileInfo3() {} 959 960 961 BAppFileInfo& 962 BAppFileInfo::operator=(const BAppFileInfo&) 963 { 964 return *this; 965 } 966 967 968 BAppFileInfo::BAppFileInfo(const BAppFileInfo&) 969 { 970 } 971 972 973 status_t 974 BAppFileInfo::GetMetaMime(BMimeType* meta) const 975 { 976 char signature[B_MIME_TYPE_LENGTH]; 977 status_t error = GetSignature(signature); 978 if (error == B_OK) 979 error = meta->SetTo(signature); 980 else if (error == B_BAD_VALUE) 981 error = B_ENTRY_NOT_FOUND; 982 if (error == B_OK && !meta->IsValid()) 983 error = B_BAD_VALUE; 984 return error; 985 } 986 987 988 status_t 989 BAppFileInfo::_ReadData(const char* name, int32 id, type_code type, 990 void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer) 991 const 992 { 993 status_t error = B_OK; 994 995 if (allocatedBuffer) 996 buffer = NULL; 997 998 bool foundData = false; 999 1000 if (IsUsingAttributes()) { 1001 // get an attribute info 1002 attr_info info; 1003 if (error == B_OK) 1004 error = fNode->GetAttrInfo(name, &info); 1005 1006 // check type and size, allocate a buffer, if required 1007 if (error == B_OK && info.type != type) 1008 error = B_BAD_VALUE; 1009 if (error == B_OK && allocatedBuffer != NULL) { 1010 buffer = malloc(info.size); 1011 if (buffer == NULL) 1012 error = B_NO_MEMORY; 1013 bufferSize = info.size; 1014 } 1015 if (error == B_OK && (off_t)bufferSize < info.size) 1016 error = B_BAD_VALUE; 1017 1018 // read the data 1019 if (error == B_OK) { 1020 ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size); 1021 if (read < 0) 1022 error = read; 1023 else if (read != info.size) 1024 error = B_ERROR; 1025 else 1026 bytesRead = read; 1027 } 1028 1029 foundData = error == B_OK; 1030 1031 // free the allocated buffer on error 1032 if (!foundData && allocatedBuffer != NULL && buffer != NULL) { 1033 free(buffer); 1034 buffer = NULL; 1035 } 1036 } 1037 1038 if (!foundData && IsUsingResources()) { 1039 // get a resource info 1040 error = B_OK; 1041 int32 idFound; 1042 size_t sizeFound; 1043 if (error == B_OK) { 1044 if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1045 error = B_ENTRY_NOT_FOUND; 1046 } 1047 1048 // check id and size, allocate a buffer, if required 1049 if (error == B_OK && id >= 0 && idFound != id) 1050 error = B_ENTRY_NOT_FOUND; 1051 if (error == B_OK && allocatedBuffer) { 1052 buffer = malloc(sizeFound); 1053 if (!buffer) 1054 error = B_NO_MEMORY; 1055 bufferSize = sizeFound; 1056 } 1057 if (error == B_OK && bufferSize < sizeFound) 1058 error = B_BAD_VALUE; 1059 1060 // load resource 1061 const void* resourceData = NULL; 1062 if (error == B_OK) { 1063 resourceData = fResources->LoadResource(type, name, &bytesRead); 1064 if (resourceData != NULL && sizeFound == bytesRead) 1065 memcpy(buffer, resourceData, bytesRead); 1066 else 1067 error = B_ERROR; 1068 } 1069 } else if (!foundData) 1070 error = B_BAD_VALUE; 1071 1072 // return the allocated buffer, or free it on error 1073 if (allocatedBuffer != NULL) { 1074 if (error == B_OK) 1075 *allocatedBuffer = buffer; 1076 else 1077 free(buffer); 1078 } 1079 1080 return error; 1081 } 1082 1083 1084 status_t 1085 BAppFileInfo::_WriteData(const char* name, int32 id, type_code type, 1086 const void* buffer, size_t bufferSize, bool findID) 1087 { 1088 if (!IsUsingAttributes() && !IsUsingResources()) 1089 return B_NO_INIT; 1090 1091 status_t error = B_OK; 1092 1093 // write to attribute 1094 if (IsUsingAttributes()) { 1095 ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize); 1096 if (written < 0) 1097 error = written; 1098 else if (written != (ssize_t)bufferSize) 1099 error = B_ERROR; 1100 } 1101 // write to resource 1102 if (IsUsingResources() && error == B_OK) { 1103 if (findID) { 1104 // get the resource info 1105 int32 idFound; 1106 size_t sizeFound; 1107 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1108 id = idFound; 1109 else { 1110 // type-name pair doesn't exist yet -- find unused ID 1111 while (fResources->HasResource(type, id)) 1112 id++; 1113 } 1114 } 1115 error = fResources->AddResource(type, id, buffer, bufferSize, name); 1116 } 1117 return error; 1118 } 1119 1120 1121 status_t 1122 BAppFileInfo::_RemoveData(const char* name, type_code type) 1123 { 1124 if (!IsUsingAttributes() && !IsUsingResources()) 1125 return B_NO_INIT; 1126 1127 status_t error = B_OK; 1128 1129 // remove the attribute 1130 if (IsUsingAttributes()) { 1131 error = fNode->RemoveAttr(name); 1132 // It's no error, if there has been no attribute. 1133 if (error == B_ENTRY_NOT_FOUND) 1134 error = B_OK; 1135 } 1136 // remove the resource 1137 if (IsUsingResources() && error == B_OK) { 1138 // get a resource info 1139 int32 idFound; 1140 size_t sizeFound; 1141 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1142 error = fResources->RemoveResource(type, idFound); 1143 } 1144 return error; 1145 } 1146