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