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