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