xref: /haiku/src/kits/package/PackageInfo.cpp (revision 62b164bd7174bb8cbb4f1617c91cd13b3b2a5ccb)
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 BPackageVersion&
474 BPackageInfo::Version() const
475 {
476 	return fVersion;
477 }
478 
479 
480 const BStringList&
481 BPackageInfo::CopyrightList() const
482 {
483 	return fCopyrightList;
484 }
485 
486 
487 const BStringList&
488 BPackageInfo::LicenseList() const
489 {
490 	return fLicenseList;
491 }
492 
493 
494 const BStringList&
495 BPackageInfo::URLList() const
496 {
497 	return fURLList;
498 }
499 
500 
501 const BStringList&
502 BPackageInfo::SourceURLList() const
503 {
504 	return fSourceURLList;
505 }
506 
507 
508 const BObjectList<BGlobalWritableFileInfo>&
509 BPackageInfo::GlobalWritableFileInfos() const
510 {
511 	return fGlobalWritableFileInfos;
512 }
513 
514 
515 const BObjectList<BUserSettingsFileInfo>&
516 BPackageInfo::UserSettingsFileInfos() const
517 {
518 	return fUserSettingsFileInfos;
519 }
520 
521 
522 const BObjectList<BUser>&
523 BPackageInfo::Users() const
524 {
525 	return fUsers;
526 }
527 
528 
529 const BStringList&
530 BPackageInfo::Groups() const
531 {
532 	return fGroups;
533 }
534 
535 
536 const BStringList&
537 BPackageInfo::PostInstallScripts() const
538 {
539 	return fPostInstallScripts;
540 }
541 
542 
543 const BObjectList<BPackageResolvable>&
544 BPackageInfo::ProvidesList() const
545 {
546 	return fProvidesList;
547 }
548 
549 
550 const BObjectList<BPackageResolvableExpression>&
551 BPackageInfo::RequiresList() const
552 {
553 	return fRequiresList;
554 }
555 
556 
557 const BObjectList<BPackageResolvableExpression>&
558 BPackageInfo::SupplementsList() const
559 {
560 	return fSupplementsList;
561 }
562 
563 
564 const BObjectList<BPackageResolvableExpression>&
565 BPackageInfo::ConflictsList() const
566 {
567 	return fConflictsList;
568 }
569 
570 
571 const BObjectList<BPackageResolvableExpression>&
572 BPackageInfo::FreshensList() const
573 {
574 	return fFreshensList;
575 }
576 
577 
578 const BStringList&
579 BPackageInfo::ReplacesList() const
580 {
581 	return fReplacesList;
582 }
583 
584 
585 BString
586 BPackageInfo::CanonicalFileName() const
587 {
588 	if (InitCheck() != B_OK)
589 		return BString();
590 
591 	return BString().SetToFormat("%s-%s-%s.hpkg", fName.String(),
592 		fVersion.ToString().String(), kArchitectureNames[fArchitecture]);
593 }
594 
595 
596 bool
597 BPackageInfo::Matches(const BPackageResolvableExpression& expression) const
598 {
599 	// check for an explicit match on the package
600 	if (expression.Name().StartsWith("pkg:")) {
601 		return fName == expression.Name().String() + 4
602 			&& expression.Matches(fVersion, fVersion);
603 	}
604 
605 	// search for a matching provides
606 	int32 count = fProvidesList.CountItems();
607 	for (int32 i = 0; i < count; i++) {
608 		const BPackageResolvable* provides = fProvidesList.ItemAt(i);
609 		if (expression.Matches(*provides))
610 			return true;
611 	}
612 
613 	return false;
614 }
615 
616 
617 void
618 BPackageInfo::SetName(const BString& name)
619 {
620 	fName = name;
621 	fName.ToLower();
622 }
623 
624 
625 void
626 BPackageInfo::SetSummary(const BString& summary)
627 {
628 	fSummary = summary;
629 }
630 
631 
632 void
633 BPackageInfo::SetDescription(const BString& description)
634 {
635 	fDescription = description;
636 }
637 
638 
639 void
640 BPackageInfo::SetVendor(const BString& vendor)
641 {
642 	fVendor = vendor;
643 }
644 
645 
646 void
647 BPackageInfo::SetPackager(const BString& packager)
648 {
649 	fPackager = packager;
650 }
651 
652 
653 void
654 BPackageInfo::SetBasePackage(const BString& basePackage)
655 {
656 	fBasePackage = basePackage;
657 }
658 
659 
660 void
661 BPackageInfo::SetChecksum(const BString& checksum)
662 {
663 	fChecksum = checksum;
664 }
665 
666 
667 void
668 BPackageInfo::SetInstallPath(const BString& installPath)
669 {
670 	fInstallPath = installPath;
671 }
672 
673 
674 void
675 BPackageInfo::SetFileName(const BString& fileName)
676 {
677 	fFileName = fileName;
678 }
679 
680 
681 void
682 BPackageInfo::SetVersion(const BPackageVersion& version)
683 {
684 	fVersion = version;
685 }
686 
687 
688 void
689 BPackageInfo::SetFlags(uint32 flags)
690 {
691 	fFlags = flags;
692 }
693 
694 
695 void
696 BPackageInfo::SetArchitecture(BPackageArchitecture architecture)
697 {
698 	fArchitecture = architecture;
699 }
700 
701 
702 void
703 BPackageInfo::ClearCopyrightList()
704 {
705 	fCopyrightList.MakeEmpty();
706 }
707 
708 
709 status_t
710 BPackageInfo::AddCopyright(const BString& copyright)
711 {
712 	return fCopyrightList.Add(copyright) ? B_OK : B_ERROR;
713 }
714 
715 
716 void
717 BPackageInfo::ClearLicenseList()
718 {
719 	fLicenseList.MakeEmpty();
720 }
721 
722 
723 status_t
724 BPackageInfo::AddLicense(const BString& license)
725 {
726 	return fLicenseList.Add(license) ? B_OK : B_ERROR;
727 }
728 
729 
730 void
731 BPackageInfo::ClearURLList()
732 {
733 	fURLList.MakeEmpty();
734 }
735 
736 
737 status_t
738 BPackageInfo::AddURL(const BString& url)
739 {
740 	return fURLList.Add(url) ? B_OK : B_NO_MEMORY;
741 }
742 
743 
744 void
745 BPackageInfo::ClearSourceURLList()
746 {
747 	fSourceURLList.MakeEmpty();
748 }
749 
750 
751 status_t
752 BPackageInfo::AddSourceURL(const BString& url)
753 {
754 	return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
755 }
756 
757 
758 void
759 BPackageInfo::ClearGlobalWritableFileInfos()
760 {
761 	fGlobalWritableFileInfos.MakeEmpty();
762 }
763 
764 
765 status_t
766 BPackageInfo::AddGlobalWritableFileInfo(const BGlobalWritableFileInfo& info)
767 {
768 	BGlobalWritableFileInfo* newInfo
769 		= new (std::nothrow) BGlobalWritableFileInfo(info);
770 	if (newInfo == NULL || !fGlobalWritableFileInfos.AddItem(newInfo)) {
771 		delete newInfo;
772 		return B_NO_MEMORY;
773 	}
774 
775 	return B_OK;
776 }
777 
778 
779 void
780 BPackageInfo::ClearUserSettingsFileInfos()
781 {
782 	fUserSettingsFileInfos.MakeEmpty();
783 }
784 
785 
786 status_t
787 BPackageInfo::AddUserSettingsFileInfo(const BUserSettingsFileInfo& info)
788 {
789 	BUserSettingsFileInfo* newInfo
790 		= new (std::nothrow) BUserSettingsFileInfo(info);
791 	if (newInfo == NULL || !fUserSettingsFileInfos.AddItem(newInfo)) {
792 		delete newInfo;
793 		return B_NO_MEMORY;
794 	}
795 
796 	return B_OK;
797 }
798 
799 
800 void
801 BPackageInfo::ClearUsers()
802 {
803 	fUsers.MakeEmpty();
804 }
805 
806 
807 status_t
808 BPackageInfo::AddUser(const BUser& user)
809 {
810 	BUser* newUser = new (std::nothrow) BUser(user);
811 	if (newUser == NULL || !fUsers.AddItem(newUser)) {
812 		delete newUser;
813 		return B_NO_MEMORY;
814 	}
815 
816 	return B_OK;
817 }
818 
819 
820 void
821 BPackageInfo::ClearGroups()
822 {
823 	fGroups.MakeEmpty();
824 }
825 
826 
827 status_t
828 BPackageInfo::AddGroup(const BString& group)
829 {
830 	return fGroups.Add(group) ? B_OK : B_NO_MEMORY;
831 }
832 
833 
834 void
835 BPackageInfo::ClearPostInstallScripts()
836 {
837 	fPostInstallScripts.MakeEmpty();
838 }
839 
840 
841 status_t
842 BPackageInfo::AddPostInstallScript(const BString& path)
843 {
844 	return fPostInstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
845 }
846 
847 
848 void
849 BPackageInfo::ClearProvidesList()
850 {
851 	fProvidesList.MakeEmpty();
852 }
853 
854 
855 status_t
856 BPackageInfo::AddProvides(const BPackageResolvable& provides)
857 {
858 	BPackageResolvable* newProvides
859 		= new (std::nothrow) BPackageResolvable(provides);
860 	if (newProvides == NULL)
861 		return B_NO_MEMORY;
862 
863 	return fProvidesList.AddItem(newProvides) ? B_OK : B_ERROR;
864 }
865 
866 
867 void
868 BPackageInfo::ClearRequiresList()
869 {
870 	fRequiresList.MakeEmpty();
871 }
872 
873 
874 status_t
875 BPackageInfo::AddRequires(const BPackageResolvableExpression& requires)
876 {
877 	BPackageResolvableExpression* newRequires
878 		= new (std::nothrow) BPackageResolvableExpression(requires);
879 	if (newRequires == NULL)
880 		return B_NO_MEMORY;
881 
882 	return fRequiresList.AddItem(newRequires) ? B_OK : B_ERROR;
883 }
884 
885 
886 void
887 BPackageInfo::ClearSupplementsList()
888 {
889 	fSupplementsList.MakeEmpty();
890 }
891 
892 
893 status_t
894 BPackageInfo::AddSupplements(const BPackageResolvableExpression& supplements)
895 {
896 	BPackageResolvableExpression* newSupplements
897 		= new (std::nothrow) BPackageResolvableExpression(supplements);
898 	if (newSupplements == NULL)
899 		return B_NO_MEMORY;
900 
901 	return fSupplementsList.AddItem(newSupplements) ? B_OK : B_ERROR;
902 }
903 
904 
905 void
906 BPackageInfo::ClearConflictsList()
907 {
908 	fConflictsList.MakeEmpty();
909 }
910 
911 
912 status_t
913 BPackageInfo::AddConflicts(const BPackageResolvableExpression& conflicts)
914 {
915 	BPackageResolvableExpression* newConflicts
916 		= new (std::nothrow) BPackageResolvableExpression(conflicts);
917 	if (newConflicts == NULL)
918 		return B_NO_MEMORY;
919 
920 	return fConflictsList.AddItem(newConflicts) ? B_OK : B_ERROR;
921 }
922 
923 
924 void
925 BPackageInfo::ClearFreshensList()
926 {
927 	fFreshensList.MakeEmpty();
928 }
929 
930 
931 status_t
932 BPackageInfo::AddFreshens(const BPackageResolvableExpression& freshens)
933 {
934 	BPackageResolvableExpression* newFreshens
935 		= new (std::nothrow) BPackageResolvableExpression(freshens);
936 	if (newFreshens == NULL)
937 		return B_NO_MEMORY;
938 
939 	return fFreshensList.AddItem(newFreshens) ? B_OK : B_ERROR;
940 }
941 
942 
943 void
944 BPackageInfo::ClearReplacesList()
945 {
946 	fReplacesList.MakeEmpty();
947 }
948 
949 
950 status_t
951 BPackageInfo::AddReplaces(const BString& replaces)
952 {
953 	return fReplacesList.Add(BString(replaces).ToLower()) ? B_OK : B_ERROR;
954 }
955 
956 
957 void
958 BPackageInfo::Clear()
959 {
960 	fName.Truncate(0);
961 	fSummary.Truncate(0);
962 	fDescription.Truncate(0);
963 	fVendor.Truncate(0);
964 	fPackager.Truncate(0);
965 	fBasePackage.Truncate(0);
966 	fChecksum.Truncate(0);
967 	fInstallPath.Truncate(0);
968 	fFileName.Truncate(0);
969 	fFlags = 0;
970 	fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT;
971 	fVersion.Clear();
972 	fCopyrightList.MakeEmpty();
973 	fLicenseList.MakeEmpty();
974 	fURLList.MakeEmpty();
975 	fSourceURLList.MakeEmpty();
976 	fGlobalWritableFileInfos.MakeEmpty();
977 	fUserSettingsFileInfos.MakeEmpty();
978 	fUsers.MakeEmpty();
979 	fGroups.MakeEmpty();
980 	fPostInstallScripts.MakeEmpty();
981 	fRequiresList.MakeEmpty();
982 	fProvidesList.MakeEmpty();
983 	fSupplementsList.MakeEmpty();
984 	fConflictsList.MakeEmpty();
985 	fFreshensList.MakeEmpty();
986 	fReplacesList.MakeEmpty();
987 }
988 
989 
990 status_t
991 BPackageInfo::Archive(BMessage* archive, bool deep) const
992 {
993 	status_t error = BArchivable::Archive(archive, deep);
994 	if (error != B_OK)
995 		return error;
996 
997 	if ((error = archive->AddString("name", fName)) != B_OK
998 		|| (error = archive->AddString("summary", fSummary)) != B_OK
999 		|| (error = archive->AddString("description", fDescription)) != B_OK
1000 		|| (error = archive->AddString("vendor", fVendor)) != B_OK
1001 		|| (error = archive->AddString("packager", fPackager)) != B_OK
1002 		|| (error = archive->AddString("basePackage", fBasePackage)) != B_OK
1003 		|| (error = archive->AddUInt32("flags", fFlags)) != B_OK
1004 		|| (error = archive->AddInt32("architecture", fArchitecture)) != B_OK
1005 		|| (error = _AddVersion(archive, "version", fVersion)) != B_OK
1006 		|| (error = archive->AddStrings("copyrights", fCopyrightList))
1007 			!= B_OK
1008 		|| (error = archive->AddStrings("licenses", fLicenseList)) != B_OK
1009 		|| (error = archive->AddStrings("urls", fURLList)) != B_OK
1010 		|| (error = archive->AddStrings("source-urls", fSourceURLList))
1011 			!= B_OK
1012 		|| (error = _AddGlobalWritableFileInfos(archive,
1013 			"global-writable-files", fGlobalWritableFileInfos)) != B_OK
1014 		|| (error = _AddUserSettingsFileInfos(archive,
1015 			"user-settings-files", fUserSettingsFileInfos)) != B_OK
1016 		|| (error = _AddUsers(archive, "users", fUsers)) != B_OK
1017 		|| (error = archive->AddStrings("groups", fGroups)) != B_OK
1018 		|| (error = archive->AddStrings("post-install-scripts",
1019 			fPostInstallScripts)) != B_OK
1020 		|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
1021 		|| (error = _AddResolvableExpressions(archive, "requires",
1022 			fRequiresList)) != B_OK
1023 		|| (error = _AddResolvableExpressions(archive, "supplements",
1024 			fSupplementsList)) != B_OK
1025 		|| (error = _AddResolvableExpressions(archive, "conflicts",
1026 			fConflictsList)) != B_OK
1027 		|| (error = _AddResolvableExpressions(archive, "freshens",
1028 			fFreshensList)) != B_OK
1029 		|| (error = archive->AddStrings("replaces", fReplacesList)) != B_OK
1030 		|| (error = archive->AddString("checksum", fChecksum)) != B_OK
1031 		|| (error = archive->AddString("install-path", fInstallPath)) != B_OK
1032 		|| (error = archive->AddString("file-name", fFileName)) != B_OK) {
1033 		return error;
1034 	}
1035 
1036 	return B_OK;
1037 }
1038 
1039 
1040 /*static*/ BArchivable*
1041 BPackageInfo::Instantiate(BMessage* archive)
1042 {
1043 	if (validate_instantiation(archive, "BPackageInfo"))
1044 		return new(std::nothrow) BPackageInfo(archive);
1045 	return NULL;
1046 }
1047 
1048 
1049 status_t
1050 BPackageInfo::GetConfigString(BString& _string) const
1051 {
1052 	return StringBuilder()
1053 		.Write("name", fName)
1054 		.Write("version", fVersion)
1055 		.Write("summary", fSummary)
1056 		.Write("description", fDescription)
1057 		.Write("vendor", fVendor)
1058 		.Write("packager", fPackager)
1059 		.Write("architecture", kArchitectureNames[fArchitecture])
1060 		.Write("copyrights", fCopyrightList)
1061 		.Write("licenses", fLicenseList)
1062 		.Write("urls", fURLList)
1063 		.Write("source-urls", fSourceURLList)
1064 		.Write("global-writable-files", fGlobalWritableFileInfos)
1065 		.Write("user-settings-files", fUserSettingsFileInfos)
1066 		.Write("users", fUsers)
1067 		.Write("groups", fGroups)
1068 		.Write("post-install-scripts", fPostInstallScripts)
1069 		.Write("provides", fProvidesList)
1070 		.BeginRequires(fBasePackage)
1071 			.Write("requires", fRequiresList)
1072 		.EndRequires()
1073 		.Write("supplements", fSupplementsList)
1074 		.Write("conflicts", fConflictsList)
1075 		.Write("freshens", fFreshensList)
1076 		.Write("replaces", fReplacesList)
1077 		.WriteFlags("flags", fFlags)
1078 		.Write("checksum", fChecksum)
1079 		.GetString(_string);
1080 	// Note: fInstallPath and fFileName can not be specified via .PackageInfo.
1081 }
1082 
1083 
1084 BString
1085 BPackageInfo::ToString() const
1086 {
1087 	BString string;
1088 	GetConfigString(string);
1089 	return string;
1090 }
1091 
1092 
1093 /*static*/ status_t
1094 BPackageInfo::GetArchitectureByName(const BString& name,
1095 	BPackageArchitecture& _architecture)
1096 {
1097 	for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) {
1098 		if (name.ICompare(kArchitectureNames[i]) == 0) {
1099 			_architecture = (BPackageArchitecture)i;
1100 			return B_OK;
1101 		}
1102 	}
1103 	return B_NAME_NOT_FOUND;
1104 }
1105 
1106 
1107 /*static*/ status_t
1108 BPackageInfo::ParseVersionString(const BString& string, bool revisionIsOptional,
1109 	BPackageVersion& _version, ParseErrorListener* listener)
1110 {
1111 	return Parser(listener).ParseVersion(string, revisionIsOptional, _version);
1112 }
1113 
1114 
1115 /*static*/ status_t
1116 BPackageInfo::ParseResolvableExpressionString(const BString& string,
1117 	BPackageResolvableExpression& _expression, ParseErrorListener* listener)
1118 {
1119 	return Parser(listener).ParseResolvableExpression(string, _expression);
1120 }
1121 
1122 
1123 status_t
1124 BPackageInfo::_ReadFromPackageFile(const PackageFileLocation& fileLocation)
1125 {
1126 	BHPKG::BNoErrorOutput errorOutput;
1127 
1128 	// try current package file format version
1129 	{
1130 		BHPKG::BPackageReader packageReader(&errorOutput);
1131 		status_t error = fileLocation.Path() != NULL
1132 			? packageReader.Init(fileLocation.Path())
1133 			: packageReader.Init(fileLocation.FD(), false);
1134 		if (error == B_OK) {
1135 			BPackageInfoContentHandler handler(*this);
1136 			return packageReader.ParseContent(&handler);
1137 		}
1138 
1139 		if (error != B_MISMATCHED_VALUES)
1140 			return error;
1141 	}
1142 
1143 	// try package file format version 1
1144 	BHPKG::V1::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 		return error;
1150 
1151 	BHPKG::V1::BPackageInfoContentHandler handler(*this);
1152 	return packageReader.ParseContent(&handler);
1153 }
1154 
1155 
1156 /*static*/ status_t
1157 BPackageInfo::_AddVersion(BMessage* archive, const char* field,
1158 	const BPackageVersion& version)
1159 {
1160 	// Storing BPackageVersion::ToString() would be nice, but the corresponding
1161 	// constructor only works for valid versions and we might want to store
1162 	// invalid versions as well.
1163 
1164 	// major
1165 	size_t fieldLength = strlen(field);
1166 	FieldName fieldName(field, ":major");
1167 	if (!fieldName.IsValid())
1168 		return B_BAD_VALUE;
1169 
1170 	status_t error = archive->AddString(fieldName, version.Major());
1171 	if (error != B_OK)
1172 		return error;
1173 
1174 	// minor
1175 	if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
1176 		return B_BAD_VALUE;
1177 
1178 	error = archive->AddString(fieldName, version.Minor());
1179 	if (error != B_OK)
1180 		return error;
1181 
1182 	// micro
1183 	if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
1184 		return B_BAD_VALUE;
1185 
1186 	error = archive->AddString(fieldName, version.Micro());
1187 	if (error != B_OK)
1188 		return error;
1189 
1190 	// pre-release
1191 	if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
1192 		return B_BAD_VALUE;
1193 
1194 	error = archive->AddString(fieldName, version.PreRelease());
1195 	if (error != B_OK)
1196 		return error;
1197 
1198 	// revision
1199 	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
1200 		return B_BAD_VALUE;
1201 
1202 	return archive->AddUInt32(fieldName, version.Revision());
1203 }
1204 
1205 
1206 /*static*/ status_t
1207 BPackageInfo::_AddResolvables(BMessage* archive, const char* field,
1208 	const ResolvableList& resolvables)
1209 {
1210 	// construct the field names we need
1211 	FieldName nameField(field, ":name");
1212 	FieldName typeField(field, ":type");
1213 	FieldName versionField(field, ":version");
1214 	FieldName compatibleVersionField(field, ":compat");
1215 
1216 	if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
1217 		|| !compatibleVersionField.IsValid()) {
1218 		return B_BAD_VALUE;
1219 	}
1220 
1221 	// add fields
1222 	int32 count = resolvables.CountItems();
1223 	for (int32 i = 0; i < count; i++) {
1224 		const BPackageResolvable* resolvable = resolvables.ItemAt(i);
1225 		status_t error;
1226 		if ((error = archive->AddString(nameField, resolvable->Name())) != B_OK
1227 			|| (error = _AddVersion(archive, versionField,
1228 				resolvable->Version())) != B_OK
1229 			|| (error = _AddVersion(archive, compatibleVersionField,
1230 				resolvable->CompatibleVersion())) != B_OK) {
1231 			return error;
1232 		}
1233 	}
1234 
1235 	return B_OK;
1236 }
1237 
1238 
1239 /*static*/ status_t
1240 BPackageInfo::_AddResolvableExpressions(BMessage* archive, const char* field,
1241 	const ResolvableExpressionList& expressions)
1242 {
1243 	// construct the field names we need
1244 	FieldName nameField(field, ":name");
1245 	FieldName operatorField(field, ":operator");
1246 	FieldName versionField(field, ":version");
1247 
1248 	if (!nameField.IsValid() || !operatorField.IsValid()
1249 		|| !versionField.IsValid()) {
1250 		return B_BAD_VALUE;
1251 	}
1252 
1253 	// add fields
1254 	int32 count = expressions.CountItems();
1255 	for (int32 i = 0; i < count; i++) {
1256 		const BPackageResolvableExpression* expression = expressions.ItemAt(i);
1257 		status_t error;
1258 		if ((error = archive->AddString(nameField, expression->Name())) != B_OK
1259 			|| (error = archive->AddInt32(operatorField,
1260 				expression->Operator())) != B_OK
1261 			|| (error = _AddVersion(archive, versionField,
1262 				expression->Version())) != B_OK) {
1263 			return error;
1264 		}
1265 	}
1266 
1267 	return B_OK;
1268 }
1269 
1270 
1271 /*static*/ status_t
1272 BPackageInfo::_AddGlobalWritableFileInfos(BMessage* archive, const char* field,
1273 	const GlobalWritableFileInfoList& infos)
1274 {
1275 	// construct the field names we need
1276 	FieldName pathField(field, ":path");
1277 	FieldName updateTypeField(field, ":updateType");
1278 	FieldName isDirectoryField(field, ":isDirectory");
1279 
1280 	if (!pathField.IsValid() || !updateTypeField.IsValid()
1281 		|| !isDirectoryField.IsValid()) {
1282 		return B_BAD_VALUE;
1283 	}
1284 
1285 	// add fields
1286 	int32 count = infos.CountItems();
1287 	for (int32 i = 0; i < count; i++) {
1288 		const BGlobalWritableFileInfo* info = infos.ItemAt(i);
1289 		status_t error;
1290 		if ((error = archive->AddString(pathField, info->Path())) != B_OK
1291 			|| (error = archive->AddInt32(updateTypeField, info->UpdateType()))
1292 				!= B_OK
1293 			|| (error = archive->AddBool(isDirectoryField,
1294 				info->IsDirectory())) != B_OK) {
1295 			return error;
1296 		}
1297 	}
1298 
1299 	return B_OK;
1300 }
1301 
1302 
1303 /*static*/ status_t
1304 BPackageInfo::_AddUserSettingsFileInfos(BMessage* archive, const char* field,
1305 	const UserSettingsFileInfoList& infos)
1306 {
1307 	// construct the field names we need
1308 	FieldName pathField(field, ":path");
1309 	FieldName templatePathField(field, ":templatePath");
1310 	FieldName isDirectoryField(field, ":isDirectory");
1311 
1312 	if (!pathField.IsValid() || !templatePathField.IsValid()
1313 		|| !isDirectoryField.IsValid()) {
1314 		return B_BAD_VALUE;
1315 	}
1316 
1317 	// add fields
1318 	int32 count = infos.CountItems();
1319 	for (int32 i = 0; i < count; i++) {
1320 		const BUserSettingsFileInfo* info = infos.ItemAt(i);
1321 		status_t error;
1322 		if ((error = archive->AddString(pathField, info->Path())) != B_OK
1323 			|| (error = archive->AddString(templatePathField,
1324 				info->TemplatePath())) != B_OK
1325 			|| (error = archive->AddBool(isDirectoryField,
1326 				info->IsDirectory())) != B_OK) {
1327 			return error;
1328 		}
1329 	}
1330 
1331 	return B_OK;
1332 }
1333 
1334 
1335 /*static*/ status_t
1336 BPackageInfo::_AddUsers(BMessage* archive, const char* field,
1337 	const UserList& users)
1338 {
1339 	// construct the field names we need
1340 	FieldName nameField(field, ":name");
1341 	FieldName realNameField(field, ":realName");
1342 	FieldName homeField(field, ":home");
1343 	FieldName shellField(field, ":shell");
1344 	FieldName groupsField(field, ":groups");
1345 
1346 	if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
1347 		|| !shellField.IsValid() || !groupsField.IsValid())
1348 		return B_BAD_VALUE;
1349 
1350 	// add fields
1351 	int32 count = users.CountItems();
1352 	for (int32 i = 0; i < count; i++) {
1353 		const BUser* user = users.ItemAt(i);
1354 		BString groups = user->Groups().Join(" ");
1355 		if (groups.IsEmpty() && !user->Groups().IsEmpty())
1356 			return B_NO_MEMORY;
1357 
1358 		status_t error;
1359 		if ((error = archive->AddString(nameField, user->Name())) != B_OK
1360 			|| (error = archive->AddString(realNameField, user->RealName()))
1361 				!= B_OK
1362 			|| (error = archive->AddString(homeField, user->Home())) != B_OK
1363 			|| (error = archive->AddString(shellField, user->Shell())) != B_OK
1364 			|| (error = archive->AddString(groupsField, groups)) != B_OK) {
1365 			return error;
1366 		}
1367 	}
1368 
1369 	return B_OK;
1370 }
1371 
1372 
1373 /*static*/ status_t
1374 BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
1375 	BPackageVersion& _version)
1376 {
1377 	// major
1378 	size_t fieldLength = strlen(field);
1379 	FieldName fieldName(field, ":major");
1380 	if (!fieldName.IsValid())
1381 		return B_BAD_VALUE;
1382 
1383 	BString major;
1384 	status_t error = archive->FindString(fieldName, index, &major);
1385 	if (error != B_OK)
1386 		return error;
1387 
1388 	// minor
1389 	if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
1390 		return B_BAD_VALUE;
1391 
1392 	BString minor;
1393 	error = archive->FindString(fieldName, index, &minor);
1394 	if (error != B_OK)
1395 		return error;
1396 
1397 	// micro
1398 	if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
1399 		return B_BAD_VALUE;
1400 
1401 	BString micro;
1402 	error = archive->FindString(fieldName, index, &micro);
1403 	if (error != B_OK)
1404 		return error;
1405 
1406 	// pre-release
1407 	if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
1408 		return B_BAD_VALUE;
1409 
1410 	BString preRelease;
1411 	error = archive->FindString(fieldName, index, &preRelease);
1412 	if (error != B_OK)
1413 		return error;
1414 
1415 	// revision
1416 	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
1417 		return B_BAD_VALUE;
1418 
1419 	uint32 revision;
1420 	error = archive->FindUInt32(fieldName, index, &revision);
1421 	if (error != B_OK)
1422 		return error;
1423 
1424 	_version.SetTo(major, minor, micro, preRelease, revision);
1425 	return B_OK;
1426 }
1427 
1428 
1429 /*static*/ status_t
1430 BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
1431 	BStringList& _list)
1432 {
1433 	status_t error = archive->FindStrings(field, &_list);
1434 	return error == B_NAME_NOT_FOUND ? B_OK : error;
1435 		// If the field doesn't exist, that's OK.
1436 }
1437 
1438 
1439 /*static*/ status_t
1440 BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field,
1441 	ResolvableList& _resolvables)
1442 {
1443 	// construct the field names we need
1444 	FieldName nameField(field, ":name");
1445 	FieldName typeField(field, ":type");
1446 	FieldName versionField(field, ":version");
1447 	FieldName compatibleVersionField(field, ":compat");
1448 
1449 	if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
1450 		|| !compatibleVersionField.IsValid()) {
1451 		return B_BAD_VALUE;
1452 	}
1453 
1454 	// get the number of items
1455 	type_code type;
1456 	int32 count;
1457 	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1458 		// the field is missing
1459 		return B_OK;
1460 	}
1461 
1462 	// extract fields
1463 	for (int32 i = 0; i < count; i++) {
1464 		BString name;
1465 		status_t error = archive->FindString(nameField, i, &name);
1466 		if (error != B_OK)
1467 			return error;
1468 
1469 		BPackageVersion version;
1470 		error = _ExtractVersion(archive, versionField, i, version);
1471 		if (error != B_OK)
1472 			return error;
1473 
1474 		BPackageVersion compatibleVersion;
1475 		error = _ExtractVersion(archive, compatibleVersionField, i,
1476 			compatibleVersion);
1477 		if (error != B_OK)
1478 			return error;
1479 
1480 		BPackageResolvable* resolvable = new(std::nothrow) BPackageResolvable(
1481 			name, version, compatibleVersion);
1482 		if (resolvable == NULL || !_resolvables.AddItem(resolvable)) {
1483 			delete resolvable;
1484 			return B_NO_MEMORY;
1485 		}
1486 	}
1487 
1488 	return B_OK;
1489 }
1490 
1491 
1492 /*static*/ status_t
1493 BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
1494 	const char* field, ResolvableExpressionList& _expressions)
1495 {
1496 	// construct the field names we need
1497 	FieldName nameField(field, ":name");
1498 	FieldName operatorField(field, ":operator");
1499 	FieldName versionField(field, ":version");
1500 
1501 	if (!nameField.IsValid() || !operatorField.IsValid()
1502 		|| !versionField.IsValid()) {
1503 		return B_BAD_VALUE;
1504 	}
1505 
1506 	// get the number of items
1507 	type_code type;
1508 	int32 count;
1509 	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1510 		// the field is missing
1511 		return B_OK;
1512 	}
1513 
1514 	// extract fields
1515 	for (int32 i = 0; i < count; i++) {
1516 		BString name;
1517 		status_t error = archive->FindString(nameField, i, &name);
1518 		if (error != B_OK)
1519 			return error;
1520 
1521 		int32 operatorType;
1522 		error = archive->FindInt32(operatorField, i, &operatorType);
1523 		if (error != B_OK)
1524 			return error;
1525 		if (operatorType < 0
1526 			|| operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
1527 			return B_BAD_DATA;
1528 		}
1529 
1530 		BPackageVersion version;
1531 		error = _ExtractVersion(archive, versionField, i, version);
1532 		if (error != B_OK)
1533 			return error;
1534 
1535 		BPackageResolvableExpression* expression
1536 			= new(std::nothrow) BPackageResolvableExpression(name,
1537 				(BPackageResolvableOperator)operatorType, version);
1538 		if (expression == NULL || !_expressions.AddItem(expression)) {
1539 			delete expression;
1540 			return B_NO_MEMORY;
1541 		}
1542 	}
1543 
1544 	return B_OK;
1545 }
1546 
1547 
1548 /*static*/ status_t
1549 BPackageInfo::_ExtractGlobalWritableFileInfos(BMessage* archive,
1550 	const char* field, GlobalWritableFileInfoList& _infos)
1551 {
1552 	// construct the field names we need
1553 	FieldName pathField(field, ":path");
1554 	FieldName updateTypeField(field, ":updateType");
1555 	FieldName isDirectoryField(field, ":isDirectory");
1556 
1557 	if (!pathField.IsValid() || !updateTypeField.IsValid()
1558 		|| !isDirectoryField.IsValid()) {
1559 		return B_BAD_VALUE;
1560 	}
1561 
1562 	// get the number of items
1563 	type_code type;
1564 	int32 count;
1565 	if (archive->GetInfo(pathField, &type, &count) != B_OK) {
1566 		// the field is missing
1567 		return B_OK;
1568 	}
1569 
1570 	// extract fields
1571 	for (int32 i = 0; i < count; i++) {
1572 		BString path;
1573 		status_t error = archive->FindString(pathField, i, &path);
1574 		if (error != B_OK)
1575 			return error;
1576 
1577 		int32 updateType;
1578 		error = archive->FindInt32(updateTypeField, i, &updateType);
1579 		if (error != B_OK)
1580 			return error;
1581 		if (updateType < 0
1582 			|| updateType > B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT) {
1583 			return B_BAD_DATA;
1584 		}
1585 
1586 		bool isDirectory;
1587 		error = archive->FindBool(isDirectoryField, i, &isDirectory);
1588 		if (error != B_OK)
1589 			return error;
1590 
1591 		BGlobalWritableFileInfo* info
1592 			= new(std::nothrow) BGlobalWritableFileInfo(path,
1593 				(BWritableFileUpdateType)updateType, isDirectory);
1594 		if (info == NULL || !_infos.AddItem(info)) {
1595 			delete info;
1596 			return B_NO_MEMORY;
1597 		}
1598 	}
1599 
1600 	return B_OK;
1601 }
1602 
1603 
1604 /*static*/ status_t
1605 BPackageInfo::_ExtractUserSettingsFileInfos(BMessage* archive,
1606 	const char* field, UserSettingsFileInfoList& _infos)
1607 {
1608 	// construct the field names we need
1609 	FieldName pathField(field, ":path");
1610 	FieldName templatePathField(field, ":templatePath");
1611 	FieldName isDirectoryField(field, ":isDirectory");
1612 
1613 	if (!pathField.IsValid() || !templatePathField.IsValid()
1614 		|| !isDirectoryField.IsValid()) {
1615 		return B_BAD_VALUE;
1616 	}
1617 
1618 	// get the number of items
1619 	type_code type;
1620 	int32 count;
1621 	if (archive->GetInfo(pathField, &type, &count) != B_OK) {
1622 		// the field is missing
1623 		return B_OK;
1624 	}
1625 
1626 	// extract fields
1627 	for (int32 i = 0; i < count; i++) {
1628 		BString path;
1629 		status_t error = archive->FindString(pathField, i, &path);
1630 		if (error != B_OK)
1631 			return error;
1632 
1633 		BString templatePath;
1634 		error = archive->FindString(templatePathField, i, &templatePath);
1635 		if (error != B_OK)
1636 			return error;
1637 
1638 		bool isDirectory;
1639 		error = archive->FindBool(isDirectoryField, i, &isDirectory);
1640 		if (error != B_OK)
1641 			return error;
1642 
1643 		BUserSettingsFileInfo* info = isDirectory
1644 			? new(std::nothrow) BUserSettingsFileInfo(path, true)
1645 			: new(std::nothrow) BUserSettingsFileInfo(path, templatePath);
1646 		if (info == NULL || !_infos.AddItem(info)) {
1647 			delete info;
1648 			return B_NO_MEMORY;
1649 		}
1650 	}
1651 
1652 	return B_OK;
1653 }
1654 
1655 
1656 /*static*/ status_t
1657 BPackageInfo::_ExtractUsers(BMessage* archive, const char* field,
1658 	UserList& _users)
1659 {
1660 	// construct the field names we need
1661 	FieldName nameField(field, ":name");
1662 	FieldName realNameField(field, ":realName");
1663 	FieldName homeField(field, ":home");
1664 	FieldName shellField(field, ":shell");
1665 	FieldName groupsField(field, ":groups");
1666 
1667 	if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
1668 		|| !shellField.IsValid() || !groupsField.IsValid())
1669 		return B_BAD_VALUE;
1670 
1671 	// get the number of items
1672 	type_code type;
1673 	int32 count;
1674 	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1675 		// the field is missing
1676 		return B_OK;
1677 	}
1678 
1679 	// extract fields
1680 	for (int32 i = 0; i < count; i++) {
1681 		BString name;
1682 		status_t error = archive->FindString(nameField, i, &name);
1683 		if (error != B_OK)
1684 			return error;
1685 
1686 		BString realName;
1687 		error = archive->FindString(realNameField, i, &realName);
1688 		if (error != B_OK)
1689 			return error;
1690 
1691 		BString home;
1692 		error = archive->FindString(homeField, i, &home);
1693 		if (error != B_OK)
1694 			return error;
1695 
1696 		BString shell;
1697 		error = archive->FindString(shellField, i, &shell);
1698 		if (error != B_OK)
1699 			return error;
1700 
1701 		BString groupsString;
1702 		error = archive->FindString(groupsField, i, &groupsString);
1703 		if (error != B_OK)
1704 			return error;
1705 
1706 		BStringList groups;
1707 		if (!groupsString.IsEmpty() && !groupsString.Split(" ", false, groups))
1708 			return B_NO_MEMORY;
1709 
1710 		BUser* user = new(std::nothrow) BUser(name, realName, home, shell,
1711 			groups);
1712 		if (user == NULL || !_users.AddItem(user)) {
1713 			delete user;
1714 			return B_NO_MEMORY;
1715 		}
1716 	}
1717 
1718 	return B_OK;
1719 }
1720 
1721 
1722 }	// namespace BPackageKit
1723