1/* 2 * Copyright 2002-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7/*! 8 \file ResourceFile.cpp 9 ResourceFile implementation. 10*/ 11 12 13#include <ResourceFile.h> 14 15#include <algorithm> 16#include <new> 17#include <stdio.h> 18 19#include <elf32.h> 20#include <elf64.h> 21#include <fatelf.h> 22 23#include <AutoDeleter.h> 24 25#include <Exception.h> 26#include <Pef.h> 27#include <ResourceItem.h> 28#include <ResourcesContainer.h> 29#include <ResourcesDefs.h> 30//#include <Warnings.h> 31 32 33namespace BPrivate { 34namespace Storage { 35 36 37// ELF defs 38static const uint32 kMaxELFHeaderSize 39 = std::max(sizeof(Elf32_Ehdr), sizeof(Elf64_Ehdr)) + 32; 40 41// sanity bounds 42static const uint32 kMaxResourceCount = 10000; 43static const uint32 kELFMaxResourceAlignment = 1024 * 1024 * 10; // 10 MB 44 45 46// recognized file types (indices into kFileTypeNames) 47enum { 48 FILE_TYPE_UNKNOWN = 0, 49 FILE_TYPE_X86_RESOURCE = 1, 50 FILE_TYPE_PPC_RESOURCE = 2, 51 FILE_TYPE_ELF = 3, 52 FILE_TYPE_FATELF = 4, 53 FILE_TYPE_PEF = 5, 54 FILE_TYPE_EMPTY = 6, 55}; 56 57 58const char* kFileTypeNames[] = { 59 "unknown", 60 "x86 resource file", 61 "PPC resource file", 62 "ELF object file", 63 "FatELF object file", 64 "PEF object file", 65 "empty file", 66}; 67 68 69// debugging 70//#define DBG(x) x 71#define DBG(x) 72#define OUT printf 73 74 75// #pragma mark - helper functions/classes 76 77 78static void 79read_exactly(BPositionIO& file, off_t position, void* buffer, size_t size, 80 const char* errorMessage = NULL) 81{ 82 ssize_t read = file.ReadAt(position, buffer, size); 83 if (read < 0) 84 throw Exception(read, errorMessage); 85 else if ((size_t)read != size) { 86 if (errorMessage) { 87 throw Exception("%s Read too few bytes (%ld/%lu).", errorMessage, 88 read, size); 89 } else 90 throw Exception("Read too few bytes (%ld/%lu).", read, size); 91 } 92} 93 94 95static void 96write_exactly(BPositionIO& file, off_t position, const void* buffer, 97 size_t size, const char* errorMessage = NULL) 98{ 99 ssize_t written = file.WriteAt(position, buffer, size); 100 if (written < 0) 101 throw Exception(written, errorMessage); 102 else if ((size_t)written != size) { 103 if (errorMessage) { 104 throw Exception("%s Wrote too few bytes (%ld/%lu).", errorMessage, 105 written, size); 106 } else 107 throw Exception("Wrote too few bytes (%ld/%lu).", written, size); 108 } 109} 110 111 112template<typename TV, typename TA> 113static inline TV 114align_value(const TV& value, const TA& alignment) 115{ 116 return ((value + alignment - 1) / alignment) * alignment; 117} 118 119 120static uint32 121calculate_checksum(const void* data, uint32 size) 122{ 123 uint32 checkSum = 0; 124 const uint8* csData = (const uint8*)data; 125 const uint8* dataEnd = csData + size; 126 const uint8* current = csData; 127 for (; current < dataEnd; current += 4) { 128 uint32 word = 0; 129 int32 bytes = std::min((int32)4, (int32)(dataEnd - current)); 130 for (int32 i = 0; i < bytes; i++) 131 word = (word << 8) + current[i]; 132 checkSum += word; 133 } 134 return checkSum; 135} 136 137 138static inline const void* 139skip_bytes(const void* buffer, int32 offset) 140{ 141 return (const char*)buffer + offset; 142} 143 144 145static inline void* 146skip_bytes(void* buffer, int32 offset) 147{ 148 return (char*)buffer + offset; 149} 150 151 152static void 153fill_pattern(uint32 byteOffset, void* _buffer, uint32 count) 154{ 155 uint32* buffer = (uint32*)_buffer; 156 for (uint32 i = 0; i < count; i++) 157 buffer[i] = kUnusedResourceDataPattern[(byteOffset / 4 + i) % 3]; 158} 159 160 161static void 162fill_pattern(const void* dataBegin, void* buffer, uint32 count) 163{ 164 fill_pattern((char*)buffer - (const char*)dataBegin, buffer, count); 165} 166 167 168static void 169fill_pattern(const void* dataBegin, void* buffer, const void* bufferEnd) 170{ 171 fill_pattern(dataBegin, buffer, 172 ((const char*)bufferEnd - (char*)buffer) / 4); 173} 174 175 176static bool 177check_pattern(uint32 byteOffset, void* _buffer, uint32 count, 178 bool hostEndianess) 179{ 180 bool result = true; 181 uint32* buffer = (uint32*)_buffer; 182 for (uint32 i = 0; result && i < count; i++) { 183 uint32 value = buffer[i]; 184 if (!hostEndianess) 185 value = B_SWAP_INT32(value); 186 result 187 = (value == kUnusedResourceDataPattern[(byteOffset / 4 + i) % 3]); 188 } 189 return result; 190} 191 192 193// #pragma mark - 194 195 196struct MemArea { 197 MemArea(const void* data, uint32 size) : data(data), size(size) {} 198 199 inline bool check(const void* _current, uint32 skip = 0) const 200 { 201 const char* start = (const char*)data; 202 const char* current = (const char*)_current; 203 return (start <= current && start + size >= current + skip); 204 } 205 206 const void* data; 207 uint32 size; 208}; 209 210 211struct resource_parse_info { 212 off_t file_size; 213 int32 resource_count; 214 ResourcesContainer* container; 215 char* info_table; 216 uint32 info_table_offset; 217 uint32 info_table_size; 218}; 219 220 221// #pragma mark - 222 223 224ResourceFile::ResourceFile() 225 : 226 fFile(), 227 fFileType(FILE_TYPE_UNKNOWN), 228 fHostEndianess(true), 229 fEmptyResources(true) 230{ 231} 232 233 234ResourceFile::~ResourceFile() 235{ 236 Unset(); 237} 238 239 240status_t 241ResourceFile::SetTo(BFile* file, bool clobber) 242{ 243 status_t error = (file ? B_OK : B_BAD_VALUE); 244 Unset(); 245 if (error == B_OK) { 246 try { 247 _InitFile(*file, clobber); 248 } catch (Exception exception) { 249 Unset(); 250 if (exception.Error() != B_OK) 251 error = exception.Error(); 252 else 253 error = B_ERROR; 254 } 255 } 256 return error; 257} 258 259 260void 261ResourceFile::Unset() 262{ 263 fFile.Unset(); 264 fFileType = FILE_TYPE_UNKNOWN; 265 fHostEndianess = true; 266 fEmptyResources = true; 267} 268 269 270status_t 271ResourceFile::InitCheck() const 272{ 273 return fFile.InitCheck(); 274} 275 276 277status_t 278ResourceFile::InitContainer(ResourcesContainer& container) 279{ 280 container.MakeEmpty(); 281 status_t error = InitCheck(); 282 if (error == B_OK && !fEmptyResources) { 283 resource_parse_info parseInfo; 284 parseInfo.file_size = 0; 285 parseInfo.resource_count = 0; 286 parseInfo.container = &container; 287 parseInfo.info_table = NULL; 288 parseInfo.info_table_offset = 0; 289 parseInfo.info_table_size = 0; 290 try { 291 // get the file size 292 error = fFile.GetSize(&parseInfo.file_size); 293 if (error != B_OK) 294 throw Exception(error, "Failed to get the file size."); 295 _ReadHeader(parseInfo); 296 _ReadIndex(parseInfo); 297 _ReadInfoTable(parseInfo); 298 container.SetModified(false); 299 } catch (Exception exception) { 300 if (exception.Error() != B_OK) 301 error = exception.Error(); 302 else 303 error = B_ERROR; 304 } 305 delete[] parseInfo.info_table; 306 } 307 return error; 308} 309 310 311status_t 312ResourceFile::ReadResource(ResourceItem& resource, bool force) 313{ 314 status_t error = InitCheck(); 315 size_t size = resource.DataSize(); 316 if (error == B_OK && (force || !resource.IsLoaded())) { 317 if (error == B_OK) 318 error = resource.SetSize(size); 319 void* data = NULL; 320 if (error == B_OK) { 321 data = resource.Data(); 322 ssize_t bytesRead = fFile.ReadAt(resource.Offset(), data, size); 323 if (bytesRead < 0) 324 error = bytesRead; 325 else if ((size_t)bytesRead != size) 326 error = B_IO_ERROR; 327 } 328 if (error == B_OK) { 329 // convert the data, if necessary 330 if (!fHostEndianess) 331 swap_data(resource.Type(), data, size, B_SWAP_ALWAYS); 332 resource.SetLoaded(true); 333 resource.SetModified(false); 334 } 335 } 336 return error; 337} 338 339 340status_t 341ResourceFile::ReadResources(ResourcesContainer& container, bool force) 342{ 343 status_t error = InitCheck(); 344 int32 count = container.CountResources(); 345 for (int32 i = 0; error == B_OK && i < count; i++) { 346 if (ResourceItem* resource = container.ResourceAt(i)) 347 error = ReadResource(*resource, force); 348 else 349 error = B_ERROR; 350 } 351 return error; 352} 353 354 355status_t 356ResourceFile::WriteResources(ResourcesContainer& container) 357{ 358 status_t error = InitCheck(); 359 if (error == B_OK && !fFile.File()->IsWritable()) 360 error = B_NOT_ALLOWED; 361 if (error == B_OK && fFileType == FILE_TYPE_EMPTY) 362 error = _MakeEmptyResourceFile(); 363 if (error == B_OK) 364 error = _WriteResources(container); 365 if (error == B_OK) 366 fEmptyResources = false; 367 return error; 368} 369 370 371void 372ResourceFile::_InitFile(BFile& file, bool clobber) 373{ 374 status_t error = B_OK; 375 fFile.Unset(); 376 // get the file size first 377 off_t fileSize = 0; 378 error = file.GetSize(&fileSize); 379 if (error != B_OK) 380 throw Exception(error, "Failed to get the file size."); 381 // read the first four bytes, and check, if they identify a resource file 382 uint32 magic; 383 if (fileSize >= 4) 384 read_exactly(file, 0, &magic, 4, "Failed to read magic number."); 385 else if (fileSize > 0 && !clobber) 386 throw Exception(B_IO_ERROR, "File is not a resource file."); 387 if (fileSize == 0) { 388 // empty file 389 fHostEndianess = true; 390 fFileType = FILE_TYPE_EMPTY; 391 fFile.SetTo(&file, 0); 392 fEmptyResources = true; 393 } else if (!memcmp(&magic, kX86ResourceFileMagic, 4)) { 394 // x86 resource file 395 fHostEndianess = B_HOST_IS_LENDIAN; 396 fFileType = FILE_TYPE_X86_RESOURCE; 397 fFile.SetTo(&file, kX86ResourcesOffset); 398 fEmptyResources = false; 399 } else if (!memcmp(&magic, kPEFFileMagic1, 4)) { 400 PEFContainerHeader pefHeader; 401 read_exactly(file, 0, &pefHeader, kPEFContainerHeaderSize, 402 "Failed to read PEF container header."); 403 if (!memcmp(pefHeader.tag2, kPPCResourceFileMagic, 4)) { 404 // PPC resource file 405 fHostEndianess = B_HOST_IS_BENDIAN; 406 fFileType = FILE_TYPE_PPC_RESOURCE; 407 fFile.SetTo(&file, kPPCResourcesOffset); 408 fEmptyResources = false; 409 } else if (!memcmp(pefHeader.tag2, kPEFFileMagic2, 4)) { 410 // PEF file 411 fFileType = FILE_TYPE_PEF; 412 _InitPEFFile(file, pefHeader); 413 } else 414 throw Exception(B_IO_ERROR, "File is not a resource file."); 415 } else if (!memcmp(&magic, ELF_MAGIC, 4)) { 416 // ELF file 417 fFileType = FILE_TYPE_ELF; 418 _InitELFFile(file); 419 } else if (B_LENDIAN_TO_HOST_INT32(magic) == FATELF_MAGIC) { 420 fFileType = FILE_TYPE_FATELF; 421 _InitFatELFFile(file); 422 } else if (!memcmp(&magic, kX86ResourceFileMagic, 2)) { 423 // x86 resource file with screwed magic? 424// Warnings::AddCurrentWarning("File magic is 0x%08lx. Should be 0x%08lx " 425// "for x86 resource file. Try anyway.", 426// ntohl(*(uint32*)magic), 427// ntohl(*(uint32*)kX86ResourceFileMagic)); 428 fHostEndianess = B_HOST_IS_LENDIAN; 429 fFileType = FILE_TYPE_X86_RESOURCE; 430 fFile.SetTo(&file, kX86ResourcesOffset); 431 fEmptyResources = true; 432 } else { 433 if (clobber) { 434 // make it an x86 resource file 435 fHostEndianess = true; 436 fFileType = FILE_TYPE_EMPTY; 437 fFile.SetTo(&file, 0); 438 } else 439 throw Exception(B_IO_ERROR, "File is not a resource file."); 440 } 441 error = fFile.InitCheck(); 442 if (error != B_OK) 443 throw Exception(error, "Failed to initialize resource file."); 444 // clobber, if desired 445 if (clobber) { 446 // just write an empty resources container 447 ResourcesContainer container; 448 WriteResources(container); 449 } 450} 451 452 453void 454ResourceFile::_InitELFFile(BFile& file) 455{ 456 status_t error = B_OK; 457 458 // get the file size 459 off_t fileSize = 0; 460 error = file.GetSize(&fileSize); 461 if (error != B_OK) 462 throw Exception(error, "Failed to get the file size."); 463 464 // read the ELF headers e_ident field 465 unsigned char identification[EI_NIDENT]; 466 read_exactly(file, 0, identification, EI_NIDENT, 467 "Failed to read ELF identification."); 468 469 // check version 470 if (identification[EI_VERSION] != EV_CURRENT) 471 throw Exception(B_UNSUPPORTED, "Unsupported ELF version."); 472 473 // check data encoding (endianess) 474 switch (identification[EI_DATA]) { 475 case ELFDATA2LSB: 476 fHostEndianess = B_HOST_IS_LENDIAN; 477 break; 478 case ELFDATA2MSB: 479 fHostEndianess = B_HOST_IS_BENDIAN; 480 break; 481 default: 482 case ELFDATANONE: 483 throw Exception(B_UNSUPPORTED, "Unsupported ELF data encoding."); 484 } 485 486 // check class (32/64 bit) and call the respective method handling it 487 switch (identification[EI_CLASS]) { 488 case ELFCLASS32: 489 _InitELFXFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(file, fileSize); 490 break; 491 case ELFCLASS64: 492 _InitELFXFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(file, fileSize); 493 break; 494 default: 495 throw Exception(B_UNSUPPORTED, "Unsupported ELF class."); 496 } 497} 498 499 500template<typename ElfHeader, typename ElfProgramHeader, 501 typename ElfSectionHeader> 502void 503ResourceFile::_InitELFXFile(BFile& file, uint64 fileSize) 504{ 505 // read ELF header 506 ElfHeader fileHeader; 507 read_exactly(file, 0, &fileHeader, sizeof(ElfHeader), 508 "Failed to read ELF header."); 509 510 // get the header values 511 uint32 headerSize = _GetInt(fileHeader.e_ehsize); 512 uint64 programHeaderTableOffset = _GetInt(fileHeader.e_phoff); 513 uint32 programHeaderSize = _GetInt(fileHeader.e_phentsize); 514 uint32 programHeaderCount = _GetInt(fileHeader.e_phnum); 515 uint64 sectionHeaderTableOffset = _GetInt(fileHeader.e_shoff); 516 uint32 sectionHeaderSize = _GetInt(fileHeader.e_shentsize); 517 uint32 sectionHeaderCount = _GetInt(fileHeader.e_shnum); 518 bool hasProgramHeaderTable = (programHeaderTableOffset != 0); 519 bool hasSectionHeaderTable = (sectionHeaderTableOffset != 0); 520 521 // check the sanity of the header values 522 // ELF header size 523 if (headerSize < sizeof(ElfHeader) || headerSize > kMaxELFHeaderSize) { 524 throw Exception(B_IO_ERROR, 525 "Invalid ELF header: invalid ELF header size: %lu.", headerSize); 526 } 527 uint64 resourceOffset = headerSize; 528 uint64 resourceAlignment = 0; 529 530 // program header table offset and entry count/size 531 uint64 programHeaderTableSize = 0; 532 if (hasProgramHeaderTable) { 533 if (programHeaderTableOffset < headerSize 534 || programHeaderTableOffset > fileSize) { 535 throw Exception(B_IO_ERROR, "Invalid ELF header: invalid program " 536 "header table offset: %lu.", programHeaderTableOffset); 537 } 538 programHeaderTableSize = (uint64)programHeaderSize * programHeaderCount; 539 if (programHeaderSize < sizeof(ElfProgramHeader) 540 || programHeaderTableOffset + programHeaderTableSize > fileSize) { 541 throw Exception(B_IO_ERROR, "Invalid ELF header: program header " 542 "table exceeds file: %lu.", 543 programHeaderTableOffset + programHeaderTableSize); 544 } 545 resourceOffset = std::max(resourceOffset, 546 programHeaderTableOffset + programHeaderTableSize); 547 548 // load the program headers into memory 549 uint8* programHeaders = (uint8*)malloc( 550 programHeaderCount * programHeaderSize); 551 if (programHeaders == NULL) 552 throw Exception(B_NO_MEMORY); 553 MemoryDeleter programHeadersDeleter(programHeaders); 554 555 read_exactly(file, programHeaderTableOffset, programHeaders, 556 programHeaderCount * programHeaderSize, 557 "Failed to read ELF program headers."); 558 559 // iterate through the program headers 560 for (uint32 i = 0; i < programHeaderCount; i++) { 561 ElfProgramHeader& programHeader 562 = *(ElfProgramHeader*)(programHeaders + i * programHeaderSize); 563 564 // get the header values 565 uint32 type = _GetInt(programHeader.p_type); 566 uint64 offset = _GetInt(programHeader.p_offset); 567 uint64 size = _GetInt(programHeader.p_filesz); 568 uint64 alignment = _GetInt(programHeader.p_align); 569 570 // check the values 571 // PT_NULL marks the header unused, 572 if (type != PT_NULL) { 573 if (/*offset < headerSize ||*/ offset > fileSize) { 574 throw Exception(B_IO_ERROR, "Invalid ELF program header: " 575 "invalid program offset: %lu.", offset); 576 } 577 uint64 segmentEnd = offset + size; 578 if (segmentEnd > fileSize) { 579 throw Exception(B_IO_ERROR, "Invalid ELF section header: " 580 "segment exceeds file: %lu.", segmentEnd); 581 } 582 resourceOffset = std::max(resourceOffset, segmentEnd); 583 resourceAlignment = std::max(resourceAlignment, alignment); 584 } 585 } 586 } 587 588 // section header table offset and entry count/size 589 uint64 sectionHeaderTableSize = 0; 590 if (hasSectionHeaderTable) { 591 if (sectionHeaderTableOffset < headerSize 592 || sectionHeaderTableOffset > fileSize) { 593 throw Exception(B_IO_ERROR, "Invalid ELF header: invalid section " 594 "header table offset: %lu.", sectionHeaderTableOffset); 595 } 596 sectionHeaderTableSize = (uint64)sectionHeaderSize * sectionHeaderCount; 597 if (sectionHeaderSize < sizeof(ElfSectionHeader) 598 || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) { 599 throw Exception(B_IO_ERROR, "Invalid ELF header: section header " 600 "table exceeds file: %lu.", 601 sectionHeaderTableOffset + sectionHeaderTableSize); 602 } 603 resourceOffset = std::max(resourceOffset, 604 sectionHeaderTableOffset + sectionHeaderTableSize); 605 606 // load the section headers into memory 607 uint8* sectionHeaders = (uint8*)malloc( 608 sectionHeaderCount * sectionHeaderSize); 609 if (sectionHeaders == NULL) 610 throw Exception(B_NO_MEMORY); 611 MemoryDeleter sectionHeadersDeleter(sectionHeaders); 612 613 read_exactly(file, sectionHeaderTableOffset, sectionHeaders, 614 sectionHeaderCount * sectionHeaderSize, 615 "Failed to read ELF section headers."); 616 617 // iterate through the section headers 618 for (uint32 i = 0; i < sectionHeaderCount; i++) { 619 ElfSectionHeader& sectionHeader 620 = *(ElfSectionHeader*)(sectionHeaders + i * sectionHeaderSize); 621 622 // get the header values 623 uint32 type = _GetInt(sectionHeader.sh_type); 624 uint64 offset = _GetInt(sectionHeader.sh_offset); 625 uint64 size = _GetInt(sectionHeader.sh_size); 626 627 // check the values 628 // SHT_NULL marks the header unused, 629 // SHT_NOBITS sections take no space in the file 630 if (type != SHT_NULL && type != SHT_NOBITS) { 631 if (offset < headerSize || offset > fileSize) { 632 throw Exception(B_IO_ERROR, "Invalid ELF section header: " 633 "invalid section offset: %lu.", offset); 634 } 635 uint64 sectionEnd = offset + size; 636 if (sectionEnd > fileSize) { 637 throw Exception(B_IO_ERROR, "Invalid ELF section header: " 638 "section exceeds file: %lu.", sectionEnd); 639 } 640 resourceOffset = std::max(resourceOffset, sectionEnd); 641 } 642 } 643 } 644 645 // align the offset 646 if (fileHeader.e_ident[EI_CLASS] == ELFCLASS64) { 647 // For ELF64 binaries we use a different alignment behaviour. It is 648 // not necessary to align the position of the resources in the file to 649 // the maximum value of p_align, and in fact on x86_64 this behaviour 650 // causes an undesirable effect: since the default segment alignment is 651 // 2MB, aligning to p_align causes all binaries to be at least 2MB when 652 // resources have been added. So, just align to an 8-byte boundary. 653 resourceAlignment = 8; 654 } else { 655 // Retain previous alignment behaviour for compatibility. 656 if (resourceAlignment < kELFMinResourceAlignment) 657 resourceAlignment = kELFMinResourceAlignment; 658 if (resourceAlignment > kELFMaxResourceAlignment) { 659 throw Exception(B_IO_ERROR, "The ELF object file requires an " 660 "invalid alignment: %lu.", resourceAlignment); 661 } 662 } 663 664 resourceOffset = align_value(resourceOffset, resourceAlignment); 665 if (resourceOffset >= fileSize) { 666// throw Exception("The ELF object file does not contain resources."); 667 fEmptyResources = true; 668 } else 669 fEmptyResources = false; 670 671 // fine, init the offset file 672 fFile.SetTo(&file, resourceOffset); 673} 674 675 676void 677ResourceFile::_InitFatELFFile(BFile& file) 678{ 679 // get the file size 680 off_t fileSize = 0; 681 status_t error = file.GetSize(&fileSize); 682 if (error != B_OK) 683 throw Exception(error, "Failed to get the file size."); 684 685 // read FatELF header 686 FATELF_header fileHeader; 687 read_exactly(file, 0, &fileHeader, sizeof(fileHeader), 688 "Failed to read FatELF header."); 689 690 // read FatELF records 691 FATELF_record* records = (FATELF_record*)malloc( 692 fileHeader.num_records * sizeof(FATELF_record)); 693 694 if (records == NULL) 695 throw Exception(B_NO_MEMORY); 696 MemoryDeleter recordsDeleter(records); 697 698 read_exactly(file, sizeof(FATELF_header), records, 699 fileHeader.num_records * sizeof(FATELF_record), 700 "Failed to read FatELF records."); 701 702 // find furthest entry 703 uint64 resourceOffset = 0; 704 for (uint8 i = 0; i < fileHeader.num_records; i++) { 705 FATELF_record *record = records + i; 706 uint64 elfEnd = B_LENDIAN_TO_HOST_INT64(record->offset) + 707 B_LENDIAN_TO_HOST_INT64(record->size); 708 resourceOffset = std::max(resourceOffset, elfEnd); 709 } 710 711 712 resourceOffset = align_value(resourceOffset, kFatELFMinResourceAlignment); 713 if (resourceOffset >= (uint64) fileSize) 714 fEmptyResources = true; 715 else 716 fEmptyResources = false; 717 718 fFile.SetTo(&file, resourceOffset); 719} 720 721 722void 723ResourceFile::_InitPEFFile(BFile& file, const PEFContainerHeader& pefHeader) 724{ 725 status_t error = B_OK; 726 // get the file size 727 off_t fileSize = 0; 728 error = file.GetSize(&fileSize); 729 if (error != B_OK) 730 throw Exception(error, "Failed to get the file size."); 731 // check architecture -- we support PPC only 732 if (memcmp(pefHeader.architecture, kPEFArchitecturePPC, 4)) 733 throw Exception(B_IO_ERROR, "PEF file architecture is not PPC."); 734 fHostEndianess = B_HOST_IS_BENDIAN; 735 // get the section count 736 uint16 sectionCount = _GetInt(pefHeader.sectionCount); 737 // iterate through the PEF sections headers 738 uint32 sectionHeaderTableOffset = kPEFContainerHeaderSize; 739 uint32 sectionHeaderTableEnd 740 = sectionHeaderTableOffset + sectionCount * kPEFSectionHeaderSize; 741 uint32 resourceOffset = sectionHeaderTableEnd; 742 for (int32 i = 0; i < (int32)sectionCount; i++) { 743 uint32 shOffset = sectionHeaderTableOffset + i * kPEFSectionHeaderSize; 744 PEFSectionHeader sectionHeader; 745 read_exactly(file, shOffset, §ionHeader, kPEFSectionHeaderSize, 746 "Failed to read PEF section header."); 747 // get the header values 748 uint32 offset = _GetInt(sectionHeader.containerOffset); 749 uint32 size = _GetInt(sectionHeader.packedSize); 750 // check the values 751 if (offset < sectionHeaderTableEnd || offset > fileSize) { 752 throw Exception(B_IO_ERROR, "Invalid PEF section header: invalid " 753 "section offset: %lu.", offset); 754 } 755 uint32 sectionEnd = offset + size; 756 if (sectionEnd > fileSize) { 757 throw Exception(B_IO_ERROR, "Invalid PEF section header: section " 758 "exceeds file: %lu.", sectionEnd); 759 } 760 resourceOffset = std::max(resourceOffset, sectionEnd); 761 } 762 if (resourceOffset >= fileSize) { 763// throw Exception("The PEF object file does not contain resources."); 764 fEmptyResources = true; 765 } else 766 fEmptyResources = false; 767 // init the offset file 768 fFile.SetTo(&file, resourceOffset); 769} 770 771 772void 773ResourceFile::_ReadHeader(resource_parse_info& parseInfo) 774{ 775 // read the header 776 resources_header header; 777 read_exactly(fFile, 0, &header, kResourcesHeaderSize, 778 "Failed to read the header."); 779 // check the header 780 // magic 781 uint32 magic = _GetInt(header.rh_resources_magic); 782 if (magic == kResourcesHeaderMagic) { 783 // everything is fine 784 } else if (B_SWAP_INT32(magic) == kResourcesHeaderMagic) { 785// const char* endianessStr[2] = { "little", "big" }; 786// int32 endianess 787// = (fHostEndianess == ((bool)B_HOST_IS_LENDIAN ? 0 : 1)); 788// Warnings::AddCurrentWarning("Endianess seems to be %s, although %s " 789// "was expected.", 790// endianessStr[1 - endianess], 791// endianessStr[endianess]); 792 fHostEndianess = !fHostEndianess; 793 } else 794 throw Exception(B_IO_ERROR, "Invalid resources header magic."); 795 // resource count 796 uint32 resourceCount = _GetInt(header.rh_resource_count); 797 if (resourceCount > kMaxResourceCount) 798 throw Exception(B_IO_ERROR, "Bad number of resources."); 799 // index section offset 800 uint32 indexSectionOffset = _GetInt(header.rh_index_section_offset); 801 if (indexSectionOffset != kResourceIndexSectionOffset) { 802 throw Exception(B_IO_ERROR, "Unexpected resource index section " 803 "offset. Is: %lu, should be: %lu.", indexSectionOffset, 804 kResourceIndexSectionOffset); 805 } 806 // admin section size 807 uint32 indexSectionSize = kResourceIndexSectionHeaderSize 808 + kResourceIndexEntrySize * resourceCount; 809 indexSectionSize = align_value(indexSectionSize, 810 kResourceIndexSectionAlignment); 811 uint32 adminSectionSize = _GetInt(header.rh_admin_section_size); 812 if (adminSectionSize != indexSectionOffset + indexSectionSize) { 813 throw Exception(B_IO_ERROR, "Unexpected resource admin section size. " 814 "Is: %lu, should be: %lu.", adminSectionSize, 815 indexSectionOffset + indexSectionSize); 816 } 817 // set the resource count 818 parseInfo.resource_count = resourceCount; 819} 820 821 822void 823ResourceFile::_ReadIndex(resource_parse_info& parseInfo) 824{ 825 int32& resourceCount = parseInfo.resource_count; 826 off_t& fileSize = parseInfo.file_size; 827 // read the header 828 resource_index_section_header header; 829 read_exactly(fFile, kResourceIndexSectionOffset, &header, 830 kResourceIndexSectionHeaderSize, 831 "Failed to read the resource index section header."); 832 // check the header 833 // index section offset 834 uint32 indexSectionOffset = _GetInt(header.rish_index_section_offset); 835 if (indexSectionOffset != kResourceIndexSectionOffset) { 836 throw Exception(B_IO_ERROR, "Unexpected resource index section " 837 "offset. Is: %lu, should be: %lu.", indexSectionOffset, 838 kResourceIndexSectionOffset); 839 } 840 // index section size 841 uint32 expectedIndexSectionSize = kResourceIndexSectionHeaderSize 842 + kResourceIndexEntrySize * resourceCount; 843 expectedIndexSectionSize = align_value(expectedIndexSectionSize, 844 kResourceIndexSectionAlignment); 845 uint32 indexSectionSize = _GetInt(header.rish_index_section_size); 846 if (indexSectionSize != expectedIndexSectionSize) { 847 throw Exception(B_IO_ERROR, "Unexpected resource index section size. " 848 "Is: %lu, should be: %lu.", indexSectionSize, 849 expectedIndexSectionSize); 850 } 851 // unknown section offset 852 uint32 unknownSectionOffset 853 = _GetInt(header.rish_unknown_section_offset); 854 if (unknownSectionOffset != indexSectionOffset + indexSectionSize) { 855 throw Exception(B_IO_ERROR, "Unexpected resource index section size. " 856 "Is: %lu, should be: %lu.", unknownSectionOffset, 857 indexSectionOffset + indexSectionSize); 858 } 859 // unknown section size 860 uint32 unknownSectionSize = _GetInt(header.rish_unknown_section_size); 861 if (unknownSectionSize != kUnknownResourceSectionSize) { 862 throw Exception(B_IO_ERROR, "Unexpected resource index section " 863 "offset. Is: %lu, should be: %lu.", 864 unknownSectionOffset, kUnknownResourceSectionSize); 865 } 866 // info table offset and size 867 uint32 infoTableOffset = _GetInt(header.rish_info_table_offset); 868 uint32 infoTableSize = _GetInt(header.rish_info_table_size); 869 if (infoTableOffset + infoTableSize > fileSize) 870 throw Exception(B_IO_ERROR, "Invalid info table location."); 871 parseInfo.info_table_offset = infoTableOffset; 872 parseInfo.info_table_size = infoTableSize; 873 // read the index entries 874 uint32 indexTableOffset = indexSectionOffset 875 + kResourceIndexSectionHeaderSize; 876 int32 maxResourceCount = (unknownSectionOffset - indexTableOffset) 877 / kResourceIndexEntrySize; 878 int32 actualResourceCount = 0; 879 bool tableEndReached = false; 880 for (int32 i = 0; !tableEndReached && i < maxResourceCount; i++) { 881 // read one entry 882 tableEndReached = !_ReadIndexEntry(parseInfo, i, indexTableOffset, 883 (i >= resourceCount)); 884 if (!tableEndReached) 885 actualResourceCount++; 886 } 887 // check resource count 888 if (actualResourceCount != resourceCount) { 889 if (actualResourceCount > resourceCount) { 890// Warnings::AddCurrentWarning("Resource index table contains " 891// "%ld entries, although it should be " 892// "%ld only.", actualResourceCount, 893// resourceCount); 894 } 895 resourceCount = actualResourceCount; 896 } 897} 898 899 900bool 901ResourceFile::_ReadIndexEntry(resource_parse_info& parseInfo, int32 index, 902 uint32 tableOffset, bool peekAhead) 903{ 904 off_t& fileSize = parseInfo.file_size; 905 // 906 bool result = true; 907 resource_index_entry entry; 908 // read one entry 909 off_t entryOffset = tableOffset + index * kResourceIndexEntrySize; 910 read_exactly(fFile, entryOffset, &entry, kResourceIndexEntrySize, 911 "Failed to read a resource index entry."); 912 // check, if the end is reached early 913 if (result && check_pattern(entryOffset, &entry, 914 kResourceIndexEntrySize / 4, fHostEndianess)) { 915 if (!peekAhead) { 916// Warnings::AddCurrentWarning("Unexpected end of resource index " 917// "table at index: %ld (/%ld).", 918// index + 1, resourceCount); 919 } 920 result = false; 921 } 922 uint32 offset = _GetInt(entry.rie_offset); 923 uint32 size = _GetInt(entry.rie_size); 924 // check the location 925 if (result && offset + size > fileSize) { 926 if (peekAhead) { 927// Warnings::AddCurrentWarning("Invalid data after resource index " 928// "table."); 929 } else { 930 throw Exception(B_IO_ERROR, "Invalid resource index entry: index: " 931 "%ld, offset: %lu (%lx), size: %lu (%lx).", index + 1, offset, 932 offset, size, size); 933 } 934 result = false; 935 } 936 // add the entry 937 if (result) { 938 ResourceItem* item = new(std::nothrow) ResourceItem; 939 if (!item) 940 throw Exception(B_NO_MEMORY); 941 item->SetLocation(offset, size); 942 if (!parseInfo.container->AddResource(item, index, false)) { 943 delete item; 944 throw Exception(B_NO_MEMORY); 945 } 946 } 947 return result; 948} 949 950 951void 952ResourceFile::_ReadInfoTable(resource_parse_info& parseInfo) 953{ 954 int32& resourceCount = parseInfo.resource_count; 955 // read the info table 956 // alloc memory for the table 957 char* tableData = new(std::nothrow) char[parseInfo.info_table_size]; 958 if (!tableData) 959 throw Exception(B_NO_MEMORY); 960 int32 dataSize = parseInfo.info_table_size; 961 parseInfo.info_table = tableData; // freed by the info owner 962 read_exactly(fFile, parseInfo.info_table_offset, tableData, dataSize, 963 "Failed to read resource info table."); 964 // 965 bool* readIndices = new(std::nothrow) bool[resourceCount + 1]; 966 // + 1 => always > 0 967 if (!readIndices) 968 throw Exception(B_NO_MEMORY); 969 ArrayDeleter<bool> readIndicesDeleter(readIndices); 970 for (int32 i = 0; i < resourceCount; i++) 971 readIndices[i] = false; 972 MemArea area(tableData, dataSize); 973 const void* data = tableData; 974 // check the table end/check sum 975 if (_ReadInfoTableEnd(data, dataSize)) 976 dataSize -= kResourceInfoTableEndSize; 977 // read the infos 978 int32 resourceIndex = 1; 979 uint32 minRemainderSize 980 = kMinResourceInfoBlockSize + kResourceInfoSeparatorSize; 981 while (area.check(data, minRemainderSize)) { 982 // read a resource block 983 if (!area.check(data, kMinResourceInfoBlockSize)) { 984 throw Exception(B_IO_ERROR, "Unexpected end of resource info " 985 "table at index %ld.", resourceIndex); 986 } 987 const resource_info_block* infoBlock 988 = (const resource_info_block*)data; 989 type_code type = _GetInt(infoBlock->rib_type); 990 // read the infos of this block 991 const resource_info* info = infoBlock->rib_info; 992 while (info) { 993 data = _ReadResourceInfo(parseInfo, area, info, type, readIndices); 994 // prepare for next iteration, if there is another info 995 if (!area.check(data, kResourceInfoSeparatorSize)) { 996 throw Exception(B_IO_ERROR, "Unexpected end of resource info " 997 "table after index %ld.", resourceIndex); 998 } 999 const resource_info_separator* separator 1000 = (const resource_info_separator*)data; 1001 if (_GetInt(separator->ris_value1) == 0xffffffff 1002 && _GetInt(separator->ris_value2) == 0xffffffff) { 1003 // info block ends 1004 info = NULL; 1005 data = skip_bytes(data, kResourceInfoSeparatorSize); 1006 } else { 1007 // another info follows 1008 info = (const resource_info*)data; 1009 } 1010 resourceIndex++; 1011 } 1012 // end of the info block 1013 } 1014 // handle special case: empty resource info table 1015 if (resourceIndex == 1) { 1016 if (!area.check(data, kResourceInfoSeparatorSize)) { 1017 throw Exception(B_IO_ERROR, "Unexpected end of resource info " 1018 "table."); 1019 } 1020 const resource_info_separator* tableTerminator 1021 = (const resource_info_separator*)data; 1022 if (_GetInt(tableTerminator->ris_value1) != 0xffffffff 1023 || _GetInt(tableTerminator->ris_value2) != 0xffffffff) { 1024 throw Exception(B_IO_ERROR, "The resource info table ought to be " 1025 "empty, but is not properly terminated."); 1026 } 1027 data = skip_bytes(data, kResourceInfoSeparatorSize); 1028 } 1029 // Check, if the correct number of bytes are remaining. 1030 uint32 bytesLeft = (const char*)tableData + dataSize - (const char*)data; 1031 if (bytesLeft != 0) { 1032 throw Exception(B_IO_ERROR, "Error at the end of the resource info " 1033 "table: %lu bytes are remaining.", bytesLeft); 1034 } 1035 // check, if all items have been initialized 1036 for (int32 i = resourceCount - 1; i >= 0; i--) { 1037 if (!readIndices[i]) { 1038// Warnings::AddCurrentWarning("Resource item at index %ld " 1039// "has no info. Item removed.", i + 1); 1040 if (ResourceItem* item = parseInfo.container->RemoveResource(i)) 1041 delete item; 1042 resourceCount--; 1043 } 1044 } 1045} 1046 1047 1048bool 1049ResourceFile::_ReadInfoTableEnd(const void* data, int32 dataSize) 1050{ 1051 bool hasTableEnd = true; 1052 if ((uint32)dataSize < kResourceInfoSeparatorSize) 1053 throw Exception(B_IO_ERROR, "Info table is too short."); 1054 if ((uint32)dataSize < kResourceInfoTableEndSize) 1055 hasTableEnd = false; 1056 if (hasTableEnd) { 1057 const resource_info_table_end* tableEnd 1058 = (const resource_info_table_end*) 1059 skip_bytes(data, dataSize - kResourceInfoTableEndSize); 1060 if (_GetInt(tableEnd->rite_terminator) != 0) 1061 hasTableEnd = false; 1062 if (hasTableEnd) { 1063 dataSize -= kResourceInfoTableEndSize; 1064 // checksum 1065 uint32 checkSum = calculate_checksum(data, dataSize); 1066 uint32 fileCheckSum = _GetInt(tableEnd->rite_check_sum); 1067 if (checkSum != fileCheckSum) { 1068 throw Exception(B_IO_ERROR, "Invalid resource info table check" 1069 " sum: In file: %lx, calculated: %lx.", fileCheckSum, 1070 checkSum); 1071 } 1072 } 1073 } 1074// if (!hasTableEnd) 1075// Warnings::AddCurrentWarning("resource info table has no check sum."); 1076 return hasTableEnd; 1077} 1078 1079 1080const void* 1081ResourceFile::_ReadResourceInfo(resource_parse_info& parseInfo, 1082 const MemArea& area, const resource_info* info, type_code type, 1083 bool* readIndices) 1084{ 1085 int32& resourceCount = parseInfo.resource_count; 1086 int32 id = _GetInt(info->ri_id); 1087 int32 index = _GetInt(info->ri_index); 1088 uint16 nameSize = _GetInt(info->ri_name_size); 1089 const char* name = info->ri_name; 1090 // check the values 1091 bool ignore = false; 1092 // index 1093 if (index < 1 || index > resourceCount) { 1094// Warnings::AddCurrentWarning("Invalid index field in resource " 1095// "info table: %lu.", index); 1096 ignore = true; 1097 } 1098 if (!ignore) { 1099 if (readIndices[index - 1]) { 1100 throw Exception(B_IO_ERROR, "Multiple resource infos with the " 1101 "same index field: %ld.", index); 1102 } 1103 readIndices[index - 1] = true; 1104 } 1105 // name size 1106 if (!area.check(name, nameSize)) { 1107 throw Exception(B_IO_ERROR, "Invalid name size (%d) for index %ld in " 1108 "resource info table.", (int)nameSize, index); 1109 } 1110 // check, if name is null terminated 1111 if (name[nameSize - 1] != 0) { 1112// Warnings::AddCurrentWarning("Name for index %ld in " 1113// "resource info table is not null " 1114// "terminated.", index); 1115 } 1116 // set the values 1117 if (!ignore) { 1118 BString resourceName(name, nameSize); 1119 if (ResourceItem* item = parseInfo.container->ResourceAt(index - 1)) 1120 item->SetIdentity(type, id, resourceName.String()); 1121 else { 1122 throw Exception(B_IO_ERROR, "Unexpected error: No resource item " 1123 "at index %ld.", index); 1124 } 1125 } 1126 return skip_bytes(name, nameSize); 1127} 1128 1129 1130status_t 1131ResourceFile::_WriteResources(ResourcesContainer& container) 1132{ 1133 status_t error = B_OK; 1134 int32 resourceCount = container.CountResources(); 1135 char* buffer = NULL; 1136 try { 1137 // calculate sizes and offsets 1138 // header 1139 uint32 size = kResourcesHeaderSize; 1140 size_t bufferSize = size; 1141 // index section 1142 uint32 indexSectionOffset = size; 1143 uint32 indexSectionSize = kResourceIndexSectionHeaderSize 1144 + resourceCount * kResourceIndexEntrySize; 1145 indexSectionSize = align_value(indexSectionSize, 1146 kResourceIndexSectionAlignment); 1147 size += indexSectionSize; 1148 bufferSize = std::max((uint32)bufferSize, indexSectionSize); 1149 // unknown section 1150 uint32 unknownSectionOffset = size; 1151 uint32 unknownSectionSize = kUnknownResourceSectionSize; 1152 size += unknownSectionSize; 1153 bufferSize = std::max((uint32)bufferSize, unknownSectionSize); 1154 // data 1155 uint32 dataOffset = size; 1156 uint32 dataSize = 0; 1157 for (int32 i = 0; i < resourceCount; i++) { 1158 ResourceItem* item = container.ResourceAt(i); 1159 if (!item->IsLoaded()) 1160 throw Exception(B_IO_ERROR, "Resource is not loaded."); 1161 dataSize += item->DataSize(); 1162 bufferSize = std::max(bufferSize, item->DataSize()); 1163 } 1164 size += dataSize; 1165 // info table 1166 uint32 infoTableOffset = size; 1167 uint32 infoTableSize = 0; 1168 type_code type = 0; 1169 for (int32 i = 0; i < resourceCount; i++) { 1170 ResourceItem* item = container.ResourceAt(i); 1171 if (i == 0 || type != item->Type()) { 1172 if (i != 0) 1173 infoTableSize += kResourceInfoSeparatorSize; 1174 type = item->Type(); 1175 infoTableSize += kMinResourceInfoBlockSize; 1176 } else 1177 infoTableSize += kMinResourceInfoSize; 1178 1179 const char* name = item->Name(); 1180 if (name && name[0] != '\0') 1181 infoTableSize += strlen(name) + 1; 1182 } 1183 infoTableSize += kResourceInfoSeparatorSize 1184 + kResourceInfoTableEndSize; 1185 size += infoTableSize; 1186 bufferSize = std::max((uint32)bufferSize, infoTableSize); 1187 1188 // write... 1189 // set the file size 1190 fFile.SetSize(size); 1191 buffer = new(std::nothrow) char[bufferSize]; 1192 if (!buffer) 1193 throw Exception(B_NO_MEMORY); 1194 void* data = buffer; 1195 // header 1196 resources_header* resourcesHeader = (resources_header*)data; 1197 resourcesHeader->rh_resources_magic = kResourcesHeaderMagic; 1198 resourcesHeader->rh_resource_count = resourceCount; 1199 resourcesHeader->rh_index_section_offset = indexSectionOffset; 1200 resourcesHeader->rh_admin_section_size = indexSectionOffset 1201 + indexSectionSize; 1202 for (int32 i = 0; i < 13; i++) 1203 resourcesHeader->rh_pad[i] = 0; 1204 write_exactly(fFile, 0, buffer, kResourcesHeaderSize, 1205 "Failed to write resources header."); 1206 // index section 1207 data = buffer; 1208 // header 1209 resource_index_section_header* indexHeader 1210 = (resource_index_section_header*)data; 1211 indexHeader->rish_index_section_offset = indexSectionOffset; 1212 indexHeader->rish_index_section_size = indexSectionSize; 1213 indexHeader->rish_unknown_section_offset = unknownSectionOffset; 1214 indexHeader->rish_unknown_section_size = unknownSectionSize; 1215 indexHeader->rish_info_table_offset = infoTableOffset; 1216 indexHeader->rish_info_table_size = infoTableSize; 1217 fill_pattern(buffer - indexSectionOffset, 1218 &indexHeader->rish_unused_data1, 1); 1219 fill_pattern(buffer - indexSectionOffset, 1220 indexHeader->rish_unused_data2, 25); 1221 fill_pattern(buffer - indexSectionOffset, 1222 &indexHeader->rish_unused_data3, 1); 1223 // index table 1224 data = skip_bytes(data, kResourceIndexSectionHeaderSize); 1225 resource_index_entry* entry = (resource_index_entry*)data; 1226 uint32 entryOffset = dataOffset; 1227 for (int32 i = 0; i < resourceCount; i++, entry++) { 1228 ResourceItem* item = container.ResourceAt(i); 1229 uint32 entrySize = item->DataSize(); 1230 entry->rie_offset = entryOffset; 1231 entry->rie_size = entrySize; 1232 entry->rie_pad = 0; 1233 entryOffset += entrySize; 1234 } 1235 fill_pattern(buffer - indexSectionOffset, entry, 1236 buffer + indexSectionSize); 1237 write_exactly(fFile, indexSectionOffset, buffer, indexSectionSize, 1238 "Failed to write index section."); 1239 // unknown section 1240 fill_pattern(unknownSectionOffset, buffer, unknownSectionSize / 4); 1241 write_exactly(fFile, unknownSectionOffset, buffer, unknownSectionSize, 1242 "Failed to write unknown section."); 1243 // data 1244 uint32 itemOffset = dataOffset; 1245 for (int32 i = 0; i < resourceCount; i++) { 1246 data = buffer; 1247 ResourceItem* item = container.ResourceAt(i); 1248 const void* itemData = item->Data(); 1249 uint32 itemSize = item->DataSize(); 1250 if (!itemData && itemSize > 0) 1251 throw Exception(error, "Invalid resource item data."); 1252 if (itemData) { 1253 // swap data, if necessary 1254 if (!fHostEndianess) { 1255 memcpy(data, itemData, itemSize); 1256 swap_data(item->Type(), data, itemSize, B_SWAP_ALWAYS); 1257 itemData = data; 1258 } 1259 write_exactly(fFile, itemOffset, itemData, itemSize, 1260 "Failed to write resource item data."); 1261 } 1262 item->SetOffset(itemOffset); 1263 itemOffset += itemSize; 1264 } 1265 // info table 1266 data = buffer; 1267 type = 0; 1268 for (int32 i = 0; i < resourceCount; i++) { 1269 ResourceItem* item = container.ResourceAt(i); 1270 resource_info* info = NULL; 1271 if (i == 0 || type != item->Type()) { 1272 if (i != 0) { 1273 resource_info_separator* separator 1274 = (resource_info_separator*)data; 1275 separator->ris_value1 = 0xffffffff; 1276 separator->ris_value2 = 0xffffffff; 1277 data = skip_bytes(data, kResourceInfoSeparatorSize); 1278 } 1279 type = item->Type(); 1280 resource_info_block* infoBlock = (resource_info_block*)data; 1281 infoBlock->rib_type = type; 1282 info = infoBlock->rib_info; 1283 } else 1284 info = (resource_info*)data; 1285 // info 1286 info->ri_id = item->ID(); 1287 info->ri_index = i + 1; 1288 info->ri_name_size = 0; 1289 data = info->ri_name; 1290 1291 const char* name = item->Name(); 1292 if (name && name[0] != '\0') { 1293 uint32 nameLen = strlen(name); 1294 memcpy(info->ri_name, name, nameLen + 1); 1295 data = skip_bytes(data, nameLen + 1); 1296 info->ri_name_size = nameLen + 1; 1297 } 1298 } 1299 // separator 1300 resource_info_separator* separator = (resource_info_separator*)data; 1301 separator->ris_value1 = 0xffffffff; 1302 separator->ris_value2 = 0xffffffff; 1303 // table end 1304 data = skip_bytes(data, kResourceInfoSeparatorSize); 1305 resource_info_table_end* tableEnd = (resource_info_table_end*)data; 1306 tableEnd->rite_check_sum = calculate_checksum(buffer, 1307 infoTableSize - kResourceInfoTableEndSize); 1308 tableEnd->rite_terminator = 0; 1309 write_exactly(fFile, infoTableOffset, buffer, infoTableSize, 1310 "Failed to write info table."); 1311 } catch (Exception exception) { 1312 if (exception.Error() != B_OK) 1313 error = exception.Error(); 1314 else 1315 error = B_ERROR; 1316 } 1317 delete[] buffer; 1318 return error; 1319} 1320 1321 1322status_t 1323ResourceFile::_MakeEmptyResourceFile() 1324{ 1325 status_t error = fFile.InitCheck(); 1326 if (error == B_OK && !fFile.File()->IsWritable()) 1327 error = B_NOT_ALLOWED; 1328 if (error == B_OK) { 1329 try { 1330 BFile* file = fFile.File(); 1331 // make it an x86 resource file 1332 error = file->SetSize(4); 1333 if (error != B_OK) 1334 throw Exception(error, "Failed to set file size."); 1335 write_exactly(*file, 0, kX86ResourceFileMagic, 4, 1336 "Failed to write magic number."); 1337 fHostEndianess = B_HOST_IS_LENDIAN; 1338 fFileType = FILE_TYPE_X86_RESOURCE; 1339 fFile.SetTo(file, kX86ResourcesOffset); 1340 fEmptyResources = true; 1341 } catch (Exception exception) { 1342 if (exception.Error() != B_OK) 1343 error = exception.Error(); 1344 else 1345 error = B_ERROR; 1346 } 1347 } 1348 return error; 1349} 1350 1351 1352}; // namespace Storage 1353}; // namespace BPrivate 1354