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