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