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