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