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