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 0 427 if (updateMimeDB && error == B_OK && mimeType.IsInstalled()) 428 error = mimeType.SetSupportedTypes(types, syncAll); 429 #endif 430 } 431 return error; 432 } 433 434 435 status_t 436 BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll) 437 { 438 return SetSupportedTypes(types, true, syncAll); 439 } 440 441 442 status_t 443 BAppFileInfo::SetSupportedTypes(const BMessage* types) 444 { 445 return SetSupportedTypes(types, true, false); 446 } 447 448 449 bool 450 BAppFileInfo::IsSupportedType(const char* type) const 451 { 452 status_t error = type != NULL ? B_OK : B_BAD_VALUE; 453 // get the supported types 454 BMessage types; 455 if (error == B_OK) 456 error = GetSupportedTypes(&types); 457 // turn type into a BMimeType 458 BMimeType mimeType; 459 if (error == B_OK) 460 error = mimeType.SetTo(type); 461 // iterate through the supported types 462 bool found = false; 463 if (error == B_OK) { 464 const char* supportedType; 465 for (int32 i = 0; 466 !found && types.FindString("types", i, &supportedType) == B_OK; 467 i++) { 468 found = strcmp(supportedType, "application/octet-stream") == 0 469 || BMimeType(supportedType).Contains(&mimeType); 470 } 471 } 472 return found; 473 } 474 475 476 bool 477 BAppFileInfo::Supports(BMimeType* type) const 478 { 479 status_t error 480 = type != NULL && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE; 481 // get the supported types 482 BMessage types; 483 if (error == B_OK) 484 error = GetSupportedTypes(&types); 485 // iterate through the supported types 486 bool found = false; 487 if (error == B_OK) { 488 const char* supportedType; 489 for (int32 i = 0; 490 !found && types.FindString("types", i, &supportedType) == B_OK; 491 i++) { 492 found = BMimeType(supportedType).Contains(type); 493 } 494 } 495 return found; 496 } 497 498 499 status_t 500 BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const 501 { 502 return GetIconForType(NULL, icon, which); 503 } 504 505 506 status_t 507 BAppFileInfo::GetIcon(uint8** data, size_t* size) const 508 { 509 return GetIconForType(NULL, data, size); 510 } 511 512 513 status_t 514 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB) 515 { 516 return SetIconForType(NULL, icon, which, updateMimeDB); 517 } 518 519 520 status_t 521 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which) 522 { 523 return SetIconForType(NULL, icon, which, true); 524 } 525 526 527 status_t 528 BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB) 529 { 530 return SetIconForType(NULL, data, size, updateMimeDB); 531 } 532 533 534 status_t 535 BAppFileInfo::SetIcon(const uint8* data, size_t size) 536 { 537 return SetIconForType(NULL, data, size, true); 538 } 539 540 541 status_t 542 BAppFileInfo::GetVersionInfo(version_info* info, version_kind kind) const 543 { 544 // check params and initialization 545 if (info == NULL) 546 return B_BAD_VALUE; 547 548 int32 index = 0; 549 switch (kind) { 550 case B_APP_VERSION_KIND: 551 index = 0; 552 break; 553 case B_SYSTEM_VERSION_KIND: 554 index = 1; 555 break; 556 default: 557 return B_BAD_VALUE; 558 } 559 560 if (InitCheck() != B_OK) 561 return B_NO_INIT; 562 563 // read the data 564 size_t read = 0; 565 version_info infos[2]; 566 status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 567 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read); 568 if (error != B_OK) 569 return error; 570 571 // check the read data 572 if (read == sizeof(version_info)) { 573 // only the app version info is there -- return a cleared system info 574 if (index == 0) 575 *info = infos[index]; 576 else if (index == 1) 577 memset(info, 0, sizeof(version_info)); 578 } else if (read == 2 * sizeof(version_info)) { 579 *info = infos[index]; 580 } else 581 return B_ERROR; 582 583 // return result 584 return B_OK; 585 } 586 587 588 status_t 589 BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind) 590 { 591 // check initialization 592 status_t error = B_OK; 593 if (error == B_OK && InitCheck() != B_OK) 594 error = B_NO_INIT; 595 if (error == B_OK) { 596 if (info != NULL) { 597 // check param 598 int32 index = 0; 599 if (error == B_OK) { 600 switch (kind) { 601 case B_APP_VERSION_KIND: 602 index = 0; 603 break; 604 case B_SYSTEM_VERSION_KIND: 605 index = 1; 606 break; 607 default: 608 error = B_BAD_VALUE; 609 break; 610 } 611 } 612 // read both infos 613 version_info infos[2]; 614 if (error == B_OK) { 615 size_t read; 616 if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID, 617 B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), 618 read) == B_OK) { 619 // clear the part that hasn't been read 620 if (read < sizeof(infos)) 621 memset((char*)infos + read, 0, sizeof(infos) - read); 622 } else { 623 // failed to read -- clear 624 memset(infos, 0, sizeof(infos)); 625 } 626 } 627 infos[index] = *info; 628 // write the data 629 if (error == B_OK) { 630 error = _WriteData(kVersionInfoAttribute, 631 kVersionInfoResourceID, B_VERSION_INFO_TYPE, infos, 632 2 * sizeof(version_info)); 633 } 634 } else 635 error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE); 636 } 637 return error; 638 } 639 640 641 status_t 642 BAppFileInfo::GetIconForType(const char* type, BBitmap* icon, icon_size size) 643 const 644 { 645 if (InitCheck() != B_OK) 646 return B_NO_INIT; 647 648 if (icon == NULL || icon->InitCheck() != B_OK) 649 return B_BAD_VALUE; 650 651 // TODO: for consistency with attribute based icon reading, we 652 // could also prefer B_CMAP8 icons here if the provided bitmap 653 // is in that format. Right now, an existing B_CMAP8 icon resource 654 // would be ignored as soon as a vector icon is present. On the other 655 // hand, maybe this still results in a more consistent user interface, 656 // since Tracker/Deskbar would surely show the vector icon. 657 658 // try vector icon first 659 BString vectorAttributeName(kIconAttribute); 660 661 // check type param 662 if (type != NULL) { 663 if (BMimeType::IsValid(type)) 664 vectorAttributeName += type; 665 else 666 return B_BAD_VALUE; 667 } else { 668 vectorAttributeName += kIconType; 669 } 670 const char* attribute = vectorAttributeName.String(); 671 672 size_t bytesRead; 673 void* allocatedBuffer; 674 status_t error = _ReadData(attribute, -1, B_VECTOR_ICON_TYPE, NULL, 0, 675 bytesRead, &allocatedBuffer); 676 if (error == B_OK) { 677 error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer, 678 bytesRead, icon); 679 free(allocatedBuffer); 680 return error; 681 } 682 683 // no vector icon if we got this far, 684 // align size argument just in case 685 if (size < B_LARGE_ICON) 686 size = B_MINI_ICON; 687 else 688 size = B_LARGE_ICON; 689 690 error = B_OK; 691 // set some icon size related variables 692 BString attributeString; 693 BRect bounds; 694 uint32 attrType = 0; 695 size_t attrSize = 0; 696 switch (size) { 697 case B_MINI_ICON: 698 attributeString = kMiniIconAttribute; 699 bounds.Set(0, 0, 15, 15); 700 attrType = B_MINI_ICON_TYPE; 701 attrSize = 16 * 16; 702 break; 703 case B_LARGE_ICON: 704 attributeString = kLargeIconAttribute; 705 bounds.Set(0, 0, 31, 31); 706 attrType = B_LARGE_ICON_TYPE; 707 attrSize = 32 * 32; 708 break; 709 default: 710 return B_BAD_VALUE; 711 } 712 713 // compose attribute name 714 attributeString += type != NULL ? type : kStandardIconType; 715 attribute = attributeString.String(); 716 717 // check parameters 718 // currently, scaling B_CMAP8 icons is not supported 719 if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds) 720 return B_BAD_VALUE; 721 722 // read the data 723 if (error == B_OK) { 724 bool tempBuffer 725 = icon->ColorSpace() != B_CMAP8 || icon->Bounds() != bounds; 726 uint8* buffer = NULL; 727 size_t read; 728 if (tempBuffer) { 729 // other color space or bitmap size than stored in attribute 730 buffer = new(std::nothrow) uint8[attrSize]; 731 if (!buffer) { 732 error = B_NO_MEMORY; 733 } else { 734 error = _ReadData(attribute, -1, attrType, buffer, attrSize, 735 read); 736 } 737 } else { 738 error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize, 739 read); 740 } 741 if (error == B_OK && read != attrSize) 742 error = B_ERROR; 743 if (tempBuffer) { 744 // other color space than stored in attribute 745 if (error == B_OK) { 746 error = BIconUtils::ConvertFromCMAP8(buffer, (uint32)size, 747 (uint32)size, (uint32)size, icon); 748 } 749 delete[] buffer; 750 } 751 } 752 return error; 753 } 754 755 756 status_t 757 BAppFileInfo::GetIconForType(const char* type, uint8** data, size_t* size) const 758 { 759 if (InitCheck() != B_OK) 760 return B_NO_INIT; 761 762 if (data == NULL || size == NULL) 763 return B_BAD_VALUE; 764 765 // get vector icon 766 BString attributeName(kIconAttribute); 767 768 // check type param 769 if (type != NULL) { 770 if (BMimeType::IsValid(type)) 771 attributeName += type; 772 else 773 return B_BAD_VALUE; 774 } else 775 attributeName += kIconType; 776 777 void* allocatedBuffer = NULL; 778 status_t ret = _ReadData(attributeName.String(), -1, B_VECTOR_ICON_TYPE, 779 NULL, 0, *size, &allocatedBuffer); 780 781 if (ret < B_OK) 782 return ret; 783 784 *data = (uint8*)allocatedBuffer; 785 return B_OK; 786 } 787 788 789 status_t 790 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon, 791 icon_size which, bool updateMimeDB) 792 { 793 status_t error = B_OK; 794 795 // set some icon size related variables 796 BString attributeString; 797 BRect bounds; 798 uint32 attrType = 0; 799 size_t attrSize = 0; 800 int32 resourceID = 0; 801 switch (which) { 802 case B_MINI_ICON: 803 attributeString = kMiniIconAttribute; 804 bounds.Set(0, 0, 15, 15); 805 attrType = B_MINI_ICON_TYPE; 806 attrSize = 16 * 16; 807 resourceID = type != NULL 808 ? kMiniIconForTypeResourceID : kMiniIconResourceID; 809 break; 810 case B_LARGE_ICON: 811 attributeString = kLargeIconAttribute; 812 bounds.Set(0, 0, 31, 31); 813 attrType = B_LARGE_ICON_TYPE; 814 attrSize = 32 * 32; 815 resourceID = type != NULL 816 ? kLargeIconForTypeResourceID : kLargeIconResourceID; 817 break; 818 default: 819 error = B_BAD_VALUE; 820 break; 821 } 822 823 // check type param 824 if (error == B_OK) { 825 if (type != NULL) { 826 if (BMimeType::IsValid(type)) 827 attributeString += type; 828 else 829 error = B_BAD_VALUE; 830 } else 831 attributeString += kStandardIconType; 832 } 833 const char* attribute = attributeString.String(); 834 835 // check parameter and initialization 836 if (error == B_OK && icon != NULL 837 && (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { 838 error = B_BAD_VALUE; 839 } 840 if (error == B_OK && InitCheck() != B_OK) 841 error = B_NO_INIT; 842 843 // write/remove the attribute 844 if (error == B_OK) { 845 if (icon != NULL) { 846 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); 847 if (otherColorSpace) { 848 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8); 849 error = bitmap.InitCheck(); 850 if (error == B_OK) 851 error = bitmap.ImportBits(icon); 852 if (error == B_OK) { 853 error = _WriteData(attribute, resourceID, attrType, 854 bitmap.Bits(), attrSize, true); 855 } 856 } else { 857 error = _WriteData(attribute, resourceID, attrType, 858 icon->Bits(), attrSize, true); 859 } 860 } else // no icon given => remove 861 error = _RemoveData(attribute, attrType); 862 } 863 864 // set the attribute on the MIME type, if the file has a signature 865 #if 0 866 BMimeType mimeType; 867 if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) { 868 if (!mimeType.IsInstalled()) 869 error = mimeType.Install(); 870 if (error == B_OK) 871 error = mimeType.SetIconForType(type, icon, which); 872 } 873 #endif 874 return error; 875 } 876 877 878 status_t 879 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon, 880 icon_size which) 881 { 882 return SetIconForType(type, icon, which, true); 883 } 884 885 886 status_t 887 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size, 888 bool updateMimeDB) 889 { 890 if (InitCheck() != B_OK) 891 return B_NO_INIT; 892 893 // set some icon related variables 894 BString attributeString = kIconAttribute; 895 int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID; 896 uint32 attrType = B_VECTOR_ICON_TYPE; 897 898 // check type param 899 if (type != NULL) { 900 if (BMimeType::IsValid(type)) 901 attributeString += type; 902 else 903 return B_BAD_VALUE; 904 } else 905 attributeString += kIconType; 906 907 const char* attribute = attributeString.String(); 908 909 status_t error; 910 // write/remove the attribute 911 if (data != NULL) 912 error = _WriteData(attribute, resourceID, attrType, data, size, true); 913 else // no icon given => remove 914 error = _RemoveData(attribute, attrType); 915 916 // set the attribute on the MIME type, if the file has a signature 917 #if 0 918 BMimeType mimeType; 919 if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) { 920 if (!mimeType.IsInstalled()) 921 error = mimeType.Install(); 922 if (error == B_OK) 923 error = mimeType.SetIconForType(type, data, size); 924 } 925 #endif 926 return error; 927 } 928 929 930 status_t 931 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size) 932 { 933 return SetIconForType(type, data, size, true); 934 } 935 936 937 void 938 BAppFileInfo::SetInfoLocation(info_location location) 939 { 940 // if the resources failed to initialize, we must not use them 941 if (fResources == NULL) 942 location = info_location(location & ~B_USE_RESOURCES); 943 944 fWhere = location; 945 } 946 947 bool 948 BAppFileInfo::IsUsingAttributes() const 949 { 950 return (fWhere & B_USE_ATTRIBUTES) != 0; 951 } 952 953 954 bool 955 BAppFileInfo::IsUsingResources() const 956 { 957 return (fWhere & B_USE_RESOURCES) != 0; 958 } 959 960 961 // FBC 962 void BAppFileInfo::_ReservedAppFileInfo1() {} 963 void BAppFileInfo::_ReservedAppFileInfo2() {} 964 void BAppFileInfo::_ReservedAppFileInfo3() {} 965 966 967 BAppFileInfo& 968 BAppFileInfo::operator=(const BAppFileInfo&) 969 { 970 return *this; 971 } 972 973 974 BAppFileInfo::BAppFileInfo(const BAppFileInfo&) 975 { 976 } 977 978 979 status_t 980 BAppFileInfo::GetMetaMime(BMimeType* meta) const 981 { 982 char signature[B_MIME_TYPE_LENGTH]; 983 status_t error = GetSignature(signature); 984 if (error == B_OK) 985 error = meta->SetTo(signature); 986 else if (error == B_BAD_VALUE) 987 error = B_ENTRY_NOT_FOUND; 988 if (error == B_OK && !meta->IsValid()) 989 error = B_BAD_VALUE; 990 return error; 991 } 992 993 994 status_t 995 BAppFileInfo::_ReadData(const char* name, int32 id, type_code type, 996 void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer) 997 const 998 { 999 status_t error = B_OK; 1000 1001 if (allocatedBuffer) 1002 buffer = NULL; 1003 1004 bool foundData = false; 1005 1006 if (IsUsingAttributes()) { 1007 // get an attribute info 1008 attr_info info; 1009 if (error == B_OK) 1010 error = fNode->GetAttrInfo(name, &info); 1011 1012 // check type and size, allocate a buffer, if required 1013 if (error == B_OK && info.type != type) 1014 error = B_BAD_VALUE; 1015 if (error == B_OK && allocatedBuffer != NULL) { 1016 buffer = malloc(info.size); 1017 if (buffer == NULL) 1018 error = B_NO_MEMORY; 1019 bufferSize = info.size; 1020 } 1021 if (error == B_OK && (off_t)bufferSize < info.size) 1022 error = B_BAD_VALUE; 1023 1024 // read the data 1025 if (error == B_OK) { 1026 ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size); 1027 if (read < 0) 1028 error = read; 1029 else if (read != info.size) 1030 error = B_ERROR; 1031 else 1032 bytesRead = read; 1033 } 1034 1035 foundData = error == B_OK; 1036 1037 // free the allocated buffer on error 1038 if (!foundData && allocatedBuffer != NULL && buffer != NULL) { 1039 free(buffer); 1040 buffer = NULL; 1041 } 1042 } 1043 1044 if (!foundData && IsUsingResources()) { 1045 // get a resource info 1046 error = B_OK; 1047 int32 idFound; 1048 size_t sizeFound; 1049 if (error == B_OK) { 1050 if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1051 error = B_ENTRY_NOT_FOUND; 1052 } 1053 1054 // check id and size, allocate a buffer, if required 1055 if (error == B_OK && id >= 0 && idFound != id) 1056 error = B_ENTRY_NOT_FOUND; 1057 if (error == B_OK && allocatedBuffer) { 1058 buffer = malloc(sizeFound); 1059 if (!buffer) 1060 error = B_NO_MEMORY; 1061 bufferSize = sizeFound; 1062 } 1063 if (error == B_OK && bufferSize < sizeFound) 1064 error = B_BAD_VALUE; 1065 1066 // load resource 1067 const void* resourceData = NULL; 1068 if (error == B_OK) { 1069 resourceData = fResources->LoadResource(type, name, &bytesRead); 1070 if (resourceData != NULL && sizeFound == bytesRead) 1071 memcpy(buffer, resourceData, bytesRead); 1072 else 1073 error = B_ERROR; 1074 } 1075 } else if (!foundData) 1076 error = B_BAD_VALUE; 1077 1078 // return the allocated buffer, or free it on error 1079 if (allocatedBuffer != NULL) { 1080 if (error == B_OK) 1081 *allocatedBuffer = buffer; 1082 else 1083 free(buffer); 1084 } 1085 1086 return error; 1087 } 1088 1089 1090 status_t 1091 BAppFileInfo::_WriteData(const char* name, int32 id, type_code type, 1092 const void* buffer, size_t bufferSize, bool findID) 1093 { 1094 if (!IsUsingAttributes() && !IsUsingResources()) 1095 return B_NO_INIT; 1096 1097 status_t error = B_OK; 1098 1099 // write to attribute 1100 if (IsUsingAttributes()) { 1101 ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize); 1102 if (written < 0) 1103 error = written; 1104 else if (written != (ssize_t)bufferSize) 1105 error = B_ERROR; 1106 } 1107 // write to resource 1108 if (IsUsingResources() && error == B_OK) { 1109 if (findID) { 1110 // get the resource info 1111 int32 idFound; 1112 size_t sizeFound; 1113 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1114 id = idFound; 1115 else { 1116 // type-name pair doesn't exist yet -- find unused ID 1117 while (fResources->HasResource(type, id)) 1118 id++; 1119 } 1120 } 1121 error = fResources->AddResource(type, id, buffer, bufferSize, name); 1122 } 1123 return error; 1124 } 1125 1126 1127 status_t 1128 BAppFileInfo::_RemoveData(const char* name, type_code type) 1129 { 1130 if (!IsUsingAttributes() && !IsUsingResources()) 1131 return B_NO_INIT; 1132 1133 status_t error = B_OK; 1134 1135 // remove the attribute 1136 if (IsUsingAttributes()) { 1137 error = fNode->RemoveAttr(name); 1138 // It's no error, if there has been no attribute. 1139 if (error == B_ENTRY_NOT_FOUND) 1140 error = B_OK; 1141 } 1142 // remove the resource 1143 if (IsUsingResources() && error == B_OK) { 1144 // get a resource info 1145 int32 idFound; 1146 size_t sizeFound; 1147 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1148 error = fResources->RemoveResource(type, idFound); 1149 } 1150 return error; 1151 } 1152