1/*
2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <package/PackageInfo.h>
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <new>
15
16#include <File.h>
17#include <Entry.h>
18#include <Message.h>
19#include <package/hpkg/NoErrorOutput.h>
20#include <package/hpkg/PackageReader.h>
21#include <package/hpkg/v1/PackageInfoContentHandler.h>
22#include <package/hpkg/v1/PackageReader.h>
23#include <package/PackageInfoContentHandler.h>
24
25#include "PackageInfoParser.h"
26#include "PackageInfoStringBuilder.h"
27
28
29namespace BPackageKit {
30
31
32const char* const BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
33	"name",
34	"summary",
35	"description",
36	"vendor",
37	"packager",
38	"architecture",
39	"version",
40	"copyrights",
41	"licenses",
42	"provides",
43	"requires",
44	"supplements",
45	"conflicts",
46	"freshens",
47	"replaces",
48	"flags",
49	"urls",
50	"source-urls",
51	"checksum",		// not being parsed, computed externally
52	NULL,			// install-path -- not settable via .PackageInfo
53	"base-package",
54	"global-writable-files",
55	"user-settings-files",
56	"users",
57	"groups",
58	"post-install-scripts",
59	"pre-uninstall-scripts"
60};
61
62
63const char* const
64BPackageInfo::kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
65	"any",
66	"x86",
67	"x86_gcc2",
68	"source",
69	"x86_64",
70	"ppc",
71	"arm",
72	"m68k",
73	"sparc",
74	"arm64",
75	"riscv64"
76};
77
78
79const char* const BPackageInfo::kWritableFileUpdateTypes[
80		B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT] = {
81	"keep-old",
82	"manual",
83	"auto-merge",
84};
85
86
87// #pragma mark - FieldName
88
89
90struct BPackageInfo::FieldName {
91	FieldName(const char* prefix, const char* suffix)
92	{
93		size_t prefixLength = strlen(prefix);
94		size_t suffixLength = strlen(suffix);
95		if (prefixLength + suffixLength >= sizeof(fFieldName)) {
96			fFieldName[0] = '\0';
97			return;
98		}
99
100		memcpy(fFieldName, prefix, prefixLength);
101		memcpy(fFieldName + prefixLength, suffix, suffixLength);
102		fFieldName[prefixLength + suffixLength] = '\0';
103	}
104
105	bool ReplaceSuffix(size_t prefixLength, const char* suffix)
106	{
107		size_t suffixLength = strlen(suffix);
108		if (prefixLength + suffixLength >= sizeof(fFieldName)) {
109			fFieldName[0] = '\0';
110			return false;
111		}
112
113		memcpy(fFieldName + prefixLength, suffix, suffixLength);
114		fFieldName[prefixLength + suffixLength] = '\0';
115		return true;
116	}
117
118	bool IsValid() const
119	{
120		return fFieldName[0] != '\0';
121	}
122
123	operator const char*()
124	{
125		return fFieldName;
126	}
127
128private:
129	char	fFieldName[64];
130};
131
132
133// #pragma mark - PackageFileLocation
134
135
136struct BPackageInfo::PackageFileLocation {
137	PackageFileLocation(const char* path)
138		:
139		fPath(path),
140		fFD(-1)
141	{
142	}
143
144	PackageFileLocation(int fd)
145		:
146		fPath(NULL),
147		fFD(fd)
148	{
149	}
150
151	const char* Path() const
152	{
153		return fPath;
154	}
155
156	int FD() const
157	{
158		return fFD;
159	}
160
161private:
162	const char*	fPath;
163	int			fFD;
164};
165
166
167// #pragma mark - BPackageInfo
168
169
170BPackageInfo::BPackageInfo()
171	:
172	BArchivable(),
173	fFlags(0),
174	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
175	fCopyrightList(4),
176	fLicenseList(4),
177	fURLList(4),
178	fSourceURLList(4),
179	fGlobalWritableFileInfos(4, true),
180	fUserSettingsFileInfos(4, true),
181	fUsers(4, true),
182	fGroups(4),
183	fPostInstallScripts(4),
184	fPreUninstallScripts(4),
185	fProvidesList(20, true),
186	fRequiresList(20, true),
187	fSupplementsList(20, true),
188	fConflictsList(4, true),
189	fFreshensList(4, true),
190	fReplacesList(4)
191{
192}
193
194
195BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
196	:
197	BArchivable(archive),
198	fFlags(0),
199	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
200	fCopyrightList(4),
201	fLicenseList(4),
202	fURLList(4),
203	fSourceURLList(4),
204	fGlobalWritableFileInfos(4, true),
205	fUserSettingsFileInfos(4, true),
206	fUsers(4, true),
207	fGroups(4),
208	fPostInstallScripts(4),
209	fPreUninstallScripts(4),
210	fProvidesList(20, true),
211	fRequiresList(20, true),
212	fSupplementsList(20, true),
213	fConflictsList(4, true),
214	fFreshensList(4, true),
215	fReplacesList(4)
216{
217	status_t error;
218	int32 architecture;
219	if ((error = archive->FindString("name", &fName)) == B_OK
220		&& (error = archive->FindString("summary", &fSummary)) == B_OK
221		&& (error = archive->FindString("description", &fDescription)) == B_OK
222		&& (error = archive->FindString("vendor", &fVendor)) == B_OK
223		&& (error = archive->FindString("packager", &fPackager)) == B_OK
224		&& (error = archive->FindString("basePackage", &fBasePackage)) == B_OK
225		&& (error = archive->FindUInt32("flags", &fFlags)) == B_OK
226		&& (error = archive->FindInt32("architecture", &architecture)) == B_OK
227		&& (error = _ExtractVersion(archive, "version", 0, fVersion)) == B_OK
228		&& (error = _ExtractStringList(archive, "copyrights", fCopyrightList))
229			== B_OK
230		&& (error = _ExtractStringList(archive, "licenses", fLicenseList))
231			== B_OK
232		&& (error = _ExtractStringList(archive, "urls", fURLList)) == B_OK
233		&& (error = _ExtractStringList(archive, "source-urls", fSourceURLList))
234			== B_OK
235		&& (error = _ExtractGlobalWritableFileInfos(archive,
236			"global-writable-files", fGlobalWritableFileInfos)) == B_OK
237		&& (error = _ExtractUserSettingsFileInfos(archive, "user-settings-files",
238			fUserSettingsFileInfos)) == B_OK
239		&& (error = _ExtractUsers(archive, "users", fUsers)) == B_OK
240		&& (error = _ExtractStringList(archive, "groups", fGroups)) == B_OK
241		&& (error = _ExtractStringList(archive, "post-install-scripts",
242			fPostInstallScripts)) == B_OK
243		&& (error = _ExtractStringList(archive, "pre-uninstall-scripts",
244			fPreUninstallScripts)) == B_OK
245		&& (error = _ExtractResolvables(archive, "provides", fProvidesList))
246			== B_OK
247		&& (error = _ExtractResolvableExpressions(archive, "requires",
248			fRequiresList)) == B_OK
249		&& (error = _ExtractResolvableExpressions(archive, "supplements",
250			fSupplementsList)) == B_OK
251		&& (error = _ExtractResolvableExpressions(archive, "conflicts",
252			fConflictsList)) == B_OK
253		&& (error = _ExtractResolvableExpressions(archive, "freshens",
254			fFreshensList)) == B_OK
255		&& (error = _ExtractStringList(archive, "replaces", fReplacesList))
256			== B_OK
257		&& (error = archive->FindString("checksum", &fChecksum)) == B_OK
258		&& (error = archive->FindString("install-path", &fInstallPath)) == B_OK
259		&& (error = archive->FindString("file-name", &fFileName)) == B_OK) {
260		if (architecture >= 0
261			&& architecture <= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
262			fArchitecture = (BPackageArchitecture)architecture;
263		} else
264			error = B_BAD_DATA;
265	}
266
267	if (_error != NULL)
268		*_error = error;
269}
270
271
272BPackageInfo::~BPackageInfo()
273{
274}
275
276
277status_t
278BPackageInfo::ReadFromConfigFile(const BEntry& packageInfoEntry,
279	ParseErrorListener* listener)
280{
281	status_t result = packageInfoEntry.InitCheck();
282	if (result != B_OK)
283		return result;
284
285	BFile file(&packageInfoEntry, B_READ_ONLY);
286	if ((result = file.InitCheck()) != B_OK)
287		return result;
288
289	return ReadFromConfigFile(file, listener);
290}
291
292
293status_t
294BPackageInfo::ReadFromConfigFile(BFile& packageInfoFile,
295	ParseErrorListener* listener)
296{
297	off_t size;
298	status_t result = packageInfoFile.GetSize(&size);
299	if (result != B_OK)
300		return result;
301
302	BString packageInfoString;
303	char* buffer = packageInfoString.LockBuffer(size);
304	if (buffer == NULL)
305		return B_NO_MEMORY;
306
307	if ((result = packageInfoFile.Read(buffer, size)) < size) {
308		packageInfoString.UnlockBuffer(0);
309		return result >= 0 ? B_IO_ERROR : result;
310	}
311
312	buffer[size] = '\0';
313	packageInfoString.UnlockBuffer(size);
314
315	return ReadFromConfigString(packageInfoString, listener);
316}
317
318
319status_t
320BPackageInfo::ReadFromConfigString(const BString& packageInfoString,
321	ParseErrorListener* listener)
322{
323	Clear();
324
325	Parser parser(listener);
326	return parser.Parse(packageInfoString, this);
327}
328
329
330status_t
331BPackageInfo::ReadFromPackageFile(const char* path)
332{
333	return _ReadFromPackageFile(PackageFileLocation(path));
334}
335
336
337status_t
338BPackageInfo::ReadFromPackageFile(int fd)
339{
340	return _ReadFromPackageFile(PackageFileLocation(fd));
341}
342
343
344status_t
345BPackageInfo::InitCheck() const
346{
347	if (fName.Length() == 0 || fSummary.Length() == 0
348		|| fDescription.Length() == 0 || fVendor.Length() == 0
349		|| fPackager.Length() == 0
350		|| fArchitecture == B_PACKAGE_ARCHITECTURE_ENUM_COUNT
351		|| fVersion.InitCheck() != B_OK
352		|| fCopyrightList.IsEmpty() || fLicenseList.IsEmpty()
353		|| fProvidesList.IsEmpty())
354		return B_NO_INIT;
355
356	// check global writable files
357	int32 globalWritableFileCount = fGlobalWritableFileInfos.CountItems();
358	for (int32 i = 0; i < globalWritableFileCount; i++) {
359		const BGlobalWritableFileInfo* info
360			= fGlobalWritableFileInfos.ItemAt(i);
361		status_t error = info->InitCheck();
362		if (error != B_OK)
363			return error;
364	}
365
366	// check user settings files
367	int32 userSettingsFileCount = fUserSettingsFileInfos.CountItems();
368	for (int32 i = 0; i < userSettingsFileCount; i++) {
369		const BUserSettingsFileInfo* info = fUserSettingsFileInfos.ItemAt(i);
370		status_t error = info->InitCheck();
371		if (error != B_OK)
372			return error;
373	}
374
375	// check users
376	int32 userCount = fUsers.CountItems();
377	for (int32 i = 0; i < userCount; i++) {
378		const BUser* user = fUsers.ItemAt(i);
379		status_t error = user->InitCheck();
380		if (error != B_OK)
381			return B_NO_INIT;
382
383		// make sure the user's groups are specified as groups
384		const BStringList& userGroups = user->Groups();
385		int32 groupCount = userGroups.CountStrings();
386		for (int32 k = 0; k < groupCount; k++) {
387			const BString& group = userGroups.StringAt(k);
388			if (!fGroups.HasString(group))
389				return B_BAD_VALUE;
390		}
391	}
392
393	// check groups
394	int32 groupCount = fGroups.CountStrings();
395	for (int32 i = 0; i< groupCount; i++) {
396		if (!BUser::IsValidUserName(fGroups.StringAt(i)))
397			return B_BAD_VALUE;
398	}
399
400	return B_OK;
401}
402
403
404const BString&
405BPackageInfo::Name() const
406{
407	return fName;
408}
409
410
411const BString&
412BPackageInfo::Summary() const
413{
414	return fSummary;
415}
416
417
418const BString&
419BPackageInfo::Description() const
420{
421	return fDescription;
422}
423
424
425const BString&
426BPackageInfo::Vendor() const
427{
428	return fVendor;
429}
430
431
432const BString&
433BPackageInfo::Packager() const
434{
435	return fPackager;
436}
437
438
439const BString&
440BPackageInfo::BasePackage() const
441{
442	return fBasePackage;
443}
444
445
446const BString&
447BPackageInfo::Checksum() const
448{
449	return fChecksum;
450}
451
452
453const BString&
454BPackageInfo::InstallPath() const
455{
456	return fInstallPath;
457}
458
459
460BString
461BPackageInfo::FileName() const
462{
463	return fFileName.IsEmpty() ? CanonicalFileName() : fFileName;
464}
465
466
467uint32
468BPackageInfo::Flags() const
469{
470	return fFlags;
471}
472
473
474BPackageArchitecture
475BPackageInfo::Architecture() const
476{
477	return fArchitecture;
478}
479
480
481const char*
482BPackageInfo::ArchitectureName() const
483{
484	if ((int)fArchitecture < 0
485		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
486		return NULL;
487	}
488	return kArchitectureNames[fArchitecture];
489}
490
491
492const BPackageVersion&
493BPackageInfo::Version() const
494{
495	return fVersion;
496}
497
498
499const BStringList&
500BPackageInfo::CopyrightList() const
501{
502	return fCopyrightList;
503}
504
505
506const BStringList&
507BPackageInfo::LicenseList() const
508{
509	return fLicenseList;
510}
511
512
513const BStringList&
514BPackageInfo::URLList() const
515{
516	return fURLList;
517}
518
519
520const BStringList&
521BPackageInfo::SourceURLList() const
522{
523	return fSourceURLList;
524}
525
526
527const BObjectList<BGlobalWritableFileInfo>&
528BPackageInfo::GlobalWritableFileInfos() const
529{
530	return fGlobalWritableFileInfos;
531}
532
533
534const BObjectList<BUserSettingsFileInfo>&
535BPackageInfo::UserSettingsFileInfos() const
536{
537	return fUserSettingsFileInfos;
538}
539
540
541const BObjectList<BUser>&
542BPackageInfo::Users() const
543{
544	return fUsers;
545}
546
547
548const BStringList&
549BPackageInfo::Groups() const
550{
551	return fGroups;
552}
553
554
555const BStringList&
556BPackageInfo::PostInstallScripts() const
557{
558	return fPostInstallScripts;
559}
560
561
562const BStringList&
563BPackageInfo::PreUninstallScripts() const
564{
565	return fPreUninstallScripts;
566}
567
568
569const BObjectList<BPackageResolvable>&
570BPackageInfo::ProvidesList() const
571{
572	return fProvidesList;
573}
574
575
576const BObjectList<BPackageResolvableExpression>&
577BPackageInfo::RequiresList() const
578{
579	return fRequiresList;
580}
581
582
583const BObjectList<BPackageResolvableExpression>&
584BPackageInfo::SupplementsList() const
585{
586	return fSupplementsList;
587}
588
589
590const BObjectList<BPackageResolvableExpression>&
591BPackageInfo::ConflictsList() const
592{
593	return fConflictsList;
594}
595
596
597const BObjectList<BPackageResolvableExpression>&
598BPackageInfo::FreshensList() const
599{
600	return fFreshensList;
601}
602
603
604const BStringList&
605BPackageInfo::ReplacesList() const
606{
607	return fReplacesList;
608}
609
610
611BString
612BPackageInfo::CanonicalFileName() const
613{
614	if (InitCheck() != B_OK)
615		return BString();
616
617	return BString().SetToFormat("%s-%s-%s.hpkg", fName.String(),
618		fVersion.ToString().String(), kArchitectureNames[fArchitecture]);
619}
620
621
622bool
623BPackageInfo::Matches(const BPackageResolvableExpression& expression) const
624{
625	// check for an explicit match on the package
626	if (expression.Name().StartsWith("pkg:")) {
627		return fName == expression.Name().String() + 4
628			&& expression.Matches(fVersion, fVersion);
629	}
630
631	// search for a matching provides
632	int32 count = fProvidesList.CountItems();
633	for (int32 i = 0; i < count; i++) {
634		const BPackageResolvable* provides = fProvidesList.ItemAt(i);
635		if (expression.Matches(*provides))
636			return true;
637	}
638
639	return false;
640}
641
642
643void
644BPackageInfo::SetName(const BString& name)
645{
646	fName = name;
647	fName.ToLower();
648}
649
650
651void
652BPackageInfo::SetSummary(const BString& summary)
653{
654	fSummary = summary;
655}
656
657
658void
659BPackageInfo::SetDescription(const BString& description)
660{
661	fDescription = description;
662}
663
664
665void
666BPackageInfo::SetVendor(const BString& vendor)
667{
668	fVendor = vendor;
669}
670
671
672void
673BPackageInfo::SetPackager(const BString& packager)
674{
675	fPackager = packager;
676}
677
678
679void
680BPackageInfo::SetBasePackage(const BString& basePackage)
681{
682	fBasePackage = basePackage;
683}
684
685
686void
687BPackageInfo::SetChecksum(const BString& checksum)
688{
689	fChecksum = checksum;
690}
691
692
693void
694BPackageInfo::SetInstallPath(const BString& installPath)
695{
696	fInstallPath = installPath;
697}
698
699
700void
701BPackageInfo::SetFileName(const BString& fileName)
702{
703	fFileName = fileName;
704}
705
706
707void
708BPackageInfo::SetVersion(const BPackageVersion& version)
709{
710	fVersion = version;
711}
712
713
714void
715BPackageInfo::SetFlags(uint32 flags)
716{
717	fFlags = flags;
718}
719
720
721void
722BPackageInfo::SetArchitecture(BPackageArchitecture architecture)
723{
724	fArchitecture = architecture;
725}
726
727
728void
729BPackageInfo::ClearCopyrightList()
730{
731	fCopyrightList.MakeEmpty();
732}
733
734
735status_t
736BPackageInfo::AddCopyright(const BString& copyright)
737{
738	return fCopyrightList.Add(copyright) ? B_OK : B_ERROR;
739}
740
741
742void
743BPackageInfo::ClearLicenseList()
744{
745	fLicenseList.MakeEmpty();
746}
747
748
749status_t
750BPackageInfo::AddLicense(const BString& license)
751{
752	return fLicenseList.Add(license) ? B_OK : B_ERROR;
753}
754
755
756void
757BPackageInfo::ClearURLList()
758{
759	fURLList.MakeEmpty();
760}
761
762
763status_t
764BPackageInfo::AddURL(const BString& url)
765{
766	return fURLList.Add(url) ? B_OK : B_NO_MEMORY;
767}
768
769
770void
771BPackageInfo::ClearSourceURLList()
772{
773	fSourceURLList.MakeEmpty();
774}
775
776
777status_t
778BPackageInfo::AddSourceURL(const BString& url)
779{
780	return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
781}
782
783
784void
785BPackageInfo::ClearGlobalWritableFileInfos()
786{
787	fGlobalWritableFileInfos.MakeEmpty();
788}
789
790
791status_t
792BPackageInfo::AddGlobalWritableFileInfo(const BGlobalWritableFileInfo& info)
793{
794	BGlobalWritableFileInfo* newInfo
795		= new (std::nothrow) BGlobalWritableFileInfo(info);
796	if (newInfo == NULL || !fGlobalWritableFileInfos.AddItem(newInfo)) {
797		delete newInfo;
798		return B_NO_MEMORY;
799	}
800
801	return B_OK;
802}
803
804
805void
806BPackageInfo::ClearUserSettingsFileInfos()
807{
808	fUserSettingsFileInfos.MakeEmpty();
809}
810
811
812status_t
813BPackageInfo::AddUserSettingsFileInfo(const BUserSettingsFileInfo& info)
814{
815	BUserSettingsFileInfo* newInfo
816		= new (std::nothrow) BUserSettingsFileInfo(info);
817	if (newInfo == NULL || !fUserSettingsFileInfos.AddItem(newInfo)) {
818		delete newInfo;
819		return B_NO_MEMORY;
820	}
821
822	return B_OK;
823}
824
825
826void
827BPackageInfo::ClearUsers()
828{
829	fUsers.MakeEmpty();
830}
831
832
833status_t
834BPackageInfo::AddUser(const BUser& user)
835{
836	BUser* newUser = new (std::nothrow) BUser(user);
837	if (newUser == NULL || !fUsers.AddItem(newUser)) {
838		delete newUser;
839		return B_NO_MEMORY;
840	}
841
842	return B_OK;
843}
844
845
846void
847BPackageInfo::ClearGroups()
848{
849	fGroups.MakeEmpty();
850}
851
852
853status_t
854BPackageInfo::AddGroup(const BString& group)
855{
856	return fGroups.Add(group) ? B_OK : B_NO_MEMORY;
857}
858
859
860void
861BPackageInfo::ClearPostInstallScripts()
862{
863	fPostInstallScripts.MakeEmpty();
864}
865
866
867void
868BPackageInfo::ClearPreUninstallScripts()
869{
870	fPreUninstallScripts.MakeEmpty();
871}
872
873
874status_t
875BPackageInfo::AddPostInstallScript(const BString& path)
876{
877	return fPostInstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
878}
879
880
881status_t
882BPackageInfo::AddPreUninstallScript(const BString& path)
883{
884	return fPreUninstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
885}
886
887
888void
889BPackageInfo::ClearProvidesList()
890{
891	fProvidesList.MakeEmpty();
892}
893
894
895status_t
896BPackageInfo::AddProvides(const BPackageResolvable& provides)
897{
898	BPackageResolvable* newProvides
899		= new (std::nothrow) BPackageResolvable(provides);
900	if (newProvides == NULL)
901		return B_NO_MEMORY;
902
903	return fProvidesList.AddItem(newProvides) ? B_OK : B_ERROR;
904}
905
906
907void
908BPackageInfo::ClearRequiresList()
909{
910	fRequiresList.MakeEmpty();
911}
912
913
914status_t
915BPackageInfo::AddRequires(const BPackageResolvableExpression& packageRequires)
916{
917	BPackageResolvableExpression* newRequires
918		= new (std::nothrow) BPackageResolvableExpression(packageRequires);
919	if (newRequires == NULL)
920		return B_NO_MEMORY;
921
922	return fRequiresList.AddItem(newRequires) ? B_OK : B_ERROR;
923}
924
925
926void
927BPackageInfo::ClearSupplementsList()
928{
929	fSupplementsList.MakeEmpty();
930}
931
932
933status_t
934BPackageInfo::AddSupplements(const BPackageResolvableExpression& supplements)
935{
936	BPackageResolvableExpression* newSupplements
937		= new (std::nothrow) BPackageResolvableExpression(supplements);
938	if (newSupplements == NULL)
939		return B_NO_MEMORY;
940
941	return fSupplementsList.AddItem(newSupplements) ? B_OK : B_ERROR;
942}
943
944
945void
946BPackageInfo::ClearConflictsList()
947{
948	fConflictsList.MakeEmpty();
949}
950
951
952status_t
953BPackageInfo::AddConflicts(const BPackageResolvableExpression& conflicts)
954{
955	BPackageResolvableExpression* newConflicts
956		= new (std::nothrow) BPackageResolvableExpression(conflicts);
957	if (newConflicts == NULL)
958		return B_NO_MEMORY;
959
960	return fConflictsList.AddItem(newConflicts) ? B_OK : B_ERROR;
961}
962
963
964void
965BPackageInfo::ClearFreshensList()
966{
967	fFreshensList.MakeEmpty();
968}
969
970
971status_t
972BPackageInfo::AddFreshens(const BPackageResolvableExpression& freshens)
973{
974	BPackageResolvableExpression* newFreshens
975		= new (std::nothrow) BPackageResolvableExpression(freshens);
976	if (newFreshens == NULL)
977		return B_NO_MEMORY;
978
979	return fFreshensList.AddItem(newFreshens) ? B_OK : B_ERROR;
980}
981
982
983void
984BPackageInfo::ClearReplacesList()
985{
986	fReplacesList.MakeEmpty();
987}
988
989
990status_t
991BPackageInfo::AddReplaces(const BString& replaces)
992{
993	return fReplacesList.Add(BString(replaces).ToLower()) ? B_OK : B_ERROR;
994}
995
996
997void
998BPackageInfo::Clear()
999{
1000	fName.Truncate(0);
1001	fSummary.Truncate(0);
1002	fDescription.Truncate(0);
1003	fVendor.Truncate(0);
1004	fPackager.Truncate(0);
1005	fBasePackage.Truncate(0);
1006	fChecksum.Truncate(0);
1007	fInstallPath.Truncate(0);
1008	fFileName.Truncate(0);
1009	fFlags = 0;
1010	fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT;
1011	fVersion.Clear();
1012	fCopyrightList.MakeEmpty();
1013	fLicenseList.MakeEmpty();
1014	fURLList.MakeEmpty();
1015	fSourceURLList.MakeEmpty();
1016	fGlobalWritableFileInfos.MakeEmpty();
1017	fUserSettingsFileInfos.MakeEmpty();
1018	fUsers.MakeEmpty();
1019	fGroups.MakeEmpty();
1020	fPostInstallScripts.MakeEmpty();
1021	fPreUninstallScripts.MakeEmpty();
1022	fRequiresList.MakeEmpty();
1023	fProvidesList.MakeEmpty();
1024	fSupplementsList.MakeEmpty();
1025	fConflictsList.MakeEmpty();
1026	fFreshensList.MakeEmpty();
1027	fReplacesList.MakeEmpty();
1028}
1029
1030
1031status_t
1032BPackageInfo::Archive(BMessage* archive, bool deep) const
1033{
1034	status_t error = BArchivable::Archive(archive, deep);
1035	if (error != B_OK)
1036		return error;
1037
1038	if ((error = archive->AddString("name", fName)) != B_OK
1039		|| (error = archive->AddString("summary", fSummary)) != B_OK
1040		|| (error = archive->AddString("description", fDescription)) != B_OK
1041		|| (error = archive->AddString("vendor", fVendor)) != B_OK
1042		|| (error = archive->AddString("packager", fPackager)) != B_OK
1043		|| (error = archive->AddString("basePackage", fBasePackage)) != B_OK
1044		|| (error = archive->AddUInt32("flags", fFlags)) != B_OK
1045		|| (error = archive->AddInt32("architecture", fArchitecture)) != B_OK
1046		|| (error = _AddVersion(archive, "version", fVersion)) != B_OK
1047		|| (error = archive->AddStrings("copyrights", fCopyrightList))
1048			!= B_OK
1049		|| (error = archive->AddStrings("licenses", fLicenseList)) != B_OK
1050		|| (error = archive->AddStrings("urls", fURLList)) != B_OK
1051		|| (error = archive->AddStrings("source-urls", fSourceURLList))
1052			!= B_OK
1053		|| (error = _AddGlobalWritableFileInfos(archive,
1054			"global-writable-files", fGlobalWritableFileInfos)) != B_OK
1055		|| (error = _AddUserSettingsFileInfos(archive,
1056			"user-settings-files", fUserSettingsFileInfos)) != B_OK
1057		|| (error = _AddUsers(archive, "users", fUsers)) != B_OK
1058		|| (error = archive->AddStrings("groups", fGroups)) != B_OK
1059		|| (error = archive->AddStrings("post-install-scripts",
1060			fPostInstallScripts)) != B_OK
1061		|| (error = archive->AddStrings("pre-uninstall-scripts",
1062			fPreUninstallScripts)) != B_OK
1063		|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
1064		|| (error = _AddResolvableExpressions(archive, "requires",
1065			fRequiresList)) != B_OK
1066		|| (error = _AddResolvableExpressions(archive, "supplements",
1067			fSupplementsList)) != B_OK
1068		|| (error = _AddResolvableExpressions(archive, "conflicts",
1069			fConflictsList)) != B_OK
1070		|| (error = _AddResolvableExpressions(archive, "freshens",
1071			fFreshensList)) != B_OK
1072		|| (error = archive->AddStrings("replaces", fReplacesList)) != B_OK
1073		|| (error = archive->AddString("checksum", fChecksum)) != B_OK
1074		|| (error = archive->AddString("install-path", fInstallPath)) != B_OK
1075		|| (error = archive->AddString("file-name", fFileName)) != B_OK) {
1076		return error;
1077	}
1078
1079	return B_OK;
1080}
1081
1082
1083/*static*/ BArchivable*
1084BPackageInfo::Instantiate(BMessage* archive)
1085{
1086	if (validate_instantiation(archive, "BPackageInfo"))
1087		return new(std::nothrow) BPackageInfo(archive);
1088	return NULL;
1089}
1090
1091
1092status_t
1093BPackageInfo::GetConfigString(BString& _string) const
1094{
1095	return StringBuilder()
1096		.Write("name", fName)
1097		.Write("version", fVersion)
1098		.Write("summary", fSummary)
1099		.Write("description", fDescription)
1100		.Write("vendor", fVendor)
1101		.Write("packager", fPackager)
1102		.Write("architecture", kArchitectureNames[fArchitecture])
1103		.Write("copyrights", fCopyrightList)
1104		.Write("licenses", fLicenseList)
1105		.Write("urls", fURLList)
1106		.Write("source-urls", fSourceURLList)
1107		.Write("global-writable-files", fGlobalWritableFileInfos)
1108		.Write("user-settings-files", fUserSettingsFileInfos)
1109		.Write("users", fUsers)
1110		.Write("groups", fGroups)
1111		.Write("post-install-scripts", fPostInstallScripts)
1112		.Write("pre-uninstall-scripts", fPreUninstallScripts)
1113		.Write("provides", fProvidesList)
1114		.BeginRequires(fBasePackage)
1115			.Write("requires", fRequiresList)
1116		.EndRequires()
1117		.Write("supplements", fSupplementsList)
1118		.Write("conflicts", fConflictsList)
1119		.Write("freshens", fFreshensList)
1120		.Write("replaces", fReplacesList)
1121		.WriteFlags("flags", fFlags)
1122		.Write("checksum", fChecksum)
1123		.GetString(_string);
1124	// Note: fInstallPath and fFileName can not be specified via .PackageInfo.
1125}
1126
1127
1128BString
1129BPackageInfo::ToString() const
1130{
1131	BString string;
1132	GetConfigString(string);
1133	return string;
1134}
1135
1136
1137/*static*/ status_t
1138BPackageInfo::GetArchitectureByName(const BString& name,
1139	BPackageArchitecture& _architecture)
1140{
1141	for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) {
1142		if (name.ICompare(kArchitectureNames[i]) == 0) {
1143			_architecture = (BPackageArchitecture)i;
1144			return B_OK;
1145		}
1146	}
1147	return B_NAME_NOT_FOUND;
1148}
1149
1150
1151/*static*/ status_t
1152BPackageInfo::ParseVersionString(const BString& string, bool revisionIsOptional,
1153	BPackageVersion& _version, ParseErrorListener* listener)
1154{
1155	return Parser(listener).ParseVersion(string, revisionIsOptional, _version);
1156}
1157
1158
1159/*static*/ status_t
1160BPackageInfo::ParseResolvableString(const BString& string,
1161	BPackageResolvable& _expression, ParseErrorListener* listener)
1162{
1163	return Parser(listener).ParseResolvable(string, _expression);
1164}
1165
1166
1167/*static*/ status_t
1168BPackageInfo::ParseResolvableExpressionString(const BString& string,
1169	BPackageResolvableExpression& _expression, ParseErrorListener* listener)
1170{
1171	return Parser(listener).ParseResolvableExpression(string, _expression);
1172}
1173
1174
1175status_t
1176BPackageInfo::_ReadFromPackageFile(const PackageFileLocation& fileLocation)
1177{
1178	BHPKG::BNoErrorOutput errorOutput;
1179
1180	// try current package file format version
1181	{
1182		BHPKG::BPackageReader packageReader(&errorOutput);
1183		status_t error = fileLocation.Path() != NULL
1184			? packageReader.Init(fileLocation.Path())
1185			: packageReader.Init(fileLocation.FD(), false);
1186		if (error == B_OK) {
1187			BPackageInfoContentHandler handler(*this);
1188			return packageReader.ParseContent(&handler);
1189		}
1190
1191		if (error != B_MISMATCHED_VALUES)
1192			return error;
1193	}
1194
1195	// try package file format version 1
1196	BHPKG::V1::BPackageReader packageReader(&errorOutput);
1197	status_t error = fileLocation.Path() != NULL
1198		? packageReader.Init(fileLocation.Path())
1199		: packageReader.Init(fileLocation.FD(), false);
1200	if (error != B_OK)
1201		return error;
1202
1203	BHPKG::V1::BPackageInfoContentHandler handler(*this);
1204	return packageReader.ParseContent(&handler);
1205}
1206
1207
1208/*static*/ status_t
1209BPackageInfo::_AddVersion(BMessage* archive, const char* field,
1210	const BPackageVersion& version)
1211{
1212	// Storing BPackageVersion::ToString() would be nice, but the corresponding
1213	// constructor only works for valid versions and we might want to store
1214	// invalid versions as well.
1215
1216	// major
1217	size_t fieldLength = strlen(field);
1218	FieldName fieldName(field, ":major");
1219	if (!fieldName.IsValid())
1220		return B_BAD_VALUE;
1221
1222	status_t error = archive->AddString(fieldName, version.Major());
1223	if (error != B_OK)
1224		return error;
1225
1226	// minor
1227	if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
1228		return B_BAD_VALUE;
1229
1230	error = archive->AddString(fieldName, version.Minor());
1231	if (error != B_OK)
1232		return error;
1233
1234	// micro
1235	if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
1236		return B_BAD_VALUE;
1237
1238	error = archive->AddString(fieldName, version.Micro());
1239	if (error != B_OK)
1240		return error;
1241
1242	// pre-release
1243	if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
1244		return B_BAD_VALUE;
1245
1246	error = archive->AddString(fieldName, version.PreRelease());
1247	if (error != B_OK)
1248		return error;
1249
1250	// revision
1251	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
1252		return B_BAD_VALUE;
1253
1254	return archive->AddUInt32(fieldName, version.Revision());
1255}
1256
1257
1258/*static*/ status_t
1259BPackageInfo::_AddResolvables(BMessage* archive, const char* field,
1260	const ResolvableList& resolvables)
1261{
1262	// construct the field names we need
1263	FieldName nameField(field, ":name");
1264	FieldName typeField(field, ":type");
1265	FieldName versionField(field, ":version");
1266	FieldName compatibleVersionField(field, ":compat");
1267
1268	if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
1269		|| !compatibleVersionField.IsValid()) {
1270		return B_BAD_VALUE;
1271	}
1272
1273	// add fields
1274	int32 count = resolvables.CountItems();
1275	for (int32 i = 0; i < count; i++) {
1276		const BPackageResolvable* resolvable = resolvables.ItemAt(i);
1277		status_t error;
1278		if ((error = archive->AddString(nameField, resolvable->Name())) != B_OK
1279			|| (error = _AddVersion(archive, versionField,
1280				resolvable->Version())) != B_OK
1281			|| (error = _AddVersion(archive, compatibleVersionField,
1282				resolvable->CompatibleVersion())) != B_OK) {
1283			return error;
1284		}
1285	}
1286
1287	return B_OK;
1288}
1289
1290
1291/*static*/ status_t
1292BPackageInfo::_AddResolvableExpressions(BMessage* archive, const char* field,
1293	const ResolvableExpressionList& expressions)
1294{
1295	// construct the field names we need
1296	FieldName nameField(field, ":name");
1297	FieldName operatorField(field, ":operator");
1298	FieldName versionField(field, ":version");
1299
1300	if (!nameField.IsValid() || !operatorField.IsValid()
1301		|| !versionField.IsValid()) {
1302		return B_BAD_VALUE;
1303	}
1304
1305	// add fields
1306	int32 count = expressions.CountItems();
1307	for (int32 i = 0; i < count; i++) {
1308		const BPackageResolvableExpression* expression = expressions.ItemAt(i);
1309		status_t error;
1310		if ((error = archive->AddString(nameField, expression->Name())) != B_OK
1311			|| (error = archive->AddInt32(operatorField,
1312				expression->Operator())) != B_OK
1313			|| (error = _AddVersion(archive, versionField,
1314				expression->Version())) != B_OK) {
1315			return error;
1316		}
1317	}
1318
1319	return B_OK;
1320}
1321
1322
1323/*static*/ status_t
1324BPackageInfo::_AddGlobalWritableFileInfos(BMessage* archive, const char* field,
1325	const GlobalWritableFileInfoList& infos)
1326{
1327	// construct the field names we need
1328	FieldName pathField(field, ":path");
1329	FieldName updateTypeField(field, ":updateType");
1330	FieldName isDirectoryField(field, ":isDirectory");
1331
1332	if (!pathField.IsValid() || !updateTypeField.IsValid()
1333		|| !isDirectoryField.IsValid()) {
1334		return B_BAD_VALUE;
1335	}
1336
1337	// add fields
1338	int32 count = infos.CountItems();
1339	for (int32 i = 0; i < count; i++) {
1340		const BGlobalWritableFileInfo* info = infos.ItemAt(i);
1341		status_t error;
1342		if ((error = archive->AddString(pathField, info->Path())) != B_OK
1343			|| (error = archive->AddInt32(updateTypeField, info->UpdateType()))
1344				!= B_OK
1345			|| (error = archive->AddBool(isDirectoryField,
1346				info->IsDirectory())) != B_OK) {
1347			return error;
1348		}
1349	}
1350
1351	return B_OK;
1352}
1353
1354
1355/*static*/ status_t
1356BPackageInfo::_AddUserSettingsFileInfos(BMessage* archive, const char* field,
1357	const UserSettingsFileInfoList& infos)
1358{
1359	// construct the field names we need
1360	FieldName pathField(field, ":path");
1361	FieldName templatePathField(field, ":templatePath");
1362	FieldName isDirectoryField(field, ":isDirectory");
1363
1364	if (!pathField.IsValid() || !templatePathField.IsValid()
1365		|| !isDirectoryField.IsValid()) {
1366		return B_BAD_VALUE;
1367	}
1368
1369	// add fields
1370	int32 count = infos.CountItems();
1371	for (int32 i = 0; i < count; i++) {
1372		const BUserSettingsFileInfo* info = infos.ItemAt(i);
1373		status_t error;
1374		if ((error = archive->AddString(pathField, info->Path())) != B_OK
1375			|| (error = archive->AddString(templatePathField,
1376				info->TemplatePath())) != B_OK
1377			|| (error = archive->AddBool(isDirectoryField,
1378				info->IsDirectory())) != B_OK) {
1379			return error;
1380		}
1381	}
1382
1383	return B_OK;
1384}
1385
1386
1387/*static*/ status_t
1388BPackageInfo::_AddUsers(BMessage* archive, const char* field,
1389	const UserList& users)
1390{
1391	// construct the field names we need
1392	FieldName nameField(field, ":name");
1393	FieldName realNameField(field, ":realName");
1394	FieldName homeField(field, ":home");
1395	FieldName shellField(field, ":shell");
1396	FieldName groupsField(field, ":groups");
1397
1398	if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
1399		|| !shellField.IsValid() || !groupsField.IsValid())
1400		return B_BAD_VALUE;
1401
1402	// add fields
1403	int32 count = users.CountItems();
1404	for (int32 i = 0; i < count; i++) {
1405		const BUser* user = users.ItemAt(i);
1406		BString groups = user->Groups().Join(" ");
1407		if (groups.IsEmpty() && !user->Groups().IsEmpty())
1408			return B_NO_MEMORY;
1409
1410		status_t error;
1411		if ((error = archive->AddString(nameField, user->Name())) != B_OK
1412			|| (error = archive->AddString(realNameField, user->RealName()))
1413				!= B_OK
1414			|| (error = archive->AddString(homeField, user->Home())) != B_OK
1415			|| (error = archive->AddString(shellField, user->Shell())) != B_OK
1416			|| (error = archive->AddString(groupsField, groups)) != B_OK) {
1417			return error;
1418		}
1419	}
1420
1421	return B_OK;
1422}
1423
1424
1425/*static*/ status_t
1426BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
1427	BPackageVersion& _version)
1428{
1429	// major
1430	size_t fieldLength = strlen(field);
1431	FieldName fieldName(field, ":major");
1432	if (!fieldName.IsValid())
1433		return B_BAD_VALUE;
1434
1435	BString major;
1436	status_t error = archive->FindString(fieldName, index, &major);
1437	if (error != B_OK)
1438		return error;
1439
1440	// minor
1441	if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
1442		return B_BAD_VALUE;
1443
1444	BString minor;
1445	error = archive->FindString(fieldName, index, &minor);
1446	if (error != B_OK)
1447		return error;
1448
1449	// micro
1450	if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
1451		return B_BAD_VALUE;
1452
1453	BString micro;
1454	error = archive->FindString(fieldName, index, &micro);
1455	if (error != B_OK)
1456		return error;
1457
1458	// pre-release
1459	if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
1460		return B_BAD_VALUE;
1461
1462	BString preRelease;
1463	error = archive->FindString(fieldName, index, &preRelease);
1464	if (error != B_OK)
1465		return error;
1466
1467	// revision
1468	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
1469		return B_BAD_VALUE;
1470
1471	uint32 revision;
1472	error = archive->FindUInt32(fieldName, index, &revision);
1473	if (error != B_OK)
1474		return error;
1475
1476	_version.SetTo(major, minor, micro, preRelease, revision);
1477	return B_OK;
1478}
1479
1480
1481/*static*/ status_t
1482BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
1483	BStringList& _list)
1484{
1485	status_t error = archive->FindStrings(field, &_list);
1486	return error == B_NAME_NOT_FOUND ? B_OK : error;
1487		// If the field doesn't exist, that's OK.
1488}
1489
1490
1491/*static*/ status_t
1492BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field,
1493	ResolvableList& _resolvables)
1494{
1495	// construct the field names we need
1496	FieldName nameField(field, ":name");
1497	FieldName typeField(field, ":type");
1498	FieldName versionField(field, ":version");
1499	FieldName compatibleVersionField(field, ":compat");
1500
1501	if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
1502		|| !compatibleVersionField.IsValid()) {
1503		return B_BAD_VALUE;
1504	}
1505
1506	// get the number of items
1507	type_code type;
1508	int32 count;
1509	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1510		// the field is missing
1511		return B_OK;
1512	}
1513
1514	// extract fields
1515	for (int32 i = 0; i < count; i++) {
1516		BString name;
1517		status_t error = archive->FindString(nameField, i, &name);
1518		if (error != B_OK)
1519			return error;
1520
1521		BPackageVersion version;
1522		error = _ExtractVersion(archive, versionField, i, version);
1523		if (error != B_OK)
1524			return error;
1525
1526		BPackageVersion compatibleVersion;
1527		error = _ExtractVersion(archive, compatibleVersionField, i,
1528			compatibleVersion);
1529		if (error != B_OK)
1530			return error;
1531
1532		BPackageResolvable* resolvable = new(std::nothrow) BPackageResolvable(
1533			name, version, compatibleVersion);
1534		if (resolvable == NULL || !_resolvables.AddItem(resolvable)) {
1535			delete resolvable;
1536			return B_NO_MEMORY;
1537		}
1538	}
1539
1540	return B_OK;
1541}
1542
1543
1544/*static*/ status_t
1545BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
1546	const char* field, ResolvableExpressionList& _expressions)
1547{
1548	// construct the field names we need
1549	FieldName nameField(field, ":name");
1550	FieldName operatorField(field, ":operator");
1551	FieldName versionField(field, ":version");
1552
1553	if (!nameField.IsValid() || !operatorField.IsValid()
1554		|| !versionField.IsValid()) {
1555		return B_BAD_VALUE;
1556	}
1557
1558	// get the number of items
1559	type_code type;
1560	int32 count;
1561	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1562		// the field is missing
1563		return B_OK;
1564	}
1565
1566	// extract fields
1567	for (int32 i = 0; i < count; i++) {
1568		BString name;
1569		status_t error = archive->FindString(nameField, i, &name);
1570		if (error != B_OK)
1571			return error;
1572
1573		int32 operatorType;
1574		error = archive->FindInt32(operatorField, i, &operatorType);
1575		if (error != B_OK)
1576			return error;
1577		if (operatorType < 0
1578			|| operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
1579			return B_BAD_DATA;
1580		}
1581
1582		BPackageVersion version;
1583		error = _ExtractVersion(archive, versionField, i, version);
1584		if (error != B_OK)
1585			return error;
1586
1587		BPackageResolvableExpression* expression
1588			= new(std::nothrow) BPackageResolvableExpression(name,
1589				(BPackageResolvableOperator)operatorType, version);
1590		if (expression == NULL || !_expressions.AddItem(expression)) {
1591			delete expression;
1592			return B_NO_MEMORY;
1593		}
1594	}
1595
1596	return B_OK;
1597}
1598
1599
1600/*static*/ status_t
1601BPackageInfo::_ExtractGlobalWritableFileInfos(BMessage* archive,
1602	const char* field, GlobalWritableFileInfoList& _infos)
1603{
1604	// construct the field names we need
1605	FieldName pathField(field, ":path");
1606	FieldName updateTypeField(field, ":updateType");
1607	FieldName isDirectoryField(field, ":isDirectory");
1608
1609	if (!pathField.IsValid() || !updateTypeField.IsValid()
1610		|| !isDirectoryField.IsValid()) {
1611		return B_BAD_VALUE;
1612	}
1613
1614	// get the number of items
1615	type_code type;
1616	int32 count;
1617	if (archive->GetInfo(pathField, &type, &count) != B_OK) {
1618		// the field is missing
1619		return B_OK;
1620	}
1621
1622	// extract fields
1623	for (int32 i = 0; i < count; i++) {
1624		BString path;
1625		status_t error = archive->FindString(pathField, i, &path);
1626		if (error != B_OK)
1627			return error;
1628
1629		int32 updateType;
1630		error = archive->FindInt32(updateTypeField, i, &updateType);
1631		if (error != B_OK)
1632			return error;
1633		if (updateType < 0
1634			|| updateType > B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT) {
1635			return B_BAD_DATA;
1636		}
1637
1638		bool isDirectory;
1639		error = archive->FindBool(isDirectoryField, i, &isDirectory);
1640		if (error != B_OK)
1641			return error;
1642
1643		BGlobalWritableFileInfo* info
1644			= new(std::nothrow) BGlobalWritableFileInfo(path,
1645				(BWritableFileUpdateType)updateType, isDirectory);
1646		if (info == NULL || !_infos.AddItem(info)) {
1647			delete info;
1648			return B_NO_MEMORY;
1649		}
1650	}
1651
1652	return B_OK;
1653}
1654
1655
1656/*static*/ status_t
1657BPackageInfo::_ExtractUserSettingsFileInfos(BMessage* archive,
1658	const char* field, UserSettingsFileInfoList& _infos)
1659{
1660	// construct the field names we need
1661	FieldName pathField(field, ":path");
1662	FieldName templatePathField(field, ":templatePath");
1663	FieldName isDirectoryField(field, ":isDirectory");
1664
1665	if (!pathField.IsValid() || !templatePathField.IsValid()
1666		|| !isDirectoryField.IsValid()) {
1667		return B_BAD_VALUE;
1668	}
1669
1670	// get the number of items
1671	type_code type;
1672	int32 count;
1673	if (archive->GetInfo(pathField, &type, &count) != B_OK) {
1674		// the field is missing
1675		return B_OK;
1676	}
1677
1678	// extract fields
1679	for (int32 i = 0; i < count; i++) {
1680		BString path;
1681		status_t error = archive->FindString(pathField, i, &path);
1682		if (error != B_OK)
1683			return error;
1684
1685		BString templatePath;
1686		error = archive->FindString(templatePathField, i, &templatePath);
1687		if (error != B_OK)
1688			return error;
1689
1690		bool isDirectory;
1691		error = archive->FindBool(isDirectoryField, i, &isDirectory);
1692		if (error != B_OK)
1693			return error;
1694
1695		BUserSettingsFileInfo* info = isDirectory
1696			? new(std::nothrow) BUserSettingsFileInfo(path, true)
1697			: new(std::nothrow) BUserSettingsFileInfo(path, templatePath);
1698		if (info == NULL || !_infos.AddItem(info)) {
1699			delete info;
1700			return B_NO_MEMORY;
1701		}
1702	}
1703
1704	return B_OK;
1705}
1706
1707
1708/*static*/ status_t
1709BPackageInfo::_ExtractUsers(BMessage* archive, const char* field,
1710	UserList& _users)
1711{
1712	// construct the field names we need
1713	FieldName nameField(field, ":name");
1714	FieldName realNameField(field, ":realName");
1715	FieldName homeField(field, ":home");
1716	FieldName shellField(field, ":shell");
1717	FieldName groupsField(field, ":groups");
1718
1719	if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
1720		|| !shellField.IsValid() || !groupsField.IsValid())
1721		return B_BAD_VALUE;
1722
1723	// get the number of items
1724	type_code type;
1725	int32 count;
1726	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1727		// the field is missing
1728		return B_OK;
1729	}
1730
1731	// extract fields
1732	for (int32 i = 0; i < count; i++) {
1733		BString name;
1734		status_t error = archive->FindString(nameField, i, &name);
1735		if (error != B_OK)
1736			return error;
1737
1738		BString realName;
1739		error = archive->FindString(realNameField, i, &realName);
1740		if (error != B_OK)
1741			return error;
1742
1743		BString home;
1744		error = archive->FindString(homeField, i, &home);
1745		if (error != B_OK)
1746			return error;
1747
1748		BString shell;
1749		error = archive->FindString(shellField, i, &shell);
1750		if (error != B_OK)
1751			return error;
1752
1753		BString groupsString;
1754		error = archive->FindString(groupsField, i, &groupsString);
1755		if (error != B_OK)
1756			return error;
1757
1758		BStringList groups;
1759		if (!groupsString.IsEmpty() && !groupsString.Split(" ", false, groups))
1760			return B_NO_MEMORY;
1761
1762		BUser* user = new(std::nothrow) BUser(name, realName, home, shell,
1763			groups);
1764		if (user == NULL || !_users.AddItem(user)) {
1765			delete user;
1766			return B_NO_MEMORY;
1767		}
1768	}
1769
1770	return B_OK;
1771}
1772
1773
1774}	// namespace BPackageKit
1775