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