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