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