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