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