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 (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 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 (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 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 (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 (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 (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 (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 #ifdef _BEOS_R5_COMPATIBLE_ 962 //! Privatized assignment operator to prevent usage. 963 BAppFileInfo& 964 BAppFileInfo::operator=(const BAppFileInfo&) 965 { 966 return *this; 967 } 968 969 970 //! Privatized copy constructor to prevent usage. 971 BAppFileInfo::BAppFileInfo(const BAppFileInfo&) 972 { 973 } 974 #endif 975 976 977 /*! Initializes a BMimeType to the signature of the associated file. 978 979 \warning The parameter \a meta is not checked. 980 981 \param meta A pointer to a pre-allocated BMimeType that shall be 982 initialized to the signature of the associated file. 983 984 \returns A status code. 985 \retval B_OK Everything went fine. 986 \retval B_BAD_VALUE \c NULL \a meta 987 \retval B_ENTRY_NOT_FOUND The file has not signature or the signature is 988 (not installed in the MIME database.) no valid MIME string. 989 */ 990 status_t 991 BAppFileInfo::GetMetaMime(BMimeType* meta) const 992 { 993 char signature[B_MIME_TYPE_LENGTH]; 994 status_t error = GetSignature(signature); 995 if (error == B_OK) 996 error = meta->SetTo(signature); 997 else if (error == B_BAD_VALUE) 998 error = B_ENTRY_NOT_FOUND; 999 if (error == B_OK && !meta->IsValid()) 1000 error = B_BAD_VALUE; 1001 return error; 1002 } 1003 1004 1005 /*! Reads data from an attribute or resource. 1006 1007 \note The data is read from the location specified by \a fWhere. 1008 1009 \warning The object must be properly initialized. The parameters are 1010 \b NOT checked. 1011 1012 \param name The name of the attribute/resource to be read. 1013 \param id The resource ID of the resource to be read. It is ignored 1014 when < 0. 1015 \param type The type of the attribute/resource to be read. 1016 \param buffer A pre-allocated buffer for the data to be read. 1017 \param bufferSize The size of the supplied buffer. 1018 \param bytesRead A reference parameter, set to the number of bytes 1019 actually read. 1020 \param allocatedBuffer If not \c NULL, the method allocates a buffer 1021 large enough too store the whole data and writes a pointer to it 1022 into this variable. If \c NULL, the supplied buffer is used. 1023 1024 \returns A status code. 1025 \retval B_OK Everything went fine. 1026 \retval B_ENTRY_NOT_FOUND The entry was not found. 1027 \retval B_NO_MEMORY Ran out of memory allocating the buffer. 1028 \retval B_BAD_VALUE \a type did not match. 1029 */ 1030 status_t 1031 BAppFileInfo::_ReadData(const char* name, int32 id, type_code type, 1032 void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer) 1033 const 1034 { 1035 status_t error = B_OK; 1036 1037 if (allocatedBuffer) 1038 buffer = NULL; 1039 1040 bool foundData = false; 1041 1042 if (IsUsingAttributes()) { 1043 // get an attribute info 1044 attr_info info; 1045 if (error == B_OK) 1046 error = fNode->GetAttrInfo(name, &info); 1047 1048 // check type and size, allocate a buffer, if required 1049 if (error == B_OK && info.type != type) 1050 error = B_BAD_VALUE; 1051 if (error == B_OK && allocatedBuffer != NULL) { 1052 buffer = malloc(info.size); 1053 if (buffer == NULL) 1054 error = B_NO_MEMORY; 1055 bufferSize = info.size; 1056 } 1057 if (error == B_OK && (off_t)bufferSize < info.size) 1058 error = B_BAD_VALUE; 1059 1060 // read the data 1061 if (error == B_OK) { 1062 ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size); 1063 if (read < 0) 1064 error = read; 1065 else if (read != info.size) 1066 error = B_ERROR; 1067 else 1068 bytesRead = read; 1069 } 1070 1071 foundData = error == B_OK; 1072 1073 // free the allocated buffer on error 1074 if (!foundData && allocatedBuffer != NULL && buffer != NULL) { 1075 free(buffer); 1076 buffer = NULL; 1077 } 1078 } 1079 1080 if (!foundData && IsUsingResources()) { 1081 // get a resource info 1082 error = B_OK; 1083 int32 idFound; 1084 size_t sizeFound; 1085 if (error == B_OK) { 1086 if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1087 error = B_ENTRY_NOT_FOUND; 1088 } 1089 1090 // check id and size, allocate a buffer, if required 1091 if (error == B_OK && id >= 0 && idFound != id) 1092 error = B_ENTRY_NOT_FOUND; 1093 if (error == B_OK && allocatedBuffer) { 1094 buffer = malloc(sizeFound); 1095 if (!buffer) 1096 error = B_NO_MEMORY; 1097 bufferSize = sizeFound; 1098 } 1099 if (error == B_OK && bufferSize < sizeFound) 1100 error = B_BAD_VALUE; 1101 1102 // load resource 1103 const void* resourceData = NULL; 1104 if (error == B_OK) { 1105 resourceData = fResources->LoadResource(type, name, &bytesRead); 1106 if (resourceData != NULL && sizeFound == bytesRead) 1107 memcpy(buffer, resourceData, bytesRead); 1108 else 1109 error = B_ERROR; 1110 } 1111 } else if (!foundData) 1112 error = B_BAD_VALUE; 1113 1114 // return the allocated buffer, or free it on error 1115 if (allocatedBuffer != NULL) { 1116 if (error == B_OK) 1117 *allocatedBuffer = buffer; 1118 else 1119 free(buffer); 1120 } 1121 1122 return error; 1123 } 1124 1125 1126 /*! Writes data to an attribute or resource. 1127 1128 \note The data is written to the location(s) specified by \a fWhere. 1129 1130 \warning The object must be properly initialized. The parameters are 1131 \b NOT checked. 1132 1133 \param name The name of the attribute/resource to be written. 1134 \param id The resource ID of the resource to be written. 1135 \param type The type of the attribute/resource to be written. 1136 \param buffer A buffer containing the data to be written. 1137 \param bufferSize The size of the supplied buffer. 1138 \param findID If set to \c true use the ID that is already assigned to the 1139 \a name / \a type pair or take the first unused ID >= \a id. 1140 If \c false, \a id is used. 1141 1142 \returns A status code. 1143 \retval B_OK Everything went fine. 1144 \retval B_ERROR An error occurred while trying to write the data. 1145 */ 1146 status_t 1147 BAppFileInfo::_WriteData(const char* name, int32 id, type_code type, 1148 const void* buffer, size_t bufferSize, bool findID) 1149 { 1150 if (!IsUsingAttributes() && !IsUsingResources()) 1151 return B_NO_INIT; 1152 1153 status_t error = B_OK; 1154 1155 // write to attribute 1156 if (IsUsingAttributes()) { 1157 ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize); 1158 if (written < 0) 1159 error = written; 1160 else if (written != (ssize_t)bufferSize) 1161 error = B_ERROR; 1162 } 1163 // write to resource 1164 if (IsUsingResources() && error == B_OK) { 1165 if (findID) { 1166 // get the resource info 1167 int32 idFound; 1168 size_t sizeFound; 1169 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1170 id = idFound; 1171 else { 1172 // type-name pair doesn't exist yet -- find unused ID 1173 while (fResources->HasResource(type, id)) 1174 id++; 1175 } 1176 } 1177 error = fResources->AddResource(type, id, buffer, bufferSize, name); 1178 } 1179 return error; 1180 } 1181 1182 1183 /*! Removes an attribute or resource. 1184 1185 \note The removal location is specified by \a fWhere. 1186 1187 \warning The object must be properly initialized. The parameters are 1188 \b NOT checked. 1189 1190 \param name The name of the attribute/resource to be remove. 1191 \param type The type of the attribute/resource to be removed. 1192 1193 \returns A status code. 1194 \retval B_OK Everything went fine. 1195 \retval B_NO_INIT Not using attributes and not using resources. 1196 \retval B_ENTRY_NOT_FOUND The attribute or resource was not found. 1197 */ 1198 status_t 1199 BAppFileInfo::_RemoveData(const char* name, type_code type) 1200 { 1201 if (!IsUsingAttributes() && !IsUsingResources()) 1202 return B_NO_INIT; 1203 1204 status_t error = B_OK; 1205 1206 // remove the attribute 1207 if (IsUsingAttributes()) { 1208 error = fNode->RemoveAttr(name); 1209 // It's no error, if there has been no attribute. 1210 if (error == B_ENTRY_NOT_FOUND) 1211 error = B_OK; 1212 } 1213 // remove the resource 1214 if (IsUsingResources() && error == B_OK) { 1215 // get a resource info 1216 int32 idFound; 1217 size_t sizeFound; 1218 if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound)) 1219 error = fResources->RemoveResource(type, idFound); 1220 } 1221 return error; 1222 } 1223