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