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