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