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
30namespace BPrivate {
31namespace Storage {
32
33
34// ELF defs
35static const uint32	kMaxELFHeaderSize
36	= std::max(sizeof(Elf32_Ehdr), sizeof(Elf64_Ehdr)) + 32;
37static const char	kELFFileMagic[4]			= { 0x7f, 'E', 'L', 'F' };
38
39// sanity bounds
40static const uint32	kMaxResourceCount			= 10000;
41static const uint32	kELFMaxResourceAlignment	= 1024 * 1024 * 10;	// 10 MB
42
43
44// recognized file types (indices into kFileTypeNames)
45enum {
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
55const 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
72static const uint32 kVersionInfoIntCount = 5;
73
74// #pragma mark - helper functions/classes
75
76
77static void
78read_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
94static void
95write_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
111template<typename TV, typename TA>
112static inline TV
113align_value(const TV& value, const TA& alignment)
114{
115	return ((value + alignment - 1) / alignment) * alignment;
116}
117
118
119static uint32
120calculate_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
137static inline const void*
138skip_bytes(const void* buffer, int32 offset)
139{
140	return (const char*)buffer + offset;
141}
142
143
144static inline void*
145skip_bytes(void* buffer, int32 offset)
146{
147	return (char*)buffer + offset;
148}
149
150
151static void
152fill_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
160static void
161fill_pattern(const void* dataBegin, void* buffer, uint32 count)
162{
163	fill_pattern((char*)buffer - (const char*)dataBegin, buffer, count);
164}
165
166
167static void
168fill_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
175static bool
176check_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
195struct 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
210struct 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
223ResourceFile::ResourceFile()
224	:
225	fFile(),
226	fFileType(FILE_TYPE_UNKNOWN),
227	fHostEndianess(true),
228	fEmptyResources(true)
229{
230}
231
232
233ResourceFile::~ResourceFile()
234{
235	Unset();
236}
237
238
239status_t
240ResourceFile::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
259void
260ResourceFile::Unset()
261{
262	fFile.Unset();
263	fFileType = FILE_TYPE_UNKNOWN;
264	fHostEndianess = true;
265	fEmptyResources = true;
266}
267
268
269status_t
270ResourceFile::InitCheck() const
271{
272	return fFile.InitCheck();
273}
274
275
276status_t
277ResourceFile::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
310status_t
311ResourceFile::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
346status_t
347ResourceFile::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
361status_t
362ResourceFile::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
377void
378ResourceFile::_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
456void
457ResourceFile::_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
503template<typename ElfHeader, typename ElfProgramHeader,
504	typename ElfSectionHeader>
505void
506ResourceFile::_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
680void
681ResourceFile::_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, &sectionHeader, 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
730void
731ResourceFile::_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
780void
781ResourceFile::_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
862bool
863ResourceFile::_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
911void
912ResourceFile::_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
1008bool
1009ResourceFile::_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
1040const void*
1041ResourceFile::_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
1091status_t
1092ResourceFile::_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
1290status_t
1291ResourceFile::_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