3 #include "ResourceFile.h"
11 #include "ResourceItem.h"
12 #include "ResourcesDefs.h"
16 static const uint32 kMaxELFHeaderSize
= sizeof(Elf32_Ehdr
) + 32;
17 static const char kELFFileMagic
[4] = { 0x7f, 'E', 'L', 'F' };
20 static const uint32 kMaxResourceCount
= 10000;
21 static const uint32 kELFMaxResourceAlignment
= 1024 * 1024 * 10; // 10 MB
23 // recognized file types (indices into kFileTypeNames)
25 FILE_TYPE_UNKNOWN
= 0,
26 FILE_TYPE_X86_RESOURCE
= 1,
27 FILE_TYPE_PPC_RESOURCE
= 2,
32 const char* kFileTypeNames
[] = {
41 // helper functions/classes
46 read_exactly(BPositionIO
& file
, off_t position
, void* buffer
, size_t size
,
47 const char* errorMessage
= NULL
)
49 ssize_t read
= file
.ReadAt(position
, buffer
, size
);
51 throw Exception(read
, errorMessage
);
52 else if ((size_t)read
!= size
) {
54 throw Exception("%s Read to few bytes (%ld/%lu).", errorMessage
,
57 throw Exception("Read to few bytes (%ld/%lu).", read
, size
);
62 template<typename TV
, typename TA
>
65 align_value(const TV
& value
, const TA
& alignment
)
67 return ((value
+ alignment
- 1) / alignment
) * alignment
;
73 calculate_checksum(const void* data
, uint32 size
)
76 const uint8
* csData
= (const uint8
*)data
;
77 const uint8
* dataEnd
= csData
+ size
;
78 const uint8
* current
= csData
;
79 for (; current
< dataEnd
; current
+= 4) {
81 int32 bytes
= min(4L, dataEnd
- current
);
82 for (int32 i
= 0; i
< bytes
; i
++)
83 word
= (word
<< 8) + current
[i
];
92 skip_bytes(const void* buffer
, int32 offset
)
94 return (const char*)buffer
+ offset
;
100 skip_bytes(void* buffer
, int32 offset
)
102 return (char*)buffer
+ offset
;
108 fill_pattern(uint32 byteOffset
, void* _buffer
, uint32 count
)
110 uint32
* buffer
= (uint32
*)_buffer
;
111 for (uint32 i
= 0; i
< count
; i
++)
112 buffer
[i
] = kUnusedResourceDataPattern
[(byteOffset
/ 4 + i
) % 3];
118 fill_pattern(const void* dataBegin
, void* buffer
, uint32 count
)
120 fill_pattern((char*)buffer
- (const char*)dataBegin
, buffer
, count
);
126 fill_pattern(const void* dataBegin
, void* buffer
, const void* bufferEnd
)
128 fill_pattern(dataBegin
, buffer
,
129 ((const char*)bufferEnd
- (char*)buffer
) / 4);
135 check_pattern(uint32 byteOffset
, void* _buffer
, uint32 count
,
139 uint32
* buffer
= (uint32
*)_buffer
;
140 for (uint32 i
= 0; result
&& i
< count
; i
++) {
141 uint32 value
= buffer
[i
];
143 value
= B_SWAP_INT32(value
);
145 = (value
== kUnusedResourceDataPattern
[(byteOffset
/ 4 + i
) % 3]);
152 MemArea(const void* data
, uint32 size
) : data(data
), size(size
) {}
154 inline bool check(const void* _current
, uint32 skip
= 0) const
156 const char* start
= (const char*)data
;
157 const char* current
= (const char*)_current
;
158 return (start
<= current
&& start
+ size
>= current
+ skip
);
168 AutoDeleter(C
* object
, bool array
= false) : object(object
), array(array
)
186 ResourceFile::ResourceFile()
189 fFileType(FILE_TYPE_UNKNOWN
),
192 fInfoTableItem(NULL
),
198 ResourceFile::~ResourceFile()
205 ResourceFile::Init(BFile
& file
)
213 } catch (Exception exception
) {
221 ResourceFile::Unset()
224 for (int32 i
= 0; ResourceItem
* item
= ItemAt(i
); i
++)
229 fFileType
= FILE_TYPE_UNKNOWN
;
234 delete fInfoTableItem
;
235 fInfoTableItem
= NULL
;
236 fHostEndianess
= true;
241 ResourceFile::InitCheck() const
243 return fFile
.InitCheck();
248 ResourceFile::AddItem(ResourceItem
* item
, int32 index
)
252 if (index
< 0 || index
> CountItems())
253 index
= CountItems();
254 result
= fItems
.AddItem(item
);
261 ResourceFile::RemoveItem(int32 index
)
263 return (ResourceItem
*)fItems
.RemoveItem(index
);
268 ResourceFile::RemoveItem(ResourceItem
* item
)
270 return RemoveItem(IndexOf(item
));
275 ResourceFile::IndexOf(ResourceItem
* item
) const
277 return fItems
.IndexOf(item
);
282 ResourceFile::ItemAt(int32 index
) const
284 return (ResourceItem
*)fItems
.ItemAt(index
);
289 ResourceFile::CountItems() const
291 return fItems
.CountItems();
296 ResourceFile::GetResourcesSize() const
298 if (!fInfoTableItem
|| fFile
.InitCheck())
299 throw Exception("Resource file not initialized.");
301 uint32 size
= kResourcesHeaderSize
;
303 uint32 indexSectionSize
= kResourceIndexSectionHeaderSize
304 + fResourceCount
* kResourceIndexEntrySize
;
305 indexSectionSize
= align_value(indexSectionSize
,
306 kResourceIndexSectionAlignment
);
307 size
+= indexSectionSize
;
309 size
+= kUnknownResourceSectionSize
;
312 for (int32 i
= 0; i
< fResourceCount
; i
++) {
313 ResourceItem
* item
= ItemAt(i
);
314 dataSize
+= item
->GetSize();
318 uint32 infoTableSize
= 0;
320 for (int32 i
= 0; i
< fResourceCount
; i
++) {
321 ResourceItem
* item
= ItemAt(i
);
322 if (i
== 0 || type
!= item
->GetType()) {
324 infoTableSize
+= kResourceInfoSeparatorSize
;
325 type
= item
->GetType();
326 infoTableSize
+= kMinResourceInfoBlockSize
;
328 infoTableSize
+= kMinResourceInfoSize
;
329 uint32 nameLen
= strlen(item
->GetName());
331 infoTableSize
+= nameLen
+ 1;
333 infoTableSize
+= kResourceInfoSeparatorSize
+ kResourceInfoTableEndSize
;
334 size
+= infoTableSize
;
340 ResourceFile::WriteResources(void* buffer
, uint32 bufferSize
)
342 // calculate sizes and offsets
344 uint32 size
= kResourcesHeaderSize
;
346 uint32 indexSectionOffset
= size
;
347 uint32 indexSectionSize
= kResourceIndexSectionHeaderSize
348 + fResourceCount
* kResourceIndexEntrySize
;
349 indexSectionSize
= align_value(indexSectionSize
,
350 kResourceIndexSectionAlignment
);
351 size
+= indexSectionSize
;
353 uint32 unknownSectionOffset
= size
;
354 uint32 unknownSectionSize
= kUnknownResourceSectionSize
;
355 size
+= unknownSectionSize
;
357 uint32 dataOffset
= size
;
359 for (int32 i
= 0; i
< fResourceCount
; i
++) {
360 ResourceItem
* item
= ItemAt(i
);
361 dataSize
+= item
->GetSize();
365 uint32 infoTableOffset
= size
;
366 uint32 infoTableSize
= 0;
368 for (int32 i
= 0; i
< fResourceCount
; i
++) {
369 ResourceItem
* item
= ItemAt(i
);
370 if (i
== 0 || type
!= item
->GetType()) {
372 infoTableSize
+= kResourceInfoSeparatorSize
;
373 type
= item
->GetType();
374 infoTableSize
+= kMinResourceInfoBlockSize
;
376 infoTableSize
+= kMinResourceInfoSize
;
377 uint32 nameLen
= strlen(item
->GetName());
379 infoTableSize
+= nameLen
+ 1;
381 infoTableSize
+= kResourceInfoSeparatorSize
+ kResourceInfoTableEndSize
;
382 size
+= infoTableSize
;
383 // check whether the buffer is large enough
385 throw Exception("Supplied buffer is NULL.");
386 if (bufferSize
< size
)
387 throw Exception("Supplied buffer is too small.");
391 resources_header
* resourcesHeader
= (resources_header
*)data
;
392 resourcesHeader
->rh_resources_magic
= kResourcesHeaderMagic
;
393 resourcesHeader
->rh_resource_count
= fResourceCount
;
394 resourcesHeader
->rh_index_section_offset
= indexSectionOffset
;
395 resourcesHeader
->rh_admin_section_size
= indexSectionOffset
397 for (int32 i
= 0; i
< 13; i
++)
398 resourcesHeader
->rh_pad
[i
] = 0;
401 data
= skip_bytes(buffer
, indexSectionOffset
);
402 resource_index_section_header
* indexHeader
403 = (resource_index_section_header
*)data
;
404 indexHeader
->rish_index_section_offset
= indexSectionOffset
;
405 indexHeader
->rish_index_section_size
= indexSectionSize
;
406 indexHeader
->rish_unknown_section_offset
= unknownSectionOffset
;
407 indexHeader
->rish_unknown_section_size
= unknownSectionSize
;
408 indexHeader
->rish_info_table_offset
= infoTableOffset
;
409 indexHeader
->rish_info_table_size
= infoTableSize
;
410 fill_pattern(buffer
, &indexHeader
->rish_unused_data1
, 1);
411 fill_pattern(buffer
, indexHeader
->rish_unused_data2
, 25);
412 fill_pattern(buffer
, &indexHeader
->rish_unused_data3
, 1);
414 data
= skip_bytes(data
, kResourceIndexSectionHeaderSize
);
415 resource_index_entry
* entry
= (resource_index_entry
*)data
;
416 uint32 entryOffset
= dataOffset
;
417 for (int32 i
= 0; i
< fResourceCount
; i
++, entry
++) {
418 ResourceItem
* item
= ItemAt(i
);
419 uint32 entrySize
= item
->GetSize();
420 entry
->rie_offset
= entryOffset
;
421 entry
->rie_size
= entrySize
;
423 entryOffset
+= entrySize
;
425 // padding + unknown section
426 data
= skip_bytes(buffer
, dataOffset
);
427 fill_pattern(buffer
, entry
, data
);
429 for (int32 i
= 0; i
< fResourceCount
; i
++) {
430 ResourceItem
* item
= ItemAt(i
);
431 status_t error
= item
->LoadData(fFile
);
433 throw Exception(error
, "Error loading resource data.");
434 uint32 entrySize
= item
->GetSize();
435 memcpy(data
, item
->GetData(), entrySize
);
436 data
= skip_bytes(data
, entrySize
);
439 data
= skip_bytes(buffer
, infoTableOffset
);
441 for (int32 i
= 0; i
< fResourceCount
; i
++) {
442 ResourceItem
* item
= ItemAt(i
);
443 resource_info
* info
= NULL
;
444 if (i
== 0 || type
!= item
->GetType()) {
446 resource_info_separator
* separator
447 = (resource_info_separator
*)data
;
448 separator
->ris_value1
= 0xffffffff;
449 separator
->ris_value2
= 0xffffffff;
450 data
= skip_bytes(data
, kResourceInfoSeparatorSize
);
452 type
= item
->GetType();
453 resource_info_block
* infoBlock
= (resource_info_block
*)data
;
454 infoBlock
->rib_type
= type
;
455 info
= infoBlock
->rib_info
;
457 info
= (resource_info
*)data
;
459 info
->ri_id
= item
->GetID();
460 info
->ri_index
= i
+ 1;
461 info
->ri_name_size
= 0;
462 data
= info
->ri_name
;
463 uint32 nameLen
= strlen(item
->GetName());
465 memcpy(info
->ri_name
, item
->GetName(), nameLen
+ 1);
466 data
= skip_bytes(data
, nameLen
+ 1);
467 info
->ri_name_size
= nameLen
+ 1;
471 resource_info_separator
* separator
= (resource_info_separator
*)data
;
472 separator
->ris_value1
= 0xffffffff;
473 separator
->ris_value2
= 0xffffffff;
475 data
= skip_bytes(data
, kResourceInfoSeparatorSize
);
476 resource_info_table_end
* tableEnd
= (resource_info_table_end
*)data
;
477 void* infoTable
= skip_bytes(buffer
, infoTableOffset
);
478 tableEnd
->rite_check_sum
= calculate_checksum(infoTable
,
479 infoTableSize
- kResourceInfoTableEndSize
);
480 tableEnd
->rite_terminator
= 0;
482 data
= skip_bytes(data
, kResourceInfoTableEndSize
);
483 uint32 bytesWritten
= (char*)data
- (char*)buffer
;
484 if (bytesWritten
!= size
) {
485 throw Exception("Bad boy error: Wrote %lu bytes, though supposed to "
486 "write %lu bytes.", bytesWritten
, size
);
493 ResourceFile::WriteTest()
495 uint32 size
= GetResourcesSize();
496 if (size
!= fFileSize
) {
497 throw Exception("Calculated resources size differs from actual size "
498 "in file: %lu vs %Ld.", size
, fFileSize
);
500 char* buffer1
= new char[size
];
501 char* buffer2
= new char[size
];
503 WriteResources(buffer1
, size
);
504 read_exactly(fFile
, 0, buffer2
, size
,
505 "Write test: Error reading resources.");
506 for (uint32 i
= 0; i
< size
; i
++) {
507 if (buffer1
[i
] != buffer2
[i
]) {
508 off_t filePosition
= fFile
.GetOffset() + i
;
509 throw Exception("Written resources differ from those in file. "
510 "First difference at byte %lu (file position "
511 "%Ld): %x vs %x.", i
, filePosition
,
512 (int)buffer1
[i
] & 0xff,
513 (int)buffer2
[i
] & 0xff);
516 } catch (Exception exception
) {
529 ResourceFile::PrintToStream(bool longInfo
)
532 off_t resourcesOffset
= fFile
.GetOffset();
533 printf("ResourceFile:\n");
534 printf("file type : %s\n", kFileTypeNames
[fFileType
]);
535 printf("endianess : %s\n",
536 (fHostEndianess
== (bool)B_HOST_IS_LENDIAN
) ? "little" : "big");
537 printf("resource section offset: 0x%08Lx (%Ld)\n", resourcesOffset
,
539 if (fInfoTableItem
) {
540 int32 offset
= fInfoTableItem
->GetOffset();
541 int32 size
= fInfoTableItem
->GetSize();
542 printf("resource info table : offset: 0x%08lx (%ld), "
543 "size: 0x%08lx (%ld)\n", offset
, offset
, size
, size
);
545 printf("number of resources : %ld\n", fResourceCount
);
546 for (int32 i
= 0; i
< fResourceCount
; i
++) {
547 ResourceItem
* item
= ItemAt(i
);
548 item
->PrintToStream();
551 printf(" Type ID Size Name\n");
552 printf(" ------ ----- -------- --------------------\n");
553 for (int32 i
= 0; i
< fResourceCount
; i
++) {
554 ResourceItem
* item
= ItemAt(i
);
555 type_code type
= item
->GetType();
556 char typeName
[4] = { type
>> 24, (type
>> 16) & 0xff,
557 (type
>> 8) & 0xff, type
& 0xff };
558 printf(" '%.4s' %5ld %8lu %s\n", typeName
, item
->GetID(),
559 item
->GetSize(), item
->GetName());
567 ResourceFile::_InitFile(BFile
& file
)
569 status_t error
= B_OK
;
571 // read the first four bytes, and check, if they identify a resource file
573 read_exactly(file
, 0, magic
, 4, "Failed to read magic number.");
574 if (!memcmp(magic
, kX86ResourceFileMagic
, 4)) {
576 fHostEndianess
= B_HOST_IS_LENDIAN
;
577 fFileType
= FILE_TYPE_X86_RESOURCE
;
578 fFile
.SetTo(file
, kX86ResourcesOffset
);
579 } else if (!memcmp(magic
, kPEFFileMagic1
, 4)) {
580 PEFContainerHeader pefHeader
;
581 read_exactly(file
, 0, &pefHeader
, kPEFContainerHeaderSize
,
582 "Failed to read PEF container header.");
583 if (!memcmp(pefHeader
.tag2
, kPPCResourceFileMagic
, 4)) {
585 fHostEndianess
= B_HOST_IS_BENDIAN
;
586 fFileType
= FILE_TYPE_PPC_RESOURCE
;
587 fFile
.SetTo(file
, kPPCResourcesOffset
);
588 } else if (!memcmp(pefHeader
.tag2
, kPEFFileMagic2
, 4)) {
590 fFileType
= FILE_TYPE_PEF
;
591 _InitPEFFile(file
, pefHeader
);
593 throw Exception("File is not a resource file.");
594 } else if (!memcmp(magic
, kELFFileMagic
, 4)) {
596 fFileType
= FILE_TYPE_ELF
;
598 } else if (!memcmp(magic
, kX86ResourceFileMagic
, 2)) {
599 // x86 resource file with screwed magic?
600 Warnings::AddCurrentWarning("File magic is 0x%08lx. Should be 0x%08lx "
601 "for x86 resource file. Try anyway.",
602 ntohl(*(uint32
*)magic
),
603 ntohl(*(uint32
*)kX86ResourceFileMagic
));
604 fHostEndianess
= B_HOST_IS_LENDIAN
;
605 fFileType
= FILE_TYPE_X86_RESOURCE
;
606 fFile
.SetTo(file
, kX86ResourcesOffset
);
608 throw Exception("File is not a resource file.");
609 error
= fFile
.InitCheck();
611 throw Exception(error
, "Failed to initialize resource file.");
614 error
= fFile
.GetSize(&fFileSize
);
616 throw Exception(error
, "Failed to get the file size.");
621 ResourceFile::_InitELFFile(BFile
& file
)
623 status_t error
= B_OK
;
626 error
= file
.GetSize(&fileSize
);
628 throw Exception(error
, "Failed to get the file size.");
630 Elf32_Ehdr fileHeader
;
631 read_exactly(file
, 0, &fileHeader
, sizeof(Elf32_Ehdr
),
632 "Failed to read ELF header.");
633 // check data encoding (endianess)
634 switch (fileHeader
.e_ident
[EI_DATA
]) {
636 fHostEndianess
= B_HOST_IS_LENDIAN
;
639 fHostEndianess
= B_HOST_IS_BENDIAN
;
643 throw Exception("Unsupported ELF data encoding.");
646 // get the header values
647 uint32 headerSize
= _GetUInt16(fileHeader
.e_ehsize
);
648 uint32 programHeaderTableOffset
= _GetUInt32(fileHeader
.e_phoff
);
649 uint32 programHeaderSize
= _GetUInt16(fileHeader
.e_phentsize
);
650 uint32 programHeaderCount
= _GetUInt16(fileHeader
.e_phnum
);
651 uint32 sectionHeaderTableOffset
= _GetUInt32(fileHeader
.e_shoff
);
652 uint32 sectionHeaderSize
= _GetUInt16(fileHeader
.e_shentsize
);
653 uint32 sectionHeaderCount
= _GetUInt16(fileHeader
.e_shnum
);
654 bool hasProgramHeaderTable
= (programHeaderTableOffset
!= 0);
655 bool hasSectionHeaderTable
= (sectionHeaderTableOffset
!= 0);
656 //printf("headerSize : %lu\n", headerSize);
657 //printf("programHeaderTableOffset: %lu\n", programHeaderTableOffset);
658 //printf("programHeaderSize : %lu\n", programHeaderSize);
659 //printf("programHeaderCount : %lu\n", programHeaderCount);
660 //printf("sectionHeaderTableOffset: %lu\n", sectionHeaderTableOffset);
661 //printf("sectionHeaderSize : %lu\n", sectionHeaderSize);
662 //printf("sectionHeaderCount : %lu\n", sectionHeaderCount);
663 // check the sanity of the header values
665 if (headerSize
< sizeof(Elf32_Ehdr
) || headerSize
> kMaxELFHeaderSize
) {
666 throw Exception("Invalid ELF header: invalid ELF header size: %lu.",
669 uint32 resourceOffset
= headerSize
;
670 uint32 resourceAlignment
= 0;
671 // program header table offset and entry count/size
672 uint32 programHeaderTableSize
= 0;
673 if (hasProgramHeaderTable
) {
674 if (programHeaderTableOffset
< headerSize
675 || programHeaderTableOffset
> fileSize
) {
676 throw Exception("Invalid ELF header: invalid program header table "
677 "offset: %lu.", programHeaderTableOffset
);
679 programHeaderTableSize
= programHeaderSize
* programHeaderCount
;
680 if (programHeaderSize
< sizeof(Elf32_Phdr
)
681 || programHeaderTableOffset
+ programHeaderTableSize
> fileSize
) {
682 throw Exception("Invalid ELF header: program header table exceeds "
684 programHeaderTableOffset
+ programHeaderTableSize
);
686 resourceOffset
= max(resourceOffset
, programHeaderTableOffset
687 + programHeaderTableSize
);
688 // iterate through the program headers
689 for (int32 i
= 0; i
< (int32
)programHeaderCount
; i
++) {
690 uint32 shOffset
= programHeaderTableOffset
+ i
* programHeaderSize
;
691 Elf32_Phdr programHeader
;
692 read_exactly(file
, shOffset
, &programHeader
, sizeof(Elf32_Shdr
),
693 "Failed to read ELF program header.");
694 // get the header values
695 uint32 type
= _GetUInt32(programHeader
.p_type
);
696 uint32 offset
= _GetUInt32(programHeader
.p_offset
);
697 uint32 size
= _GetUInt32(programHeader
.p_filesz
);
698 uint32 alignment
= _GetUInt32(programHeader
.p_align
);
699 //printf("segment: type: %ld, offset: %lu, size: %lu, alignment: %lu\n",
700 //type, offset, size, alignment);
702 // PT_NULL marks the header unused,
703 if (type
!= PT_NULL
) {
704 if (/*offset < headerSize ||*/ offset
> fileSize
) {
705 throw Exception("Invalid ELF program header: invalid "
706 "program offset: %lu.", offset
);
708 uint32 segmentEnd
= offset
+ size
;
709 if (segmentEnd
> fileSize
) {
710 throw Exception("Invalid ELF section header: segment "
711 "exceeds file: %lu.", segmentEnd
);
713 resourceOffset
= max(resourceOffset
, segmentEnd
);
714 resourceAlignment
= max(resourceAlignment
, alignment
);
718 // section header table offset and entry count/size
719 uint32 sectionHeaderTableSize
= 0;
720 if (hasSectionHeaderTable
) {
721 if (sectionHeaderTableOffset
< headerSize
722 || sectionHeaderTableOffset
> fileSize
) {
723 throw Exception("Invalid ELF header: invalid section header table "
724 "offset: %lu.", sectionHeaderTableOffset
);
726 sectionHeaderTableSize
= sectionHeaderSize
* sectionHeaderCount
;
727 if (sectionHeaderSize
< sizeof(Elf32_Shdr
)
728 || sectionHeaderTableOffset
+ sectionHeaderTableSize
> fileSize
) {
729 throw Exception("Invalid ELF header: section header table exceeds "
731 sectionHeaderTableOffset
+ sectionHeaderTableSize
);
733 resourceOffset
= max(resourceOffset
, sectionHeaderTableOffset
734 + sectionHeaderTableSize
);
735 // iterate through the section headers
736 for (int32 i
= 0; i
< (int32
)sectionHeaderCount
; i
++) {
737 uint32 shOffset
= sectionHeaderTableOffset
+ i
* sectionHeaderSize
;
738 Elf32_Shdr sectionHeader
;
739 read_exactly(file
, shOffset
, §ionHeader
, sizeof(Elf32_Shdr
),
740 "Failed to read ELF section header.");
741 // get the header values
742 uint32 type
= _GetUInt32(sectionHeader
.sh_type
);
743 uint32 offset
= _GetUInt32(sectionHeader
.sh_offset
);
744 uint32 size
= _GetUInt32(sectionHeader
.sh_size
);
745 //printf("section: type: %ld, offset: %lu, size: %lu\n", type, offset, size);
747 // SHT_NULL marks the header unused,
748 // SHT_NOBITS sections take no space in the file
749 if (type
!= SHT_NULL
&& type
!= SHT_NOBITS
) {
750 if (offset
< headerSize
|| offset
> fileSize
) {
751 throw Exception("Invalid ELF section header: invalid "
752 "section offset: %lu.", offset
);
754 uint32 sectionEnd
= offset
+ size
;
755 if (sectionEnd
> fileSize
) {
756 throw Exception("Invalid ELF section header: section "
757 "exceeds file: %lu.", sectionEnd
);
759 resourceOffset
= max(resourceOffset
, sectionEnd
);
763 //printf("resourceOffset: %lu\n", resourceOffset);
765 if (resourceAlignment
< kELFMinResourceAlignment
)
766 resourceAlignment
= kELFMinResourceAlignment
;
767 if (resourceAlignment
> kELFMaxResourceAlignment
) {
768 throw Exception("The ELF object file requires an invalid alignment: "
769 "%lu.", resourceAlignment
);
771 resourceOffset
= align_value(resourceOffset
, resourceAlignment
);
772 //printf("resourceOffset: %lu\n", resourceOffset);
773 if (resourceOffset
>= fileSize
)
774 throw Exception("The ELF object file does not contain resources.");
775 // fine, init the offset file
776 fFile
.SetTo(file
, resourceOffset
);
781 ResourceFile::_InitPEFFile(BFile
& file
, const PEFContainerHeader
& pefHeader
)
783 status_t error
= B_OK
;
786 error
= file
.GetSize(&fileSize
);
788 throw Exception(error
, "Failed to get the file size.");
789 // check architecture -- we support PPC only
790 if (memcmp(pefHeader
.architecture
, kPEFArchitecturePPC
, 4))
791 throw Exception("PEF file architecture is not PPC.");
792 fHostEndianess
= B_HOST_IS_BENDIAN
;
793 // get the section count
794 uint16 sectionCount
= _GetUInt16(pefHeader
.sectionCount
);
795 // iterate through the PEF sections headers
796 uint32 sectionHeaderTableOffset
= kPEFContainerHeaderSize
;
797 uint32 sectionHeaderTableEnd
798 = sectionHeaderTableOffset
+ sectionCount
* kPEFSectionHeaderSize
;
799 uint32 resourceOffset
= sectionHeaderTableEnd
;
800 for (int32 i
= 0; i
< (int32
)sectionCount
; i
++) {
801 uint32 shOffset
= sectionHeaderTableOffset
+ i
* kPEFSectionHeaderSize
;
802 PEFSectionHeader sectionHeader
;
803 read_exactly(file
, shOffset
, §ionHeader
, kPEFSectionHeaderSize
,
804 "Failed to read PEF section header.");
805 // get the header values
806 uint32 offset
= _GetUInt32(sectionHeader
.containerOffset
);
807 uint32 size
= _GetUInt32(sectionHeader
.packedSize
);
809 if (offset
< sectionHeaderTableEnd
|| offset
> fileSize
) {
810 throw Exception("Invalid PEF section header: invalid "
811 "section offset: %lu.", offset
);
813 uint32 sectionEnd
= offset
+ size
;
814 if (sectionEnd
> fileSize
) {
815 throw Exception("Invalid PEF section header: section "
816 "exceeds file: %lu.", sectionEnd
);
818 resourceOffset
= max(resourceOffset
, sectionEnd
);
820 // init the offset file
821 fFile
.SetTo(file
, resourceOffset
);
826 ResourceFile::_ReadHeader()
829 resources_header header
;
830 read_exactly(fFile
, 0, &header
, kResourcesHeaderSize
,
831 "Failed to read the header.");
834 uint32 magic
= _GetUInt32(header
.rh_resources_magic
);
835 if (magic
== kResourcesHeaderMagic
) {
836 // everything is fine
837 } else if (B_SWAP_INT32(magic
) == kResourcesHeaderMagic
) {
838 const char* endianessStr
[2] = { "little", "big" };
840 = (fHostEndianess
== ((bool)B_HOST_IS_LENDIAN
? 0 : 1));
841 Warnings::AddCurrentWarning("Endianess seems to be %s, although %s "
843 endianessStr
[1 - endianess
],
844 endianessStr
[endianess
]);
845 fHostEndianess
= !fHostEndianess
;
847 throw Exception("Invalid resources header magic.");
849 uint32 resourceCount
= _GetUInt32(header
.rh_resource_count
);
850 if (resourceCount
> kMaxResourceCount
)
851 throw Exception("Bad number of resources.");
852 // index section offset
853 uint32 indexSectionOffset
= _GetUInt32(header
.rh_index_section_offset
);
854 if (indexSectionOffset
!= kResourceIndexSectionOffset
) {
855 throw Exception("Unexpected resource index section offset. Is: %lu, "
856 "should be: %lu.", indexSectionOffset
,
857 kResourceIndexSectionOffset
);
859 // admin section size
860 uint32 indexSectionSize
= kResourceIndexSectionHeaderSize
861 + kResourceIndexEntrySize
* resourceCount
;
862 indexSectionSize
= align_value(indexSectionSize
,
863 kResourceIndexSectionAlignment
);
864 uint32 adminSectionSize
= _GetUInt32(header
.rh_admin_section_size
);
865 if (adminSectionSize
!= indexSectionOffset
+ indexSectionSize
) {
866 throw Exception("Unexpected resource admin section size. Is: %lu, "
867 "should be: %lu.", adminSectionSize
,
868 indexSectionOffset
+ indexSectionSize
);
870 // set the resource count
871 fResourceCount
= resourceCount
;
876 ResourceFile::_ReadIndex()
879 resource_index_section_header header
;
880 read_exactly(fFile
, kResourceIndexSectionOffset
, &header
,
881 kResourceIndexSectionHeaderSize
,
882 "Failed to read the resource index section header.");
884 // index section offset
885 uint32 indexSectionOffset
= _GetUInt32(header
.rish_index_section_offset
);
886 if (indexSectionOffset
!= kResourceIndexSectionOffset
) {
887 throw Exception("Unexpected resource index section offset. Is: %lu, "
888 "should be: %lu.", indexSectionOffset
,
889 kResourceIndexSectionOffset
);
891 // index section size
892 uint32 expectedIndexSectionSize
= kResourceIndexSectionHeaderSize
893 + kResourceIndexEntrySize
* fResourceCount
;
894 expectedIndexSectionSize
= align_value(expectedIndexSectionSize
,
895 kResourceIndexSectionAlignment
);
896 uint32 indexSectionSize
= _GetUInt32(header
.rish_index_section_size
);
897 if (indexSectionSize
!= expectedIndexSectionSize
) {
898 throw Exception("Unexpected resource index section size. Is: %lu, "
899 "should be: %lu.", indexSectionSize
,
900 expectedIndexSectionSize
);
902 // unknown section offset
903 uint32 unknownSectionOffset
904 = _GetUInt32(header
.rish_unknown_section_offset
);
905 if (unknownSectionOffset
!= indexSectionOffset
+ indexSectionSize
) {
906 throw Exception("Unexpected resource index section size. Is: %lu, "
907 "should be: %lu.", unknownSectionOffset
,
908 indexSectionOffset
+ indexSectionSize
);
910 // unknown section size
911 uint32 unknownSectionSize
= _GetUInt32(header
.rish_unknown_section_size
);
912 if (unknownSectionSize
!= kUnknownResourceSectionSize
) {
913 throw Exception("Unexpected resource index section offset. Is: %lu, "
914 "should be: %lu.", unknownSectionOffset
,
915 kUnknownResourceSectionSize
);
917 // info table offset and size
918 uint32 infoTableOffset
= _GetUInt32(header
.rish_info_table_offset
);
919 uint32 infoTableSize
= _GetUInt32(header
.rish_info_table_size
);
920 if (infoTableOffset
+ infoTableSize
> fFileSize
)
921 throw Exception("Invalid info table location.");
922 fInfoTableItem
= new ResourceItem
;
923 fInfoTableItem
->SetLocation(infoTableOffset
, infoTableSize
);
924 // read the index entries
925 uint32 indexTableOffset
= indexSectionOffset
926 + kResourceIndexSectionHeaderSize
;
927 int32 maxResourceCount
= (unknownSectionOffset
- indexTableOffset
)
928 / kResourceIndexEntrySize
;
929 int32 actualResourceCount
= 0;
930 bool tableEndReached
= false;
931 for (int32 i
= 0; !tableEndReached
&& i
< maxResourceCount
; i
++) {
933 tableEndReached
= !_ReadIndexEntry(i
, indexTableOffset
,
934 (i
>= fResourceCount
));
935 if (!tableEndReached
)
936 actualResourceCount
++;
938 // check resource count
939 if (actualResourceCount
!= fResourceCount
) {
940 if (actualResourceCount
> fResourceCount
) {
941 Warnings::AddCurrentWarning("Resource index table contains "
942 "%ld entries, although it should be "
943 "%ld only.", actualResourceCount
,
946 fResourceCount
= actualResourceCount
;
952 ResourceFile::_ReadIndexEntry(int32 index
, uint32 tableOffset
, bool peekAhead
)
955 resource_index_entry entry
;
957 off_t entryOffset
= tableOffset
+ index
* kResourceIndexEntrySize
;
958 read_exactly(fFile
, entryOffset
, &entry
, kResourceIndexEntrySize
,
959 "Failed to read a resource index entry.");
960 // check, if the end is reached early
961 if (result
&& check_pattern(entryOffset
, &entry
,
962 kResourceIndexEntrySize
/ 4, fHostEndianess
)) {
964 Warnings::AddCurrentWarning("Unexpected end of resource index "
965 "table at index: %ld (/%ld).",
966 index
+ 1, fResourceCount
);
970 uint32 offset
= _GetUInt32(entry
.rie_offset
);
971 uint32 size
= _GetUInt32(entry
.rie_size
);
972 // check the location
973 if (result
&& offset
+ size
> fFileSize
) {
975 Warnings::AddCurrentWarning("Invalid data after resource index "
978 throw Exception("Invalid resource index entry: index: %ld, "
979 "offset: %lu (%lx), size: %lu (%lx).", index
+ 1,
980 offset
, offset
, size
, size
);
986 ResourceItem
* item
= new ResourceItem
;
987 item
->SetLocation(offset
, size
);
988 AddItem(item
, index
);
995 ResourceFile::_ReadInfoTable()
997 status_t error
= B_OK
;
998 error
= fInfoTableItem
->LoadData(fFile
);
1000 throw Exception(error
, "Failed to read resource info table.");
1001 const void* tableData
= fInfoTableItem
->GetData();
1002 int32 dataSize
= fInfoTableItem
->GetSize();
1004 bool* readIndices
= new bool[fResourceCount
+ 1]; // + 1 => always > 0
1005 for (int32 i
= 0; i
< fResourceCount
; i
++)
1006 readIndices
[i
] = false;
1007 AutoDeleter
<bool> deleter(readIndices
, true);
1008 MemArea
area(tableData
, dataSize
);
1009 const void* data
= tableData
;
1010 // check the table end/check sum
1011 if (_ReadInfoTableEnd(data
, dataSize
))
1012 dataSize
-= kResourceInfoTableEndSize
;
1014 int32 resourceIndex
= 1;
1015 uint32 minRemainderSize
1016 = kMinResourceInfoBlockSize
+ kResourceInfoSeparatorSize
;
1017 while (area
.check(data
, minRemainderSize
)) {
1018 // read a resource block
1019 if (!area
.check(data
, kMinResourceInfoBlockSize
)) {
1020 throw Exception("Unexpected end of resource info table at index "
1021 "%ld.", resourceIndex
);
1023 const resource_info_block
* infoBlock
1024 = (const resource_info_block
*)data
;
1025 type_code type
= _GetUInt32(infoBlock
->rib_type
);
1026 // read the infos of this block
1027 const resource_info
* info
= infoBlock
->rib_info
;
1029 data
= _ReadResourceInfo(area
, info
, type
, readIndices
);
1030 // prepare for next iteration, if there is another info
1031 if (!area
.check(data
, kResourceInfoSeparatorSize
)) {
1032 throw Exception("Unexpected end of resource info table after "
1033 "index %ld.", resourceIndex
);
1035 const resource_info_separator
* separator
1036 = (const resource_info_separator
*)data
;
1037 if (_GetUInt32(separator
->ris_value1
) == 0xffffffff
1038 && _GetUInt32(separator
->ris_value2
) == 0xffffffff) {
1041 data
= skip_bytes(data
, kResourceInfoSeparatorSize
);
1043 // another info follows
1044 info
= (const resource_info
*)data
;
1048 // end of the info block
1050 // handle special case: empty resource info table
1051 if (resourceIndex
== 1) {
1052 if (!area
.check(data
, kResourceInfoSeparatorSize
)) {
1053 throw Exception("Unexpected end of resource info table.");
1055 const resource_info_separator
* tableTerminator
1056 = (const resource_info_separator
*)data
;
1057 if (_GetUInt32(tableTerminator
->ris_value1
) != 0xffffffff
1058 || _GetUInt32(tableTerminator
->ris_value2
) != 0xffffffff) {
1059 throw Exception("The resource info table ought to be empty, but "
1060 "is not properly terminated.");
1062 data
= skip_bytes(data
, kResourceInfoSeparatorSize
);
1064 // Check, if the correct number of bytes are remaining.
1065 uint32 bytesLeft
= (const char*)tableData
+ dataSize
- (const char*)data
;
1066 if (bytesLeft
!= 0) {
1067 throw Exception("Error at the end of the resource info table: %lu "
1068 "bytes are remaining.", bytesLeft
);
1070 // check, if all items have been initialized
1071 for (int32 i
= fResourceCount
- 1; i
>= 0; i
--) {
1072 if (!readIndices
[i
]) {
1073 Warnings::AddCurrentWarning("Resource item at index %ld "
1074 "has no info. Item removed.", i
+ 1);
1075 if (ResourceItem
* item
= RemoveItem(i
))
1082 // _ReadInfoTableEnd
1084 ResourceFile::_ReadInfoTableEnd(const void* data
, int32 dataSize
)
1086 bool hasTableEnd
= true;
1087 if ((uint32
)dataSize
< kResourceInfoSeparatorSize
)
1088 throw Exception("Info table is too short.");
1089 if ((uint32
)dataSize
< kResourceInfoTableEndSize
)
1090 hasTableEnd
= false;
1092 const resource_info_table_end
* tableEnd
1093 = (const resource_info_table_end
*)
1094 skip_bytes(data
, dataSize
- kResourceInfoTableEndSize
);
1095 if (_GetInt32(tableEnd
->rite_terminator
) != 0)
1096 hasTableEnd
= false;
1098 dataSize
-= kResourceInfoTableEndSize
;
1100 uint32 checkSum
= calculate_checksum(data
, dataSize
);
1101 uint32 fileCheckSum
= _GetUInt32(tableEnd
->rite_check_sum
);
1102 if (checkSum
!= fileCheckSum
) {
1103 throw Exception("Invalid resource info table check sum: In "
1104 "file: %lx, calculated: %lx.", fileCheckSum
,
1110 Warnings::AddCurrentWarning("resource info table has no check sum.");
1114 // _ReadResourceInfo
1116 ResourceFile::_ReadResourceInfo(const MemArea
& area
, const resource_info
* info
,
1117 type_code type
, bool* readIndices
)
1119 int32 id
= _GetInt32(info
->ri_id
);
1120 int32 index
= _GetInt32(info
->ri_index
);
1121 uint16 nameSize
= _GetUInt16(info
->ri_name_size
);
1122 const char* name
= info
->ri_name
;
1124 bool ignore
= false;
1126 if (index
< 1 || index
> fResourceCount
) {
1127 Warnings::AddCurrentWarning("Invalid index field in resource "
1128 "info table: %lu.", index
);
1132 if (readIndices
[index
- 1]) {
1133 throw Exception("Multiple resource infos with the same index "
1134 "field: %ld.", index
);
1136 readIndices
[index
- 1] = true;
1139 if (!area
.check(name
, nameSize
)) {
1140 throw Exception("Invalid name size (%d) for index %ld in "
1141 "resource info table.", (int)nameSize
, index
);
1143 // check, if name is null terminated
1144 if (name
[nameSize
- 1] != 0) {
1145 Warnings::AddCurrentWarning("Name for index %ld in "
1146 "resource info table is not null "
1147 "terminated.", index
);
1151 BString
resourceName(name
, nameSize
);
1152 if (ResourceItem
* item
= ItemAt(index
- 1))
1153 item
->SetIdentity(type
, id
, resourceName
.String());
1155 throw Exception("Unexpected error: No resource item at index "
1159 return skip_bytes(name
, nameSize
);