xref: /haiku/src/kits/package/hpkg/ReaderImplBase.cpp (revision 697b9545b17b6a29237523f6e5aac14a1cab5684)
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 	fParentToken(NULL),
467 	fToken(NULL),
468 	fID(B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
469 {
470 }
471 
472 
473 ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler(uint8 id,
474 	const BPackageAttributeValue& value, void* parentToken, void* token)
475 	:
476 	fParentToken(NULL),
477 	fToken(token),
478 	fID(id),
479 	fValue(value)
480 {
481 }
482 
483 
484 status_t
485 ReaderImplBase::LowLevelAttributeHandler::HandleAttribute(
486 	AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
487 	AttributeHandler** _handler)
488 {
489 	// notify the content handler
490 	void* token;
491 	status_t error = context->lowLevelHandler->HandleAttribute(
492 		(BHPKGAttributeID)id, value, fToken, token);
493 	if (error != B_OK)
494 		return error;
495 
496 	// create a subhandler for the attribute, if it has children
497 	if (_handler != NULL) {
498 		*_handler = new(std::nothrow) LowLevelAttributeHandler(id, value,
499 			fToken, token);
500 		if (*_handler == NULL) {
501 			context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id,
502 				value, fToken, token);
503 			return B_NO_MEMORY;
504 		}
505 		return B_OK;
506 	}
507 
508 	// no children -- just call the done hook
509 	return context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id,
510 		value, fToken, token);
511 }
512 
513 
514 status_t
515 ReaderImplBase::LowLevelAttributeHandler::Delete(
516 	AttributeHandlerContext* context)
517 {
518 	status_t error = B_OK;
519 	if (fID != B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) {
520 		error = context->lowLevelHandler->HandleAttributeDone(
521 			(BHPKGAttributeID)fID, fValue, fParentToken, fToken);
522 	}
523 
524 	delete this;
525 	return error;
526 }
527 
528 
529 // #pragma mark - ReaderImplBase
530 
531 
532 ReaderImplBase::ReaderImplBase(BErrorOutput* errorOutput)
533 	:
534 	fPackageAttributesSection("package attributes"),
535 	fErrorOutput(errorOutput),
536 	fFD(-1),
537 	fOwnsFD(false),
538 	fCurrentSection(NULL),
539 	fScratchBuffer(NULL),
540 	fScratchBufferSize(0)
541 {
542 }
543 
544 
545 ReaderImplBase::~ReaderImplBase()
546 {
547 	if (fOwnsFD && fFD >= 0)
548 		close(fFD);
549 
550 	delete[] fScratchBuffer;
551 }
552 
553 
554 status_t
555 ReaderImplBase::Init(int fd, bool keepFD)
556 {
557 	fFD = fd;
558 	fOwnsFD = keepFD;
559 
560 	// allocate a scratch buffer
561 	fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize];
562 	if (fScratchBuffer == NULL) {
563 		fErrorOutput->PrintError("Error: Out of memory!\n");
564 		return B_NO_MEMORY;
565 	}
566 	fScratchBufferSize = kScratchBufferSize;
567 
568 	return B_OK;
569 }
570 
571 
572 const char*
573 ReaderImplBase::CheckCompression(const SectionInfo& section) const
574 {
575 	switch (section.compression) {
576 		case B_HPKG_COMPRESSION_NONE:
577 			if (section.compressedLength != section.uncompressedLength) {
578 				return "Uncompressed, but compressed and uncompressed length "
579 					"don't match";
580 			}
581 			return NULL;
582 
583 		case B_HPKG_COMPRESSION_ZLIB:
584 			if (section.compressedLength >= section.uncompressedLength) {
585 				return "Compressed, but compressed length is not less than "
586 					"uncompressed length";
587 			}
588 			return NULL;
589 
590 		default:
591 			return "Invalid compression algorithm ID";
592 	}
593 }
594 
595 
596 status_t
597 ReaderImplBase::ParseStrings()
598 {
599 	// allocate table, if there are any strings
600 	if (fCurrentSection->stringsCount == 0) {
601 		fCurrentSection->currentOffset += fCurrentSection->stringsLength;
602 		return B_OK;
603 	}
604 
605 	fCurrentSection->strings
606 		= new(std::nothrow) char*[fCurrentSection->stringsCount];
607 	if (fCurrentSection->strings == NULL) {
608 		fErrorOutput->PrintError("Error: Out of memory!\n");
609 		return B_NO_MEMORY;
610 	}
611 
612 	// parse the section and fill the table
613 	char* position
614 		= (char*)fCurrentSection->data + fCurrentSection->currentOffset;
615 	char* sectionEnd = position + fCurrentSection->stringsLength;
616 	uint32 index = 0;
617 	while (true) {
618 		if (position >= sectionEnd) {
619 			fErrorOutput->PrintError("Error: Malformed %s strings section\n",
620 				fCurrentSection->name);
621 			return B_BAD_DATA;
622 		}
623 
624 		size_t stringLength = strnlen(position, (char*)sectionEnd - position);
625 
626 		if (stringLength == 0) {
627 			if (position + 1 != sectionEnd) {
628 				fErrorOutput->PrintError(
629 					"Error: %ld excess bytes in %s strings section\n",
630 					sectionEnd - (position + 1), fCurrentSection->name);
631 				return B_BAD_DATA;
632 			}
633 
634 			if (index != fCurrentSection->stringsCount) {
635 				fErrorOutput->PrintError("Error: Invalid %s strings section: "
636 					"Less strings (%lld) than specified in the header (%lld)\n",
637 					fCurrentSection->name, index,
638 					fCurrentSection->stringsCount);
639 				return B_BAD_DATA;
640 			}
641 
642 			fCurrentSection->currentOffset += fCurrentSection->stringsLength;
643 
644 			return B_OK;
645 		}
646 
647 		if (index >= fCurrentSection->stringsCount) {
648 			fErrorOutput->PrintError("Error: Invalid %s strings section: "
649 				"More strings (%lld) than specified in the header (%lld)\n",
650 				fCurrentSection->name, index, fCurrentSection->stringsCount);
651 			return B_BAD_DATA;
652 		}
653 
654 		fCurrentSection->strings[index++] = position;
655 		position += stringLength + 1;
656 	}
657 }
658 
659 
660 status_t
661 ReaderImplBase::ParsePackageAttributesSection(
662 	AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler)
663 {
664 	// parse package attributes
665 	SetCurrentSection(&fPackageAttributesSection);
666 
667 	// init the attribute handler stack
668 	rootAttributeHandler->SetLevel(0);
669 	ClearAttributeHandlerStack();
670 	PushAttributeHandler(rootAttributeHandler);
671 
672 	status_t error = ParseAttributeTree(context);
673 	if (error == B_OK) {
674 		if (fPackageAttributesSection.currentOffset
675 				< fPackageAttributesSection.uncompressedLength) {
676 			fErrorOutput->PrintError("Error: %llu excess byte(s) in package "
677 				"attributes section\n",
678 				fPackageAttributesSection.uncompressedLength
679 					- fPackageAttributesSection.currentOffset);
680 			error = B_BAD_DATA;
681 		}
682 	}
683 
684 	SetCurrentSection(NULL);
685 
686 	// clean up on error
687 	if (error != B_OK) {
688 		context->ErrorOccurred();
689 		while (AttributeHandler* handler = PopAttributeHandler()) {
690 			if (handler != rootAttributeHandler)
691 				handler->Delete(context);
692 		}
693 		return error;
694 	}
695 
696 	return B_OK;
697 }
698 
699 
700 status_t
701 ReaderImplBase::ParseAttributeTree(AttributeHandlerContext* context)
702 {
703 	int level = 0;
704 
705 	while (true) {
706 		uint8 id;
707 		AttributeValue value;
708 		bool hasChildren;
709 		uint64 tag;
710 
711 		status_t error = _ReadAttribute(id, value, &hasChildren, &tag);
712 		if (error != B_OK)
713 			return error;
714 
715 		if (tag == 0) {
716 			AttributeHandler* handler = PopAttributeHandler();
717 			if (level-- == 0)
718 				return B_OK;
719 
720 			error = handler->Delete(context);
721 			if (error != B_OK)
722 				return error;
723 
724 			continue;
725 		}
726 
727 		AttributeHandler* childHandler = NULL;
728 		error = CurrentAttributeHandler()->HandleAttribute(context, id, value,
729 			hasChildren ? &childHandler : NULL);
730 		if (error != B_OK)
731 			return error;
732 
733 		// parse children
734 		if (hasChildren) {
735 			// create an ignore handler, if necessary
736 			if (childHandler == NULL) {
737 				childHandler = new(std::nothrow) IgnoreAttributeHandler;
738 				if (childHandler == NULL) {
739 					fErrorOutput->PrintError("Error: Out of memory!\n");
740 					return B_NO_MEMORY;
741 				}
742 			}
743 
744 			childHandler->SetLevel(++level);
745 			PushAttributeHandler(childHandler);
746 		}
747 	}
748 }
749 
750 
751 status_t
752 ReaderImplBase::_ReadAttribute(uint8& _id, AttributeValue& _value,
753 	bool* _hasChildren, uint64* _tag)
754 {
755 	uint64 tag;
756 	status_t error = ReadUnsignedLEB128(tag);
757 	if (error != B_OK)
758 		return error;
759 
760 	if (tag != 0) {
761 		// get the type
762 		uint16 type = HPKG_ATTRIBUTE_TAG_TYPE(tag);
763 		if (type >= B_HPKG_ATTRIBUTE_TYPE_ENUM_COUNT) {
764 			fErrorOutput->PrintError("Error: Invalid %s section: attribute "
765 				"type %d not supported!\n", fCurrentSection->name, type);
766 			return B_BAD_DATA;
767 		}
768 
769 		// get the value
770 		error = ReadAttributeValue(type, HPKG_ATTRIBUTE_TAG_ENCODING(tag),
771 			_value);
772 		if (error != B_OK)
773 			return error;
774 
775 		_id = HPKG_ATTRIBUTE_TAG_ID(tag);
776 		if (_id >= B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) {
777 			fErrorOutput->PrintError("Error: Invalid %s section: "
778 				"attribute id %d not supported!\n", fCurrentSection->name, _id);
779 			return B_BAD_DATA;
780 		}
781 	}
782 
783 	if (_hasChildren != NULL)
784 		*_hasChildren = HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag);
785 	if (_tag != NULL)
786 		*_tag = tag;
787 
788 	return B_OK;
789 }
790 
791 
792 status_t
793 ReaderImplBase::ReadAttributeValue(uint8 type, uint8 encoding,
794 	AttributeValue& _value)
795 {
796 	switch (type) {
797 		case B_HPKG_ATTRIBUTE_TYPE_INT:
798 		case B_HPKG_ATTRIBUTE_TYPE_UINT:
799 		{
800 			uint64 intValue;
801 			status_t error;
802 
803 			switch (encoding) {
804 				case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT:
805 				{
806 					uint8 value;
807 					error = _Read(value);
808 					intValue = value;
809 					break;
810 				}
811 				case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT:
812 				{
813 					uint16 value;
814 					error = _Read(value);
815 					intValue = B_BENDIAN_TO_HOST_INT16(value);
816 					break;
817 				}
818 				case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT:
819 				{
820 					uint32 value;
821 					error = _Read(value);
822 					intValue = B_BENDIAN_TO_HOST_INT32(value);
823 					break;
824 				}
825 				case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT:
826 				{
827 					uint64 value;
828 					error = _Read(value);
829 					intValue = B_BENDIAN_TO_HOST_INT64(value);
830 					break;
831 				}
832 				default:
833 				{
834 					fErrorOutput->PrintError("Error: Invalid %s section: "
835 						"invalid encoding %d for int value type %d\n",
836 						fCurrentSection->name, encoding, type);
837 					return B_BAD_VALUE;
838 				}
839 			}
840 
841 			if (error != B_OK)
842 				return error;
843 
844 			if (type == B_HPKG_ATTRIBUTE_TYPE_INT)
845 				_value.SetTo((int64)intValue);
846 			else
847 				_value.SetTo(intValue);
848 
849 			return B_OK;
850 		}
851 
852 		case B_HPKG_ATTRIBUTE_TYPE_STRING:
853 		{
854 			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) {
855 				uint64 index;
856 				status_t error = ReadUnsignedLEB128(index);
857 				if (error != B_OK)
858 					return error;
859 
860 				if (index > fCurrentSection->stringsCount) {
861 					fErrorOutput->PrintError("Error: Invalid %s section: "
862 						"string reference (%lld) out of bounds (%lld)\n",
863 						fCurrentSection->name, index,
864 						fCurrentSection->stringsCount);
865 					return B_BAD_DATA;
866 				}
867 
868 				_value.SetTo(fCurrentSection->strings[index]);
869 			} else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) {
870 				const char* string;
871 				status_t error = _ReadString(string);
872 				if (error != B_OK)
873 					return error;
874 
875 				_value.SetTo(string);
876 			} else {
877 				fErrorOutput->PrintError("Error: Invalid %s section: invalid "
878 					"string encoding (%u)\n", fCurrentSection->name, encoding);
879 				return B_BAD_DATA;
880 			}
881 
882 			return B_OK;
883 		}
884 
885 		default:
886 			fErrorOutput->PrintError("Error: Invalid %s section: invalid "
887 				"value type: %d\n", fCurrentSection->name, type);
888 			return B_BAD_DATA;
889 	}
890 }
891 
892 
893 status_t
894 ReaderImplBase::ReadUnsignedLEB128(uint64& _value)
895 {
896 	uint64 result = 0;
897 	int shift = 0;
898 	while (true) {
899 		uint8 byte;
900 		status_t error = _Read(byte);
901 		if (error != B_OK)
902 			return error;
903 
904 		result |= uint64(byte & 0x7f) << shift;
905 		if ((byte & 0x80) == 0)
906 			break;
907 		shift += 7;
908 	}
909 
910 	_value = result;
911 	return B_OK;
912 }
913 
914 
915 status_t
916 ReaderImplBase::_ReadString(const char*& _string, size_t* _stringLength)
917 {
918 	const char* string
919 		= (const char*)fCurrentSection->data + fCurrentSection->currentOffset;
920 	size_t stringLength = strnlen(string,
921 		fCurrentSection->uncompressedLength - fCurrentSection->currentOffset);
922 
923 	if (stringLength
924 		== fCurrentSection->uncompressedLength
925 			- fCurrentSection->currentOffset) {
926 		fErrorOutput->PrintError(
927 			"_ReadString(): string extends beyond %s end\n",
928 			fCurrentSection->name);
929 		return B_BAD_DATA;
930 	}
931 
932 	_string = string;
933 	if (_stringLength != NULL)
934 		*_stringLength = stringLength;
935 
936 	fCurrentSection->currentOffset += stringLength + 1;
937 	return B_OK;
938 }
939 
940 
941 status_t
942 ReaderImplBase::_ReadSectionBuffer(void* buffer, size_t size)
943 {
944 	if (size > fCurrentSection->uncompressedLength
945 			- fCurrentSection->currentOffset) {
946 		fErrorOutput->PrintError("_ReadBuffer(%lu): read beyond %s end\n",
947 			size, fCurrentSection->name);
948 		return B_BAD_DATA;
949 	}
950 
951 	memcpy(buffer, fCurrentSection->data + fCurrentSection->currentOffset,
952 		size);
953 	fCurrentSection->currentOffset += size;
954 	return B_OK;
955 }
956 
957 
958 status_t
959 ReaderImplBase::ReadBuffer(off_t offset, void* buffer, size_t size)
960 {
961 	ssize_t bytesRead = pread(fFD, buffer, size, offset);
962 	if (bytesRead < 0) {
963 		fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: "
964 			"%s\n", buffer, size, strerror(errno));
965 		return errno;
966 	}
967 	if ((size_t)bytesRead != size) {
968 		fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read all "
969 			"data\n", buffer, size);
970 		return B_ERROR;
971 	}
972 
973 	return B_OK;
974 }
975 
976 
977 status_t
978 ReaderImplBase::ReadCompressedBuffer(const SectionInfo& section)
979 {
980 	uint32 compressedSize = section.compressedLength;
981 	uint64 offset = section.offset;
982 
983 	switch (section.compression) {
984 		case B_HPKG_COMPRESSION_NONE:
985 			return ReadBuffer(offset, section.data, compressedSize);
986 
987 		case B_HPKG_COMPRESSION_ZLIB:
988 		{
989 			// init the decompressor
990 			BBufferDataOutput bufferOutput(section.data,
991 				section.uncompressedLength);
992 			ZlibDecompressor decompressor(&bufferOutput);
993 			status_t error = decompressor.Init();
994 			if (error != B_OK)
995 				return error;
996 
997 			while (compressedSize > 0) {
998 				// read compressed buffer
999 				size_t toRead = std::min((size_t)compressedSize,
1000 					fScratchBufferSize);
1001 				error = ReadBuffer(offset, fScratchBuffer, toRead);
1002 				if (error != B_OK)
1003 					return error;
1004 
1005 				// uncompress
1006 				error = decompressor.DecompressNext(fScratchBuffer, toRead);
1007 				if (error != B_OK)
1008 					return error;
1009 
1010 				compressedSize -= toRead;
1011 				offset += toRead;
1012 			}
1013 
1014 			error = decompressor.Finish();
1015 			if (error != B_OK)
1016 				return error;
1017 
1018 			// verify that all data have been read
1019 			if (bufferOutput.BytesWritten() != section.uncompressedLength) {
1020 				fErrorOutput->PrintError("Error: Missing bytes in uncompressed "
1021 					"buffer!\n");
1022 				return B_BAD_DATA;
1023 			}
1024 
1025 			return B_OK;
1026 		}
1027 
1028 		default:
1029 			return B_BAD_DATA;
1030 	}
1031 }
1032 
1033 
1034 }	// namespace BPrivate
1035 
1036 }	// namespace BHPKG
1037 
1038 }	// namespace BPackageKit
1039