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