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