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