xref: /haiku/src/kits/package/hpkg/v1/PackageReaderImplV1.cpp (revision 16c83730262f1e4f0fc69d80744bb36dcfbbe3af)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <package/hpkg/v1/PackageReaderImpl.h>
9 
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <unistd.h>
17 
18 #include <algorithm>
19 #include <new>
20 
21 #include <ByteOrder.h>
22 
23 #include <package/hpkg/v1/HPKGDefsPrivate.h>
24 
25 #include <package/hpkg/DataOutput.h>
26 #include <package/hpkg/ErrorOutput.h>
27 #include <package/hpkg/v1/PackageData.h>
28 #include <package/hpkg/v1/PackageEntry.h>
29 #include <package/hpkg/v1/PackageEntryAttribute.h>
30 #include <package/hpkg/ZlibDecompressor.h>
31 
32 
33 namespace BPackageKit {
34 
35 namespace BHPKG {
36 
37 namespace V1 {
38 
39 namespace BPrivate {
40 
41 
42 //#define TRACE(format...)	printf(format)
43 #define TRACE(format...)	do {} while (false)
44 
45 
46 // maximum TOC size we support reading
47 static const size_t kMaxTOCSize					= 64 * 1024 * 1024;
48 
49 // maximum package attributes size we support reading
50 static const size_t kMaxPackageAttributesSize	= 1 * 1024 * 1024;
51 
52 
53 // #pragma mark - DataAttributeHandler
54 
55 
56 struct PackageReaderImpl::DataAttributeHandler : AttributeHandler {
57 	DataAttributeHandler(BPackageData* data)
58 		:
59 		fData(data)
60 	{
61 	}
62 
63 	static status_t InitData(AttributeHandlerContext* context,
64 		BPackageData* data, const AttributeValue& value)
65 	{
66 		if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE)
67 			data->SetData(value.data.size, value.data.raw);
68 		else
69 			data->SetData(value.data.size, value.data.offset);
70 
71 		data->SetUncompressedSize(value.data.size);
72 
73 		return B_OK;
74 	}
75 
76 	static status_t Create(AttributeHandlerContext* context,
77 		BPackageData* data, const AttributeValue& value,
78 		AttributeHandler*& _handler)
79 	{
80 		DataAttributeHandler* handler = new(std::nothrow) DataAttributeHandler(
81 			data);
82 		if (handler == NULL)
83 			return B_NO_MEMORY;
84 
85 		InitData(context, data, value);
86 
87 		_handler = handler;
88 		return B_OK;
89 	}
90 
91 	virtual status_t HandleAttribute(AttributeHandlerContext* context,
92 		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
93 	{
94 		switch (id) {
95 			case B_HPKG_ATTRIBUTE_ID_DATA_SIZE:
96 				fData->SetUncompressedSize(value.unsignedInt);
97 				return B_OK;
98 
99 			case B_HPKG_ATTRIBUTE_ID_DATA_COMPRESSION:
100 			{
101 				switch (value.unsignedInt) {
102 					case B_HPKG_COMPRESSION_NONE:
103 					case B_HPKG_COMPRESSION_ZLIB:
104 						break;
105 					default:
106 						context->errorOutput->PrintError("Error: Invalid "
107 							"compression type for data (%llu)\n",
108 							value.unsignedInt);
109 						return B_BAD_DATA;
110 				}
111 
112 				fData->SetCompression(value.unsignedInt);
113 				return B_OK;
114 			}
115 
116 			case B_HPKG_ATTRIBUTE_ID_DATA_CHUNK_SIZE:
117 				fData->SetChunkSize(value.unsignedInt);
118 				return B_OK;
119 		}
120 
121 		return AttributeHandler::HandleAttribute(context, id, value, _handler);
122 	}
123 
124 private:
125 	BPackageData*	fData;
126 };
127 
128 
129 // #pragma mark - AttributeAttributeHandler
130 
131 
132 struct PackageReaderImpl::AttributeAttributeHandler : AttributeHandler {
133 	AttributeAttributeHandler(BPackageEntry* entry, const char* name)
134 		:
135 		fEntry(entry),
136 		fAttribute(name)
137 	{
138 	}
139 
140 	virtual status_t HandleAttribute(AttributeHandlerContext* context,
141 		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
142 	{
143 		switch (id) {
144 			case B_HPKG_ATTRIBUTE_ID_DATA:
145 				if (_handler != NULL) {
146 					return DataAttributeHandler::Create(context,
147 						&fAttribute.Data(), value, *_handler);
148 				}
149 				return DataAttributeHandler::InitData(context,
150 					&fAttribute.Data(), value);
151 
152 			case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE_TYPE:
153 				fAttribute.SetType(value.unsignedInt);
154 				return B_OK;
155 		}
156 
157 		return AttributeHandler::HandleAttribute(context, id, value, _handler);
158 	}
159 
160 	virtual status_t Delete(AttributeHandlerContext* context)
161 	{
162 		status_t error = context->packageContentHandler->HandleEntryAttribute(
163 			fEntry, &fAttribute);
164 
165 		delete this;
166 		return error;
167 	}
168 
169 private:
170 	BPackageEntry*			fEntry;
171 	BPackageEntryAttribute	fAttribute;
172 };
173 
174 
175 // #pragma mark - EntryAttributeHandler
176 
177 
178 struct PackageReaderImpl::EntryAttributeHandler : AttributeHandler {
179 	EntryAttributeHandler(AttributeHandlerContext* context,
180 		BPackageEntry* parentEntry, const char* name)
181 		:
182 		fEntry(parentEntry, name),
183 		fNotified(false)
184 	{
185 		_SetFileType(context, B_HPKG_DEFAULT_FILE_TYPE);
186 	}
187 
188 	static status_t Create(AttributeHandlerContext* context,
189 		BPackageEntry* parentEntry, const char* name,
190 		AttributeHandler*& _handler)
191 	{
192 		// check name
193 		if (name[0] == '\0' || strcmp(name, ".") == 0
194 			|| strcmp(name, "..") == 0 || strchr(name, '/') != NULL) {
195 			context->errorOutput->PrintError("Error: Invalid package: Invalid "
196 				"entry name: \"%s\"\n", name);
197 			return B_BAD_DATA;
198 		}
199 
200 		// create handler
201 		EntryAttributeHandler* handler = new(std::nothrow)
202 			EntryAttributeHandler(context, parentEntry, name);
203 		if (handler == NULL)
204 			return B_NO_MEMORY;
205 
206 		_handler = handler;
207 		return B_OK;
208 	}
209 
210 	virtual status_t HandleAttribute(AttributeHandlerContext* context,
211 		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
212 	{
213 		switch (id) {
214 			case B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY:
215 			{
216 				status_t error = _Notify(context);
217 				if (error != B_OK)
218 					return error;
219 
220 //TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string);
221 				if (_handler != NULL) {
222 					return EntryAttributeHandler::Create(context, &fEntry,
223 						value.string, *_handler);
224 				}
225 				return B_OK;
226 			}
227 
228 			case B_HPKG_ATTRIBUTE_ID_FILE_TYPE:
229 				return _SetFileType(context, value.unsignedInt);
230 
231 			case B_HPKG_ATTRIBUTE_ID_FILE_PERMISSIONS:
232 				fEntry.SetPermissions(value.unsignedInt);
233 				return B_OK;
234 
235 			case B_HPKG_ATTRIBUTE_ID_FILE_USER:
236 			case B_HPKG_ATTRIBUTE_ID_FILE_GROUP:
237 				// TODO:...
238 				break;
239 
240 			case B_HPKG_ATTRIBUTE_ID_FILE_ATIME:
241 				fEntry.SetAccessTime(value.unsignedInt);
242 				return B_OK;
243 
244 			case B_HPKG_ATTRIBUTE_ID_FILE_MTIME:
245 				fEntry.SetModifiedTime(value.unsignedInt);
246 				return B_OK;
247 
248 			case B_HPKG_ATTRIBUTE_ID_FILE_CRTIME:
249 				fEntry.SetCreationTime(value.unsignedInt);
250 				return B_OK;
251 
252 			case B_HPKG_ATTRIBUTE_ID_FILE_ATIME_NANOS:
253 				fEntry.SetAccessTimeNanos(value.unsignedInt);
254 				return B_OK;
255 
256 			case B_HPKG_ATTRIBUTE_ID_FILE_MTIME_NANOS:
257 				fEntry.SetModifiedTimeNanos(value.unsignedInt);
258 				return B_OK;
259 
260 			case B_HPKG_ATTRIBUTE_ID_FILE_CRTIM_NANOS:
261 				fEntry.SetCreationTimeNanos(value.unsignedInt);
262 				return B_OK;
263 
264 			case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE:
265 			{
266 				status_t error = _Notify(context);
267 				if (error != B_OK)
268 					return error;
269 
270 				if (_handler != NULL) {
271 					*_handler = new(std::nothrow) AttributeAttributeHandler(
272 						&fEntry, value.string);
273 					if (*_handler == NULL)
274 						return B_NO_MEMORY;
275 					return B_OK;
276 				} else {
277 					BPackageEntryAttribute attribute(value.string);
278 					return context->packageContentHandler->HandleEntryAttribute(
279 						&fEntry, &attribute);
280 				}
281 			}
282 
283 			case B_HPKG_ATTRIBUTE_ID_DATA:
284 				if (_handler != NULL) {
285 					return DataAttributeHandler::Create(context, &fEntry.Data(),
286 						value, *_handler);
287 				}
288 				return DataAttributeHandler::InitData(context, &fEntry.Data(),
289 					value);
290 
291 			case B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH:
292 				fEntry.SetSymlinkPath(value.string);
293 				return B_OK;
294 		}
295 
296 		return AttributeHandler::HandleAttribute(context, id, value, _handler);
297 	}
298 
299 	virtual status_t Delete(AttributeHandlerContext* context)
300 	{
301 		// notify if not done yet
302 		status_t error = _Notify(context);
303 
304 		// notify done
305 		if (error == B_OK)
306 			error = context->packageContentHandler->HandleEntryDone(&fEntry);
307 		else
308 			context->packageContentHandler->HandleEntryDone(&fEntry);
309 
310 		delete this;
311 		return error;
312 	}
313 
314 private:
315 	status_t _Notify(AttributeHandlerContext* context)
316 	{
317 		if (fNotified)
318 			return B_OK;
319 
320 		fNotified = true;
321 		return context->packageContentHandler->HandleEntry(&fEntry);
322 	}
323 
324 	status_t _SetFileType(AttributeHandlerContext* context, uint64 fileType)
325 	{
326 		switch (fileType) {
327 			case B_HPKG_FILE_TYPE_FILE:
328 				fEntry.SetType(S_IFREG);
329 				fEntry.SetPermissions(B_HPKG_DEFAULT_FILE_PERMISSIONS);
330 				break;
331 
332 			case B_HPKG_FILE_TYPE_DIRECTORY:
333 				fEntry.SetType(S_IFDIR);
334 				fEntry.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS);
335 				break;
336 
337 			case B_HPKG_FILE_TYPE_SYMLINK:
338 				fEntry.SetType(S_IFLNK);
339 				fEntry.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS);
340 				break;
341 
342 			default:
343 				context->errorOutput->PrintError("Error: Invalid file type for "
344 					"package entry (%llu)\n", fileType);
345 				return B_BAD_DATA;
346 		}
347 		return B_OK;
348 	}
349 
350 private:
351 	BPackageEntry	fEntry;
352 	bool			fNotified;
353 };
354 
355 
356 // #pragma mark - RootAttributeHandler
357 
358 
359 struct PackageReaderImpl::RootAttributeHandler : PackageAttributeHandler {
360 	typedef PackageAttributeHandler inherited;
361 
362 	virtual status_t HandleAttribute(AttributeHandlerContext* context,
363 		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
364 	{
365 		if (id == B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY) {
366 			if (_handler != NULL) {
367 				return EntryAttributeHandler::Create(context, NULL,
368 					value.string, *_handler);
369 			}
370 			return B_OK;
371 		}
372 
373 		return inherited::HandleAttribute(context, id, value, _handler);
374 	}
375 };
376 
377 
378 // #pragma mark - PackageReaderImpl
379 
380 
381 PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput)
382 	:
383 	inherited(errorOutput),
384 	fTOCSection("TOC")
385 {
386 }
387 
388 
389 PackageReaderImpl::~PackageReaderImpl()
390 {
391 }
392 
393 
394 status_t
395 PackageReaderImpl::Init(const char* fileName)
396 {
397 	// open file
398 	int fd = open(fileName, O_RDONLY);
399 	if (fd < 0) {
400 		ErrorOutput()->PrintError("Error: Failed to open package file \"%s\": "
401 			"%s\n", fileName, strerror(errno));
402 		return errno;
403 	}
404 
405 	return Init(fd, true);
406 }
407 
408 
409 status_t
410 PackageReaderImpl::Init(int fd, bool keepFD)
411 {
412 	status_t error = inherited::Init(fd, keepFD);
413 	if (error != B_OK)
414 		return error;
415 
416 	// stat it
417 	struct stat st;
418 	if (fstat(FD(), &st) < 0) {
419 		ErrorOutput()->PrintError("Error: Failed to access package file: %s\n",
420 			strerror(errno));
421 		return errno;
422 	}
423 
424 	// read the header
425 	hpkg_header header;
426 	if ((error = ReadBuffer(0, &header, sizeof(header))) != B_OK)
427 		return error;
428 
429 	// check the header
430 
431 	// magic
432 	if (B_BENDIAN_TO_HOST_INT32(header.magic) != B_HPKG_MAGIC) {
433 		ErrorOutput()->PrintError("Error: Invalid package file: Invalid "
434 			"magic\n");
435 		return B_BAD_DATA;
436 	}
437 
438 	// version
439 	if (B_BENDIAN_TO_HOST_INT16(header.version) != B_HPKG_VERSION) {
440 		ErrorOutput()->PrintError("Error: Invalid/unsupported package file "
441 			"version (%d)\n", B_BENDIAN_TO_HOST_INT16(header.version));
442 		return B_MISMATCHED_VALUES;
443 	}
444 
445 	// header size
446 	fHeapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size);
447 	if ((size_t)fHeapOffset < sizeof(hpkg_header)) {
448 		ErrorOutput()->PrintError("Error: Invalid package file: Invalid header "
449 			"size (%llu)\n", fHeapOffset);
450 		return B_BAD_DATA;
451 	}
452 
453 	// total size
454 	fTotalSize = B_BENDIAN_TO_HOST_INT64(header.total_size);
455 	if (fTotalSize != (uint64)st.st_size) {
456 		ErrorOutput()->PrintError("Error: Invalid package file: Total size in "
457 			"header (%llu) doesn't agree with total file size (%lld)\n",
458 			fTotalSize, st.st_size);
459 		return B_BAD_DATA;
460 	}
461 
462 	// package attributes length and compression
463 	fPackageAttributesSection.compression
464 		= B_BENDIAN_TO_HOST_INT32(header.attributes_compression);
465 	fPackageAttributesSection.compressedLength
466 		= B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed);
467 	fPackageAttributesSection.uncompressedLength
468 		= B_BENDIAN_TO_HOST_INT32(header.attributes_length_uncompressed);
469 	fPackageAttributesSection.stringsLength
470 		= B_BENDIAN_TO_HOST_INT32(header.attributes_strings_length);
471 	fPackageAttributesSection.stringsCount
472 		= B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count);
473 
474 	if (const char* errorString = CheckCompression(
475 		fPackageAttributesSection)) {
476 		ErrorOutput()->PrintError("Error: Invalid package file: package "
477 			"attributes section: %s\n", errorString);
478 		return B_BAD_DATA;
479 	}
480 
481 	// TOC length and compression
482 	fTOCSection.compression = B_BENDIAN_TO_HOST_INT32(header.toc_compression);
483 	fTOCSection.compressedLength
484 		= B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed);
485 	fTOCSection.uncompressedLength
486 		= B_BENDIAN_TO_HOST_INT64(header.toc_length_uncompressed);
487 
488 	if (const char* errorString = CheckCompression(fTOCSection)) {
489 		ErrorOutput()->PrintError("Error: Invalid package file: TOC section: "
490 			"%s\n", errorString);
491 		return B_BAD_DATA;
492 	}
493 
494 	// TOC subsections
495 	fTOCSection.stringsLength
496 		= B_BENDIAN_TO_HOST_INT64(header.toc_strings_length);
497 	fTOCSection.stringsCount
498 		= B_BENDIAN_TO_HOST_INT64(header.toc_strings_count);
499 
500 	if (fTOCSection.stringsLength > fTOCSection.uncompressedLength
501 		|| fTOCSection.stringsCount > fTOCSection.stringsLength) {
502 		ErrorOutput()->PrintError("Error: Invalid package file: Invalid TOC "
503 			"subsections description\n");
504 		return B_BAD_DATA;
505 	}
506 
507 	// check whether the sections fit together
508 	if (fPackageAttributesSection.compressedLength > fTotalSize
509 		|| fTOCSection.compressedLength
510 			> fTotalSize - fPackageAttributesSection.compressedLength
511 		|| fHeapOffset
512 			> fTotalSize - fPackageAttributesSection.compressedLength
513 				- fTOCSection.compressedLength) {
514 		ErrorOutput()->PrintError("Error: Invalid package file: The sum of the "
515 			"sections sizes is greater than the package size\n");
516 		return B_BAD_DATA;
517 	}
518 
519 	fPackageAttributesSection.offset
520 		= fTotalSize - fPackageAttributesSection.compressedLength;
521 	fTOCSection.offset = fPackageAttributesSection.offset
522 		- fTOCSection.compressedLength;
523 	fHeapSize = fTOCSection.offset - fHeapOffset;
524 
525 	// TOC size sanity check
526 	if (fTOCSection.uncompressedLength > kMaxTOCSize) {
527 		ErrorOutput()->PrintError("Error: Package file TOC section size "
528 			"is %llu bytes. This is beyond the reader's sanity limit\n",
529 			fTOCSection.uncompressedLength);
530 		return B_UNSUPPORTED;
531 	}
532 
533 	// package attributes size sanity check
534 	if (fPackageAttributesSection.uncompressedLength
535 			> kMaxPackageAttributesSize) {
536 		ErrorOutput()->PrintError(
537 			"Error: Package file package attributes section size "
538 			"is %llu bytes. This is beyond the reader's sanity limit\n",
539 			fPackageAttributesSection.uncompressedLength);
540 		return B_UNSUPPORTED;
541 	}
542 
543 	// read in the complete TOC
544 	fTOCSection.data
545 		= new(std::nothrow) uint8[fTOCSection.uncompressedLength];
546 	if (fTOCSection.data == NULL) {
547 		ErrorOutput()->PrintError("Error: Out of memory!\n");
548 		return B_NO_MEMORY;
549 	}
550 	error = ReadCompressedBuffer(fTOCSection);
551 	if (error != B_OK)
552 		return error;
553 
554 	// read in the complete package attributes section
555 	fPackageAttributesSection.data
556 		= new(std::nothrow) uint8[fPackageAttributesSection.uncompressedLength];
557 	if (fPackageAttributesSection.data == NULL) {
558 		ErrorOutput()->PrintError("Error: Out of memory!\n");
559 		return B_NO_MEMORY;
560 	}
561 	error = ReadCompressedBuffer(fPackageAttributesSection);
562 	if (error != B_OK)
563 		return error;
564 
565 	// start parsing the TOC
566 	fTOCSection.currentOffset = 0;
567 	SetCurrentSection(&fTOCSection);
568 
569 	// strings
570 	error = ParseStrings();
571 	if (error != B_OK)
572 		return error;
573 
574 	// parse strings from package attributes section
575 	fPackageAttributesSection.currentOffset = 0;
576 	SetCurrentSection(&fPackageAttributesSection);
577 
578 	// strings
579 	error = ParseStrings();
580 	if (error != B_OK)
581 		return error;
582 
583 	SetCurrentSection(NULL);
584 
585 	return B_OK;
586 }
587 
588 
589 status_t
590 PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler)
591 {
592 	AttributeHandlerContext context(ErrorOutput(), contentHandler,
593 		B_HPKG_SECTION_PACKAGE_ATTRIBUTES);
594 	RootAttributeHandler rootAttributeHandler;
595 
596 	status_t error
597 		= ParsePackageAttributesSection(&context, &rootAttributeHandler);
598 
599 	if (error == B_OK) {
600 		context.section = B_HPKG_SECTION_PACKAGE_TOC;
601 		error = _ParseTOC(&context, &rootAttributeHandler);
602 	}
603 
604 	return error;
605 }
606 
607 
608 status_t
609 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler)
610 {
611 	AttributeHandlerContext context(ErrorOutput(), contentHandler,
612 		B_HPKG_SECTION_PACKAGE_ATTRIBUTES);
613 	LowLevelAttributeHandler rootAttributeHandler;
614 
615 	status_t error
616 		= ParsePackageAttributesSection(&context, &rootAttributeHandler);
617 
618 	if (error == B_OK) {
619 		context.section = B_HPKG_SECTION_PACKAGE_TOC;
620 		error = _ParseTOC(&context, &rootAttributeHandler);
621 	}
622 
623 	return error;
624 }
625 
626 
627 status_t
628 PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context,
629 	AttributeHandler* rootAttributeHandler)
630 {
631 	// parse the TOC
632 	fTOCSection.currentOffset = fTOCSection.stringsLength;
633 	SetCurrentSection(&fTOCSection);
634 
635 	// prepare attribute handler context
636 	context->heapOffset = fHeapOffset;
637 	context->heapSize = fHeapSize;
638 
639 	// init the attribute handler stack
640 	rootAttributeHandler->SetLevel(0);
641 	ClearAttributeHandlerStack();
642 	PushAttributeHandler(rootAttributeHandler);
643 
644 	bool sectionHandled;
645 	status_t error = ParseAttributeTree(context, sectionHandled);
646 	if (error == B_OK && sectionHandled) {
647 		if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) {
648 			ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC "
649 				"section\n",
650 				fTOCSection.uncompressedLength - fTOCSection.currentOffset);
651 			error = B_BAD_DATA;
652 		}
653 	}
654 
655 	// clean up on error
656 	if (error != B_OK) {
657 		context->ErrorOccurred();
658 		while (AttributeHandler* handler = PopAttributeHandler()) {
659 			if (handler != rootAttributeHandler)
660 				handler->Delete(context);
661 		}
662 		return error;
663 	}
664 
665 	return B_OK;
666 }
667 
668 
669 status_t
670 PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding,
671 	AttributeValue& _value)
672 {
673 	switch (type) {
674 		case B_HPKG_ATTRIBUTE_TYPE_RAW:
675 		{
676 			uint64 size;
677 			status_t error = ReadUnsignedLEB128(size);
678 			if (error != B_OK)
679 				return error;
680 
681 			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
682 				uint64 offset;
683 				error = ReadUnsignedLEB128(offset);
684 				if (error != B_OK)
685 					return error;
686 
687 				if (offset > fHeapSize || size > fHeapSize - offset) {
688 					ErrorOutput()->PrintError("Error: Invalid %s section: "
689 						"invalid data reference\n", CurrentSection()->name);
690 					return B_BAD_DATA;
691 				}
692 
693 				_value.SetToData(size, fHeapOffset + offset);
694 			} else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
695 				if (size > B_HPKG_MAX_INLINE_DATA_SIZE) {
696 					ErrorOutput()->PrintError("Error: Invalid %s section: "
697 						"inline data too long\n", CurrentSection()->name);
698 					return B_BAD_DATA;
699 				}
700 
701 				const void* buffer;
702 				error = _GetTOCBuffer(size, buffer);
703 				if (error != B_OK)
704 					return error;
705 				_value.SetToData(size, buffer);
706 			} else {
707 				ErrorOutput()->PrintError("Error: Invalid %s section: invalid "
708 					"raw encoding (%u)\n", CurrentSection()->name, encoding);
709 				return B_BAD_DATA;
710 			}
711 
712 			return B_OK;
713 		}
714 
715 		default:
716 			return inherited::ReadAttributeValue(type, encoding, _value);
717 	}
718 }
719 
720 
721 status_t
722 PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer)
723 {
724 	if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) {
725 		ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n",
726 			size);
727 		return B_BAD_DATA;
728 	}
729 
730 	_buffer = fTOCSection.data + fTOCSection.currentOffset;
731 	fTOCSection.currentOffset += size;
732 	return B_OK;
733 }
734 
735 
736 }	// namespace BPrivate
737 
738 }	// namespace V1
739 
740 }	// namespace BHPKG
741 
742 }	// namespace BPackageKit
743