xref: /haiku/src/kits/package/hpkg/ReaderImplBase.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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/ReaderImplBase.h>
9 
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <algorithm>
16 #include <new>
17 
18 #include <ByteOrder.h>
19 
20 #include <package/hpkg/HPKGDefsPrivate.h>
21 
22 #include <package/hpkg/DataOutput.h>
23 #include <package/hpkg/ErrorOutput.h>
24 #include <package/hpkg/ZlibDecompressor.h>
25 
26 
27 namespace BPackageKit {
28 
29 namespace BHPKG {
30 
31 namespace BPrivate {
32 
33 
34 static const size_t kScratchBufferSize = 64 * 1024;
35 
36 
37 // #pragma mark - AttributeHandlerContext
38 
39 
40 ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext(
41 	BErrorOutput* errorOutput, BPackageContentHandler* packageContentHandler)
42 	:
43 	errorOutput(errorOutput),
44 	packageContentHandler(packageContentHandler),
45 	hasLowLevelHandler(false)
46 {
47 }
48 
49 
50 ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext(
51 	BErrorOutput* errorOutput, BLowLevelPackageContentHandler* lowLevelHandler)
52 	:
53 	errorOutput(errorOutput),
54 	lowLevelHandler(lowLevelHandler),
55 	hasLowLevelHandler(true)
56 {
57 }
58 
59 
60 void
61 ReaderImplBase::AttributeHandlerContext::ErrorOccurred()
62 {
63 	if (hasLowLevelHandler)
64 		lowLevelHandler->HandleErrorOccurred();
65 	else
66 		packageContentHandler->HandleErrorOccurred();
67 }
68 
69 
70 // #pragma mark - AttributeHandler
71 
72 
73 ReaderImplBase::AttributeHandler::~AttributeHandler()
74 {
75 }
76 
77 
78 void
79 ReaderImplBase::AttributeHandler::SetLevel(int level)
80 {
81 	fLevel = level;
82 }
83 
84 
85 status_t
86 ReaderImplBase::AttributeHandler::HandleAttribute(
87 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
88 	AttributeHandler** _handler)
89 {
90 	return B_OK;
91 }
92 
93 
94 status_t
95 ReaderImplBase::AttributeHandler::Delete(AttributeHandlerContext* context)
96 {
97 	delete this;
98 	return B_OK;
99 }
100 
101 
102 // #pragma mark - PackageVersionAttributeHandler
103 
104 
105 ReaderImplBase::PackageVersionAttributeHandler::PackageVersionAttributeHandler(
106 	BPackageInfoAttributeValue& packageInfoValue,
107 	BPackageVersionData& versionData, bool notify)
108 	:
109 	fPackageInfoValue(packageInfoValue),
110 	fPackageVersionData(versionData),
111 	fNotify(notify)
112 {
113 }
114 
115 
116 status_t
117 ReaderImplBase::PackageVersionAttributeHandler::HandleAttribute(
118 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
119 	AttributeHandler** _handler)
120 {
121 	switch (id) {
122 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR:
123 			fPackageVersionData.minor = value.string;
124 			break;
125 
126 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO:
127 			fPackageVersionData.micro = value.string;
128 			break;
129 
130 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE:
131 			fPackageVersionData.release = value.unsignedInt;
132 			break;
133 
134 		default:
135 			context->errorOutput->PrintError("Error: Invalid package "
136 				"attribute section: unexpected package attribute id %d "
137 				"encountered when parsing package version\n", id);
138 			return B_BAD_DATA;
139 	}
140 
141 	return B_OK;
142 }
143 
144 
145 status_t
146 ReaderImplBase::PackageVersionAttributeHandler::Delete(
147 	AttributeHandlerContext* context)
148 {
149 	status_t error = B_OK;
150 	if (fNotify) {
151 		fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION;
152 		error = context->packageContentHandler->HandlePackageAttribute(
153 			fPackageInfoValue);
154 		fPackageInfoValue.Clear();
155 	}
156 
157 	delete this;
158 	return error;
159 }
160 
161 
162 // #pragma mark - PackageResolvableAttributeHandler
163 
164 
165 ReaderImplBase::PackageResolvableAttributeHandler
166 	::PackageResolvableAttributeHandler(
167 		BPackageInfoAttributeValue& packageInfoValue)
168 	:
169 	fPackageInfoValue(packageInfoValue)
170 {
171 }
172 
173 
174 status_t
175 ReaderImplBase::PackageResolvableAttributeHandler::HandleAttribute(
176 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
177 	AttributeHandler** _handler)
178 {
179 	switch (id) {
180 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_TYPE:
181 			fPackageInfoValue.resolvable.type
182 				= (BPackageResolvableType)value.unsignedInt;
183 			break;
184 
185 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR:
186 			fPackageInfoValue.resolvable.haveVersion = true;
187 			fPackageInfoValue.resolvable.version.major = value.string;
188 			if (_handler != NULL) {
189 				*_handler
190 					= new(std::nothrow) PackageVersionAttributeHandler(
191 						fPackageInfoValue,
192 						fPackageInfoValue.resolvable.version, false);
193 				if (*_handler == NULL)
194 					return B_NO_MEMORY;
195 			}
196 			break;
197 
198 		default:
199 			context->errorOutput->PrintError("Error: Invalid package "
200 				"attribute section: unexpected package attribute id %d "
201 				"encountered when parsing package resolvable\n", id);
202 			return B_BAD_DATA;
203 	}
204 
205 	return B_OK;
206 }
207 
208 
209 status_t
210 ReaderImplBase::PackageResolvableAttributeHandler::Delete(
211 	AttributeHandlerContext* context)
212 {
213 	status_t error = context->packageContentHandler->HandlePackageAttribute(
214 		fPackageInfoValue);
215 	fPackageInfoValue.Clear();
216 
217 	delete this;
218 	return error;
219 }
220 
221 
222 // #pragma mark - PackageResolvableExpressionAttributeHandler
223 
224 
225 ReaderImplBase::PackageResolvableExpressionAttributeHandler
226 	::PackageResolvableExpressionAttributeHandler(
227 		BPackageInfoAttributeValue& packageInfoValue)
228 	:
229 	fPackageInfoValue(packageInfoValue)
230 {
231 }
232 
233 
234 status_t
235 ReaderImplBase::PackageResolvableExpressionAttributeHandler::HandleAttribute(
236 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
237 	AttributeHandler** _handler)
238 {
239 	switch (id) {
240 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR:
241 			if (value.unsignedInt >= B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
242 				context->errorOutput->PrintError(
243 					"Error: Invalid package attribute section: invalid "
244 					"package resolvable operator %lld encountered\n",
245 					value.unsignedInt);
246 				return B_BAD_DATA;
247 			}
248 			fPackageInfoValue.resolvableExpression.op
249 				= (BPackageResolvableOperator)value.unsignedInt;
250 			break;
251 
252 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR:
253 			fPackageInfoValue.resolvableExpression.haveOpAndVersion = true;
254 			fPackageInfoValue.resolvableExpression.version.major
255 				= value.string;
256 			if (_handler != NULL) {
257 				*_handler
258 					= new(std::nothrow) PackageVersionAttributeHandler(
259 						fPackageInfoValue,
260 						fPackageInfoValue.resolvableExpression.version,
261 						false);
262 				if (*_handler == NULL)
263 					return B_NO_MEMORY;
264 			}
265 			return B_OK;
266 
267 		default:
268 			context->errorOutput->PrintError("Error: Invalid package "
269 				"attribute section: unexpected package attribute id %d "
270 				"encountered when parsing package resolvable-expression\n",
271 				id);
272 			return B_BAD_DATA;
273 	}
274 
275 	return B_OK;
276 }
277 
278 
279 status_t
280 ReaderImplBase::PackageResolvableExpressionAttributeHandler::Delete(
281 	AttributeHandlerContext* context)
282 {
283 	status_t error = context->packageContentHandler->HandlePackageAttribute(
284 		fPackageInfoValue);
285 	fPackageInfoValue.Clear();
286 
287 	delete this;
288 	return error;
289 }
290 
291 
292 // #pragma mark - PackageAttributeHandler
293 
294 
295 status_t
296 ReaderImplBase::PackageAttributeHandler::HandleAttribute(
297 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
298 	AttributeHandler** _handler)
299 {
300 	switch (id) {
301 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME:
302 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_NAME, value.string);
303 			break;
304 
305 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY:
306 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_SUMMARY, value.string);
307 			break;
308 
309 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION:
310 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_DESCRIPTION,
311 				value.string);
312 			break;
313 
314 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR:
315 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_VENDOR, value.string);
316 			break;
317 
318 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER:
319 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_PACKAGER, value.string);
320 			break;
321 
322 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS:
323 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_FLAGS,
324 				(uint32)value.unsignedInt);
325 			break;
326 
327 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE:
328 			if (value.unsignedInt
329 					>= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
330 				context->errorOutput->PrintError(
331 					"Error: Invalid package attribute section: "
332 					"Invalid package architecture %lld encountered\n",
333 					value.unsignedInt);
334 				return B_BAD_DATA;
335 			}
336 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_ARCHITECTURE,
337 				(uint8)value.unsignedInt);
338 			break;
339 
340 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR:
341 			fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION;
342 			fPackageInfoValue.version.major = value.string;
343 			if (_handler != NULL) {
344 				*_handler
345 					= new(std::nothrow) PackageVersionAttributeHandler(
346 						fPackageInfoValue, fPackageInfoValue.version, true);
347 				if (*_handler == NULL)
348 					return B_NO_MEMORY;
349 			}
350 			break;
351 
352 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT:
353 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_COPYRIGHTS,
354 				value.string);
355 			break;
356 
357 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE:
358 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_LICENSES,
359 				value.string);
360 			break;
361 
362 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES:
363 			fPackageInfoValue.resolvable.name = value.string;
364 			fPackageInfoValue.attributeID = B_PACKAGE_INFO_PROVIDES;
365 			if (_handler != NULL) {
366 				*_handler
367 					= new(std::nothrow) PackageResolvableAttributeHandler(
368 						fPackageInfoValue);
369 				if (*_handler == NULL)
370 					return B_NO_MEMORY;
371 			}
372 			break;
373 
374 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES:
375 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS:
376 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS:
377 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS:
378 			fPackageInfoValue.resolvableExpression.name = value.string;
379 			switch (id) {
380 				case B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES:
381 					fPackageInfoValue.attributeID = B_PACKAGE_INFO_REQUIRES;
382 					break;
383 
384 				case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS:
385 					fPackageInfoValue.attributeID
386 						= B_PACKAGE_INFO_SUPPLEMENTS;
387 					break;
388 
389 				case B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS:
390 					fPackageInfoValue.attributeID
391 						= B_PACKAGE_INFO_CONFLICTS;
392 					break;
393 
394 				case B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS:
395 					fPackageInfoValue.attributeID = B_PACKAGE_INFO_FRESHENS;
396 					break;
397 			}
398 			if (_handler != NULL) {
399 				*_handler = new(std::nothrow)
400 					PackageResolvableExpressionAttributeHandler(
401 						fPackageInfoValue);
402 				if (*_handler == NULL)
403 					return B_NO_MEMORY;
404 			}
405 			break;
406 
407 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES:
408 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_REPLACES, value.string);
409 			break;
410 
411 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM:
412 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_CHECKSUM, value.string);
413 			break;
414 
415 		default:
416 			context->errorOutput->PrintError(
417 				"Error: Invalid package attribute section: unexpected "
418 				"package attribute id %d encountered\n", id);
419 			return B_BAD_DATA;
420 	}
421 
422 	// notify unless the current attribute has children, in which case
423 	// the child-handler will notify when it's done
424 	if (_handler == NULL) {
425 		status_t error = context->packageContentHandler
426 			->HandlePackageAttribute(fPackageInfoValue);
427 		fPackageInfoValue.Clear();
428 		if (error != B_OK)
429 			return error;
430 	}
431 
432 	return B_OK;
433 }
434 
435 
436 // #pragma mark - LowLevelAttributeHandler
437 
438 
439 ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler()
440 	:
441 	fToken(NULL),
442 	fID(B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
443 {
444 }
445 
446 
447 ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler(uint8 id,
448 	const BPackageAttributeValue& value, void* token)
449 	:
450 	fToken(token),
451 	fID(id),
452 	fValue(value)
453 {
454 }
455 
456 
457 status_t
458 ReaderImplBase::LowLevelAttributeHandler::HandleAttribute(
459 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
460 	AttributeHandler** _handler)
461 {
462 	// notify the content handler
463 	void* token;
464 	status_t error = context->lowLevelHandler->HandleAttribute(
465 		(BHPKGAttributeID)id, value, fToken, token);
466 	if (error != B_OK)
467 		return error;
468 
469 	// create a subhandler for the attribute, if it has children
470 	if (_handler != NULL) {
471 		*_handler = new(std::nothrow) LowLevelAttributeHandler(id, value,
472 			token);
473 		if (*_handler == NULL) {
474 			context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id,
475 				value, token);
476 			return B_NO_MEMORY;
477 		}
478 		return B_OK;
479 	}
480 
481 	// no children -- just call the done hook
482 	return context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id,
483 		value, token);
484 }
485 
486 
487 status_t
488 ReaderImplBase::LowLevelAttributeHandler::Delete(
489 	AttributeHandlerContext* context)
490 {
491 	status_t error = B_OK;
492 	if (fID != B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) {
493 		error = context->lowLevelHandler->HandleAttributeDone(
494 			(BHPKGAttributeID)fID, fValue, fToken);
495 	}
496 
497 	delete this;
498 	return error;
499 }
500 
501 
502 // #pragma mark - ReaderImplBase
503 
504 
505 ReaderImplBase::ReaderImplBase(BErrorOutput* errorOutput)
506 	:
507 	fPackageAttributesSection("package attributes"),
508 	fErrorOutput(errorOutput),
509 	fFD(-1),
510 	fOwnsFD(false),
511 	fCurrentSection(NULL),
512 	fScratchBuffer(NULL),
513 	fScratchBufferSize(0)
514 {
515 }
516 
517 
518 ReaderImplBase::~ReaderImplBase()
519 {
520 	if (fOwnsFD && fFD >= 0)
521 		close(fFD);
522 
523 	delete[] fScratchBuffer;
524 }
525 
526 
527 status_t
528 ReaderImplBase::Init(int fd, bool keepFD)
529 {
530 	fFD = fd;
531 	fOwnsFD = keepFD;
532 
533 	// allocate a scratch buffer
534 	fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize];
535 	if (fScratchBuffer == NULL) {
536 		fErrorOutput->PrintError("Error: Out of memory!\n");
537 		return B_NO_MEMORY;
538 	}
539 	fScratchBufferSize = kScratchBufferSize;
540 
541 	return B_OK;
542 }
543 
544 
545 const char*
546 ReaderImplBase::CheckCompression(const SectionInfo& section) const
547 {
548 	switch (section.compression) {
549 		case B_HPKG_COMPRESSION_NONE:
550 			if (section.compressedLength != section.uncompressedLength) {
551 				return "Uncompressed, but compressed and uncompressed length "
552 					"don't match";
553 			}
554 			return NULL;
555 
556 		case B_HPKG_COMPRESSION_ZLIB:
557 			if (section.compressedLength >= section.uncompressedLength) {
558 				return "Compressed, but compressed length is not less than "
559 					"uncompressed length";
560 			}
561 			return NULL;
562 
563 		default:
564 			return "Invalid compression algorithm ID";
565 	}
566 }
567 
568 
569 status_t
570 ReaderImplBase::ParseStrings()
571 {
572 	// allocate table
573 	fCurrentSection->strings
574 		= new(std::nothrow) char*[fCurrentSection->stringsCount];
575 	if (fCurrentSection->strings == NULL) {
576 		fErrorOutput->PrintError("Error: Out of memory!\n");
577 		return B_NO_MEMORY;
578 	}
579 
580 	// parse the section and fill the table
581 	char* position
582 		= (char*)fCurrentSection->data + fCurrentSection->currentOffset;
583 	char* sectionEnd = position + fCurrentSection->stringsLength;
584 	uint32 index = 0;
585 	while (true) {
586 		if (position >= sectionEnd) {
587 			fErrorOutput->PrintError("Error: Malformed %s strings section\n",
588 				fCurrentSection->name);
589 			return B_BAD_DATA;
590 		}
591 
592 		size_t stringLength = strnlen(position, (char*)sectionEnd - position);
593 
594 		if (stringLength == 0) {
595 			if (position + 1 != sectionEnd) {
596 				fErrorOutput->PrintError(
597 					"Error: %ld excess bytes in %s strings section\n",
598 					sectionEnd - (position + 1), fCurrentSection->name);
599 				return B_BAD_DATA;
600 			}
601 
602 			if (index != fCurrentSection->stringsCount) {
603 				fErrorOutput->PrintError("Error: Invalid %s strings section: "
604 					"Less strings (%lld) than specified in the header (%lld)\n",
605 					fCurrentSection->name, index,
606 					fCurrentSection->stringsCount);
607 				return B_BAD_DATA;
608 			}
609 
610 			fCurrentSection->currentOffset += fCurrentSection->stringsLength;
611 
612 			return B_OK;
613 		}
614 
615 		if (index >= fCurrentSection->stringsCount) {
616 			fErrorOutput->PrintError("Error: Invalid %s strings section: "
617 				"More strings (%lld) than specified in the header (%lld)\n",
618 				fCurrentSection->name, index, fCurrentSection->stringsCount);
619 			return B_BAD_DATA;
620 		}
621 
622 		fCurrentSection->strings[index++] = position;
623 		position += stringLength + 1;
624 	}
625 }
626 
627 
628 status_t
629 ReaderImplBase::ParsePackageAttributesSection(
630 	AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler)
631 {
632 	// parse package attributes
633 	SetCurrentSection(&fPackageAttributesSection);
634 
635 	// init the attribute handler stack
636 	rootAttributeHandler->SetLevel(0);
637 	ClearAttributeHandlerStack();
638 	PushAttributeHandler(rootAttributeHandler);
639 
640 	status_t error = ParseAttributeTree(context);
641 	if (error == B_OK) {
642 		if (fPackageAttributesSection.currentOffset
643 				< fPackageAttributesSection.uncompressedLength) {
644 			fErrorOutput->PrintError("Error: %llu excess byte(s) in package "
645 				"attributes section\n",
646 				fPackageAttributesSection.uncompressedLength
647 					- fPackageAttributesSection.currentOffset);
648 			error = B_BAD_DATA;
649 		}
650 	}
651 
652 	SetCurrentSection(NULL);
653 
654 	// clean up on error
655 	if (error != B_OK) {
656 		context->ErrorOccurred();
657 		while (AttributeHandler* handler = PopAttributeHandler()) {
658 			if (handler != rootAttributeHandler)
659 				handler->Delete(context);
660 		}
661 		return error;
662 	}
663 
664 	return B_OK;
665 }
666 
667 
668 status_t
669 ReaderImplBase::ParseAttributeTree(AttributeHandlerContext* context)
670 {
671 	int level = 0;
672 
673 	while (true) {
674 		uint8 id;
675 		AttributeValue value;
676 		bool hasChildren;
677 		uint64 tag;
678 
679 		status_t error = _ReadAttribute(id, value, &hasChildren, &tag);
680 		if (error != B_OK)
681 			return error;
682 
683 		if (tag == 0) {
684 			AttributeHandler* handler = PopAttributeHandler();
685 			if (level-- == 0)
686 				return B_OK;
687 
688 			error = handler->Delete(context);
689 			if (error != B_OK)
690 				return error;
691 
692 			continue;
693 		}
694 
695 		AttributeHandler* childHandler = NULL;
696 		error = CurrentAttributeHandler()->HandleAttribute(context, id, value,
697 			hasChildren ? &childHandler : NULL);
698 		if (error != B_OK)
699 			return error;
700 
701 		// parse children
702 		if (hasChildren) {
703 			// create an ignore handler, if necessary
704 			if (childHandler == NULL) {
705 				childHandler = new(std::nothrow) IgnoreAttributeHandler;
706 				if (childHandler == NULL) {
707 					fErrorOutput->PrintError("Error: Out of memory!\n");
708 					return B_NO_MEMORY;
709 				}
710 			}
711 
712 			childHandler->SetLevel(++level);
713 			PushAttributeHandler(childHandler);
714 		}
715 	}
716 }
717 
718 
719 status_t
720 ReaderImplBase::_ReadAttribute(uint8& _id, AttributeValue& _value,
721 	bool* _hasChildren, uint64* _tag)
722 {
723 	uint64 tag;
724 	status_t error = ReadUnsignedLEB128(tag);
725 	if (error != B_OK)
726 		return error;
727 
728 	if (tag != 0) {
729 		// get the type
730 		uint16 type = HPKG_ATTRIBUTE_TAG_TYPE(tag);
731 		if (type >= B_HPKG_ATTRIBUTE_TYPE_ENUM_COUNT) {
732 			fErrorOutput->PrintError("Error: Invalid %s section: attribute "
733 				"type %d not supported!\n", fCurrentSection->name, type);
734 			return B_BAD_DATA;
735 		}
736 
737 		// get the value
738 		error = ReadAttributeValue(type, HPKG_ATTRIBUTE_TAG_ENCODING(tag),
739 			_value);
740 		if (error != B_OK)
741 			return error;
742 
743 		_id = HPKG_ATTRIBUTE_TAG_ID(tag);
744 		if (_id >= B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) {
745 			fErrorOutput->PrintError("Error: Invalid %s section: "
746 				"attribute id %d not supported!\n", fCurrentSection->name, _id);
747 			return B_BAD_DATA;
748 		}
749 	}
750 
751 	if (_hasChildren != NULL)
752 		*_hasChildren = HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag);
753 	if (_tag != NULL)
754 		*_tag = tag;
755 
756 	return B_OK;
757 }
758 
759 
760 status_t
761 ReaderImplBase::ReadAttributeValue(uint8 type, uint8 encoding,
762 	AttributeValue& _value)
763 {
764 	switch (type) {
765 		case B_HPKG_ATTRIBUTE_TYPE_INT:
766 		case B_HPKG_ATTRIBUTE_TYPE_UINT:
767 		{
768 			uint64 intValue;
769 			status_t error;
770 
771 			switch (encoding) {
772 				case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT:
773 				{
774 					uint8 value;
775 					error = _Read(value);
776 					intValue = value;
777 					break;
778 				}
779 				case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT:
780 				{
781 					uint16 value;
782 					error = _Read(value);
783 					intValue = B_BENDIAN_TO_HOST_INT16(value);
784 					break;
785 				}
786 				case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT:
787 				{
788 					uint32 value;
789 					error = _Read(value);
790 					intValue = B_BENDIAN_TO_HOST_INT32(value);
791 					break;
792 				}
793 				case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT:
794 				{
795 					uint64 value;
796 					error = _Read(value);
797 					intValue = B_BENDIAN_TO_HOST_INT64(value);
798 					break;
799 				}
800 				default:
801 				{
802 					fErrorOutput->PrintError("Error: Invalid %s section: "
803 						"invalid encoding %d for int value type %d\n",
804 						fCurrentSection->name, encoding, type);
805 					return B_BAD_VALUE;
806 				}
807 			}
808 
809 			if (error != B_OK)
810 				return error;
811 
812 			if (type == B_HPKG_ATTRIBUTE_TYPE_INT)
813 				_value.SetTo((int64)intValue);
814 			else
815 				_value.SetTo(intValue);
816 
817 			return B_OK;
818 		}
819 
820 		case B_HPKG_ATTRIBUTE_TYPE_STRING:
821 		{
822 			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) {
823 				uint64 index;
824 				status_t error = ReadUnsignedLEB128(index);
825 				if (error != B_OK)
826 					return error;
827 
828 				if (index > fCurrentSection->stringsCount) {
829 					fErrorOutput->PrintError("Error: Invalid %s section: "
830 						"string reference (%lld) out of bounds (%lld)\n",
831 						fCurrentSection->name, index,
832 						fCurrentSection->stringsCount);
833 					return B_BAD_DATA;
834 				}
835 
836 				_value.SetTo(fCurrentSection->strings[index]);
837 			} else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) {
838 				const char* string;
839 				status_t error = _ReadString(string);
840 				if (error != B_OK)
841 					return error;
842 
843 				_value.SetTo(string);
844 			} else {
845 				fErrorOutput->PrintError("Error: Invalid %s section: invalid "
846 					"string encoding (%u)\n", fCurrentSection->name, encoding);
847 				return B_BAD_DATA;
848 			}
849 
850 			return B_OK;
851 		}
852 
853 		default:
854 			fErrorOutput->PrintError("Error: Invalid %s section: invalid "
855 				"value type: %d\n", fCurrentSection->name, type);
856 			return B_BAD_DATA;
857 	}
858 }
859 
860 
861 status_t
862 ReaderImplBase::ReadUnsignedLEB128(uint64& _value)
863 {
864 	uint64 result = 0;
865 	int shift = 0;
866 	while (true) {
867 		uint8 byte;
868 		status_t error = _Read(byte);
869 		if (error != B_OK)
870 			return error;
871 
872 		result |= uint64(byte & 0x7f) << shift;
873 		if ((byte & 0x80) == 0)
874 			break;
875 		shift += 7;
876 	}
877 
878 	_value = result;
879 	return B_OK;
880 }
881 
882 
883 status_t
884 ReaderImplBase::_ReadString(const char*& _string, size_t* _stringLength)
885 {
886 	const char* string
887 		= (const char*)fCurrentSection->data + fCurrentSection->currentOffset;
888 	size_t stringLength = strnlen(string,
889 		fCurrentSection->uncompressedLength - fCurrentSection->currentOffset);
890 
891 	if (stringLength
892 		== fCurrentSection->uncompressedLength
893 			- fCurrentSection->currentOffset) {
894 		fErrorOutput->PrintError(
895 			"_ReadString(): string extends beyond %s end\n",
896 			fCurrentSection->name);
897 		return B_BAD_DATA;
898 	}
899 
900 	_string = string;
901 	if (_stringLength != NULL)
902 		*_stringLength = stringLength;
903 
904 	fCurrentSection->currentOffset += stringLength + 1;
905 	return B_OK;
906 }
907 
908 
909 status_t
910 ReaderImplBase::_ReadSectionBuffer(void* buffer, size_t size)
911 {
912 	if (size > fCurrentSection->uncompressedLength
913 			- fCurrentSection->currentOffset) {
914 		fErrorOutput->PrintError("_ReadBuffer(%lu): read beyond %s end\n",
915 			size, fCurrentSection->name);
916 		return B_BAD_DATA;
917 	}
918 
919 	memcpy(buffer, fCurrentSection->data + fCurrentSection->currentOffset,
920 		size);
921 	fCurrentSection->currentOffset += size;
922 	return B_OK;
923 }
924 
925 
926 status_t
927 ReaderImplBase::ReadBuffer(off_t offset, void* buffer, size_t size)
928 {
929 	ssize_t bytesRead = pread(fFD, buffer, size, offset);
930 	if (bytesRead < 0) {
931 		fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: "
932 			"%s\n", buffer, size, strerror(errno));
933 		return errno;
934 	}
935 	if ((size_t)bytesRead != size) {
936 		fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read all "
937 			"data\n", buffer, size);
938 		return B_ERROR;
939 	}
940 
941 	return B_OK;
942 }
943 
944 
945 status_t
946 ReaderImplBase::ReadCompressedBuffer(const SectionInfo& section)
947 {
948 	uint32 compressedSize = section.compressedLength;
949 	uint64 offset = section.offset;
950 
951 	switch (section.compression) {
952 		case B_HPKG_COMPRESSION_NONE:
953 			return ReadBuffer(offset, section.data, compressedSize);
954 
955 		case B_HPKG_COMPRESSION_ZLIB:
956 		{
957 			// init the decompressor
958 			BBufferDataOutput bufferOutput(section.data,
959 				section.uncompressedLength);
960 			ZlibDecompressor decompressor(&bufferOutput);
961 			status_t error = decompressor.Init();
962 			if (error != B_OK)
963 				return error;
964 
965 			while (compressedSize > 0) {
966 				// read compressed buffer
967 				size_t toRead = std::min((size_t)compressedSize,
968 					fScratchBufferSize);
969 				error = ReadBuffer(offset, fScratchBuffer, toRead);
970 				if (error != B_OK)
971 					return error;
972 
973 				// uncompress
974 				error = decompressor.DecompressNext(fScratchBuffer, toRead);
975 				if (error != B_OK)
976 					return error;
977 
978 				compressedSize -= toRead;
979 				offset += toRead;
980 			}
981 
982 			error = decompressor.Finish();
983 			if (error != B_OK)
984 				return error;
985 
986 			// verify that all data have been read
987 			if (bufferOutput.BytesWritten() != section.uncompressedLength) {
988 				fErrorOutput->PrintError("Error: Missing bytes in uncompressed "
989 					"buffer!\n");
990 				return B_BAD_DATA;
991 			}
992 
993 			return B_OK;
994 		}
995 
996 		default:
997 			return B_BAD_DATA;
998 	}
999 }
1000 
1001 
1002 }	// namespace BPrivate
1003 
1004 }	// namespace BHPKG
1005 
1006 }	// namespace BPackageKit
1007