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 34enum { 35 B_APP_FLAGS_TYPE = 'APPF', 36 B_VERSION_INFO_TYPE = 'APPV', 37}; 38 39 40// attributes 41static const char* kTypeAttribute = "BEOS:TYPE"; 42static const char* kSignatureAttribute = "BEOS:APP_SIG"; 43static const char* kAppFlagsAttribute = "BEOS:APP_FLAGS"; 44static const char* kSupportedTypesAttribute = "BEOS:FILE_TYPES"; 45static const char* kVersionInfoAttribute = "BEOS:APP_VERSION"; 46static const char* kMiniIconAttribute = "BEOS:M:"; 47static const char* kLargeIconAttribute = "BEOS:L:"; 48static const char* kIconAttribute = "BEOS:"; 49static const char* kStandardIconType = "STD_ICON"; 50static const char* kIconType = "ICON"; 51static const char* kCatalogEntryAttribute = "SYS:NAME"; 52 53// resource IDs 54static const int32 kTypeResourceID = 2; 55static const int32 kSignatureResourceID = 1; 56static const int32 kAppFlagsResourceID = 1; 57static const int32 kSupportedTypesResourceID = 1; 58static const int32 kMiniIconResourceID = 101; 59static const int32 kLargeIconResourceID = 101; 60static const int32 kIconResourceID = 101; 61static const int32 kVersionInfoResourceID = 1; 62static const int32 kMiniIconForTypeResourceID = 0; 63static const int32 kLargeIconForTypeResourceID = 0; 64static const int32 kIconForTypeResourceID = 0; 65static 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) 71extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE; 72const uint32 MINI_ICON_TYPE = 'MICN'; 73const uint32 LARGE_ICON_TYPE = 'ICON'; 74 75 76BAppFileInfo::BAppFileInfo() 77 : 78 fResources(NULL), 79 fWhere(B_USE_BOTH_LOCATIONS) 80{ 81} 82 83 84BAppFileInfo::BAppFileInfo(BFile* file) 85 : 86 fResources(NULL), 87 fWhere(B_USE_BOTH_LOCATIONS) 88{ 89 SetTo(file); 90} 91 92 93BAppFileInfo::~BAppFileInfo() 94{ 95 delete fResources; 96} 97 98 99status_t 100BAppFileInfo::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 155status_t 156BAppFileInfo::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 179status_t 180BAppFileInfo::SetType(const char* type) 181{ 182 // check initialization 183 status_t error = B_OK; 184 if (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 (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 204status_t 205BAppFileInfo::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 228status_t 229BAppFileInfo::SetSignature(const char* signature) 230{ 231 // check initialization 232 status_t error = B_OK; 233 if (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 (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 253status_t 254BAppFileInfo::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 278status_t 279BAppFileInfo::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 296status_t 297BAppFileInfo::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 316status_t 317BAppFileInfo::SetAppFlags(uint32 flags) 318{ 319 // check initialization 320 status_t error = B_OK; 321 if (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 332status_t 333BAppFileInfo::RemoveAppFlags() 334{ 335 // check initialization 336 status_t error = B_OK; 337 if (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 347status_t 348BAppFileInfo::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 370status_t 371BAppFileInfo::SetSupportedTypes(const BMessage* types, bool updateMimeDB, 372 bool syncAll) 373{ 374 // check initialization 375 status_t error = B_OK; 376 if (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 435status_t 436BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll) 437{ 438 return SetSupportedTypes(types, true, syncAll); 439} 440 441 442status_t 443BAppFileInfo::SetSupportedTypes(const BMessage* types) 444{ 445 return SetSupportedTypes(types, true, false); 446} 447 448 449bool 450BAppFileInfo::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 476bool 477BAppFileInfo::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 499status_t 500BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const 501{ 502 return GetIconForType(NULL, icon, which); 503} 504 505 506status_t 507BAppFileInfo::GetIcon(uint8** data, size_t* size) const 508{ 509 return GetIconForType(NULL, data, size); 510} 511 512 513status_t 514BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB) 515{ 516 return SetIconForType(NULL, icon, which, updateMimeDB); 517} 518 519 520status_t 521BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which) 522{ 523 return SetIconForType(NULL, icon, which, true); 524} 525 526 527status_t 528BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB) 529{ 530 return SetIconForType(NULL, data, size, updateMimeDB); 531} 532 533 534status_t 535BAppFileInfo::SetIcon(const uint8* data, size_t size) 536{ 537 return SetIconForType(NULL, data, size, true); 538} 539 540 541status_t 542BAppFileInfo::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 588status_t 589BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind) 590{ 591 // check initialization 592 status_t error = B_OK; 593 if (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 641status_t 642BAppFileInfo::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 756status_t 757BAppFileInfo::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 789status_t 790BAppFileInfo::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 878status_t 879BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon, 880 icon_size which) 881{ 882 return SetIconForType(type, icon, which, true); 883} 884 885 886status_t 887BAppFileInfo::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 930status_t 931BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size) 932{ 933 return SetIconForType(type, data, size, true); 934} 935 936 937void 938BAppFileInfo::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 947bool 948BAppFileInfo::IsUsingAttributes() const 949{ 950 return (fWhere & B_USE_ATTRIBUTES) != 0; 951} 952 953 954bool 955BAppFileInfo::IsUsingResources() const 956{ 957 return (fWhere & B_USE_RESOURCES) != 0; 958} 959 960 961// FBC 962void BAppFileInfo::_ReservedAppFileInfo1() {} 963void BAppFileInfo::_ReservedAppFileInfo2() {} 964void BAppFileInfo::_ReservedAppFileInfo3() {} 965 966 967BAppFileInfo& 968BAppFileInfo::operator=(const BAppFileInfo&) 969{ 970 return *this; 971} 972 973 974BAppFileInfo::BAppFileInfo(const BAppFileInfo&) 975{ 976} 977 978 979status_t 980BAppFileInfo::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 994status_t 995BAppFileInfo::_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 1090status_t 1091BAppFileInfo::_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 1127status_t 1128BAppFileInfo::_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