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