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