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