* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <package/PackageInfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#include <File.h>
#include <Entry.h>
#include <Message.h>
#include <package/hpkg/NoErrorOutput.h>
#include <package/hpkg/PackageReader.h>
#include <package/hpkg/v1/PackageInfoContentHandler.h>
#include <package/hpkg/v1/PackageReader.h>
#include <package/PackageInfoContentHandler.h>
#include "PackageInfoParser.h"
#include "PackageInfoStringBuilder.h"
namespace BPackageKit {
const char* const BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
"name",
"summary",
"description",
"vendor",
"packager",
"architecture",
"version",
"copyrights",
"licenses",
"provides",
"requires",
"supplements",
"conflicts",
"freshens",
"replaces",
"flags",
"urls",
"source-urls",
"checksum",
NULL,
"base-package",
"global-writable-files",
"user-settings-files",
"users",
"groups",
"post-install-scripts",
"pre-uninstall-scripts"
};
const char* const
BPackageInfo::kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
"any",
"x86",
"x86_gcc2",
"source",
"x86_64",
"ppc",
"arm",
"m68k",
"sparc",
"arm64",
"riscv64"
};
const char* const BPackageInfo::kWritableFileUpdateTypes[
B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT] = {
"keep-old",
"manual",
"auto-merge",
};
struct BPackageInfo::FieldName {
FieldName(const char* prefix, const char* suffix)
{
size_t prefixLength = strlen(prefix);
size_t suffixLength = strlen(suffix);
if (prefixLength + suffixLength >= sizeof(fFieldName)) {
fFieldName[0] = '\0';
return;
}
memcpy(fFieldName, prefix, prefixLength);
memcpy(fFieldName + prefixLength, suffix, suffixLength);
fFieldName[prefixLength + suffixLength] = '\0';
}
bool ReplaceSuffix(size_t prefixLength, const char* suffix)
{
size_t suffixLength = strlen(suffix);
if (prefixLength + suffixLength >= sizeof(fFieldName)) {
fFieldName[0] = '\0';
return false;
}
memcpy(fFieldName + prefixLength, suffix, suffixLength);
fFieldName[prefixLength + suffixLength] = '\0';
return true;
}
bool IsValid() const
{
return fFieldName[0] != '\0';
}
operator const char*()
{
return fFieldName;
}
private:
char fFieldName[64];
};
struct BPackageInfo::PackageFileLocation {
PackageFileLocation(const char* path)
:
fPath(path),
fFD(-1)
{
}
PackageFileLocation(int fd)
:
fPath(NULL),
fFD(fd)
{
}
const char* Path() const
{
return fPath;
}
int FD() const
{
return fFD;
}
private:
const char* fPath;
int fFD;
};
BPackageInfo::BPackageInfo()
:
BArchivable(),
fFlags(0),
fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
fCopyrightList(4),
fLicenseList(4),
fURLList(4),
fSourceURLList(4),
fGlobalWritableFileInfos(4),
fUserSettingsFileInfos(4),
fUsers(4),
fGroups(4),
fPostInstallScripts(4),
fPreUninstallScripts(4),
fProvidesList(20),
fRequiresList(20),
fSupplementsList(20),
fConflictsList(4),
fFreshensList(4),
fReplacesList(4)
{
}
BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
:
BArchivable(archive),
fFlags(0),
fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
fCopyrightList(4),
fLicenseList(4),
fURLList(4),
fSourceURLList(4),
fGlobalWritableFileInfos(4),
fUserSettingsFileInfos(4),
fUsers(4),
fGroups(4),
fPostInstallScripts(4),
fPreUninstallScripts(4),
fProvidesList(20),
fRequiresList(20),
fSupplementsList(20),
fConflictsList(4),
fFreshensList(4),
fReplacesList(4)
{
status_t error;
int32 architecture;
if ((error = archive->FindString("name", &fName)) == B_OK
&& (error = archive->FindString("summary", &fSummary)) == B_OK
&& (error = archive->FindString("description", &fDescription)) == B_OK
&& (error = archive->FindString("vendor", &fVendor)) == B_OK
&& (error = archive->FindString("packager", &fPackager)) == B_OK
&& (error = archive->FindString("basePackage", &fBasePackage)) == B_OK
&& (error = archive->FindUInt32("flags", &fFlags)) == B_OK
&& (error = archive->FindInt32("architecture", &architecture)) == B_OK
&& (error = _ExtractVersion(archive, "version", 0, fVersion)) == B_OK
&& (error = _ExtractStringList(archive, "copyrights", fCopyrightList))
== B_OK
&& (error = _ExtractStringList(archive, "licenses", fLicenseList))
== B_OK
&& (error = _ExtractStringList(archive, "urls", fURLList)) == B_OK
&& (error = _ExtractStringList(archive, "source-urls", fSourceURLList))
== B_OK
&& (error = _ExtractGlobalWritableFileInfos(archive,
"global-writable-files", fGlobalWritableFileInfos)) == B_OK
&& (error = _ExtractUserSettingsFileInfos(archive, "user-settings-files",
fUserSettingsFileInfos)) == B_OK
&& (error = _ExtractUsers(archive, "users", fUsers)) == B_OK
&& (error = _ExtractStringList(archive, "groups", fGroups)) == B_OK
&& (error = _ExtractStringList(archive, "post-install-scripts",
fPostInstallScripts)) == B_OK
&& (error = _ExtractStringList(archive, "pre-uninstall-scripts",
fPreUninstallScripts)) == B_OK
&& (error = _ExtractResolvables(archive, "provides", fProvidesList))
== B_OK
&& (error = _ExtractResolvableExpressions(archive, "requires",
fRequiresList)) == B_OK
&& (error = _ExtractResolvableExpressions(archive, "supplements",
fSupplementsList)) == B_OK
&& (error = _ExtractResolvableExpressions(archive, "conflicts",
fConflictsList)) == B_OK
&& (error = _ExtractResolvableExpressions(archive, "freshens",
fFreshensList)) == B_OK
&& (error = _ExtractStringList(archive, "replaces", fReplacesList))
== B_OK
&& (error = archive->FindString("checksum", &fChecksum)) == B_OK
&& (error = archive->FindString("install-path", &fInstallPath)) == B_OK
&& (error = archive->FindString("file-name", &fFileName)) == B_OK) {
if (architecture >= 0
&& architecture <= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
fArchitecture = (BPackageArchitecture)architecture;
} else
error = B_BAD_DATA;
}
if (_error != NULL)
*_error = error;
}
BPackageInfo::~BPackageInfo()
{
}
status_t
BPackageInfo::ReadFromConfigFile(const BEntry& packageInfoEntry,
ParseErrorListener* listener)
{
status_t result = packageInfoEntry.InitCheck();
if (result != B_OK)
return result;
BFile file(&packageInfoEntry, B_READ_ONLY);
if ((result = file.InitCheck()) != B_OK)
return result;
return ReadFromConfigFile(file, listener);
}
status_t
BPackageInfo::ReadFromConfigFile(BFile& packageInfoFile,
ParseErrorListener* listener)
{
off_t size;
status_t result = packageInfoFile.GetSize(&size);
if (result != B_OK)
return result;
BString packageInfoString;
char* buffer = packageInfoString.LockBuffer(size);
if (buffer == NULL)
return B_NO_MEMORY;
if ((result = packageInfoFile.Read(buffer, size)) < size) {
packageInfoString.UnlockBuffer(0);
return result >= 0 ? B_IO_ERROR : result;
}
buffer[size] = '\0';
packageInfoString.UnlockBuffer(size);
return ReadFromConfigString(packageInfoString, listener);
}
status_t
BPackageInfo::ReadFromConfigString(const BString& packageInfoString,
ParseErrorListener* listener)
{
Clear();
Parser parser(listener);
return parser.Parse(packageInfoString, this);
}
status_t
BPackageInfo::ReadFromPackageFile(const char* path)
{
return _ReadFromPackageFile(PackageFileLocation(path));
}
status_t
BPackageInfo::ReadFromPackageFile(int fd)
{
return _ReadFromPackageFile(PackageFileLocation(fd));
}
status_t
BPackageInfo::InitCheck() const
{
if (fName.Length() == 0 || fSummary.Length() == 0
|| fDescription.Length() == 0 || fVendor.Length() == 0
|| fPackager.Length() == 0
|| fArchitecture == B_PACKAGE_ARCHITECTURE_ENUM_COUNT
|| fVersion.InitCheck() != B_OK
|| fCopyrightList.IsEmpty() || fLicenseList.IsEmpty()
|| fProvidesList.IsEmpty())
return B_NO_INIT;
int32 globalWritableFileCount = fGlobalWritableFileInfos.CountItems();
for (int32 i = 0; i < globalWritableFileCount; i++) {
const BGlobalWritableFileInfo* info
= fGlobalWritableFileInfos.ItemAt(i);
status_t error = info->InitCheck();
if (error != B_OK)
return error;
}
int32 userSettingsFileCount = fUserSettingsFileInfos.CountItems();
for (int32 i = 0; i < userSettingsFileCount; i++) {
const BUserSettingsFileInfo* info = fUserSettingsFileInfos.ItemAt(i);
status_t error = info->InitCheck();
if (error != B_OK)
return error;
}
int32 userCount = fUsers.CountItems();
for (int32 i = 0; i < userCount; i++) {
const BUser* user = fUsers.ItemAt(i);
status_t error = user->InitCheck();
if (error != B_OK)
return B_NO_INIT;
const BStringList& userGroups = user->Groups();
int32 groupCount = userGroups.CountStrings();
for (int32 k = 0; k < groupCount; k++) {
const BString& group = userGroups.StringAt(k);
if (!fGroups.HasString(group))
return B_BAD_VALUE;
}
}
int32 groupCount = fGroups.CountStrings();
for (int32 i = 0; i< groupCount; i++) {
if (!BUser::IsValidUserName(fGroups.StringAt(i)))
return B_BAD_VALUE;
}
return B_OK;
}
const BString&
BPackageInfo::Name() const
{
return fName;
}
const BString&
BPackageInfo::Summary() const
{
return fSummary;
}
const BString&
BPackageInfo::Description() const
{
return fDescription;
}
const BString&
BPackageInfo::Vendor() const
{
return fVendor;
}
const BString&
BPackageInfo::Packager() const
{
return fPackager;
}
const BString&
BPackageInfo::BasePackage() const
{
return fBasePackage;
}
const BString&
BPackageInfo::Checksum() const
{
return fChecksum;
}
const BString&
BPackageInfo::InstallPath() const
{
return fInstallPath;
}
BString
BPackageInfo::FileName() const
{
return fFileName.IsEmpty() ? CanonicalFileName() : fFileName;
}
uint32
BPackageInfo::Flags() const
{
return fFlags;
}
BPackageArchitecture
BPackageInfo::Architecture() const
{
return fArchitecture;
}
const char*
BPackageInfo::ArchitectureName() const
{
if ((int)fArchitecture < 0
|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
return NULL;
}
return kArchitectureNames[fArchitecture];
}
const BPackageVersion&
BPackageInfo::Version() const
{
return fVersion;
}
const BStringList&
BPackageInfo::CopyrightList() const
{
return fCopyrightList;
}
const BStringList&
BPackageInfo::LicenseList() const
{
return fLicenseList;
}
const BStringList&
BPackageInfo::URLList() const
{
return fURLList;
}
const BStringList&
BPackageInfo::SourceURLList() const
{
return fSourceURLList;
}
const BObjectList<BGlobalWritableFileInfo, true>&
BPackageInfo::GlobalWritableFileInfos() const
{
return fGlobalWritableFileInfos;
}
const BObjectList<BUserSettingsFileInfo, true>&
BPackageInfo::UserSettingsFileInfos() const
{
return fUserSettingsFileInfos;
}
const BObjectList<BUser, true>&
BPackageInfo::Users() const
{
return fUsers;
}
const BStringList&
BPackageInfo::Groups() const
{
return fGroups;
}
const BStringList&
BPackageInfo::PostInstallScripts() const
{
return fPostInstallScripts;
}
const BStringList&
BPackageInfo::PreUninstallScripts() const
{
return fPreUninstallScripts;
}
const BObjectList<BPackageResolvable, true>&
BPackageInfo::ProvidesList() const
{
return fProvidesList;
}
const BObjectList<BPackageResolvableExpression, true>&
BPackageInfo::RequiresList() const
{
return fRequiresList;
}
const BObjectList<BPackageResolvableExpression, true>&
BPackageInfo::SupplementsList() const
{
return fSupplementsList;
}
const BObjectList<BPackageResolvableExpression, true>&
BPackageInfo::ConflictsList() const
{
return fConflictsList;
}
const BObjectList<BPackageResolvableExpression, true>&
BPackageInfo::FreshensList() const
{
return fFreshensList;
}
const BStringList&
BPackageInfo::ReplacesList() const
{
return fReplacesList;
}
BString
BPackageInfo::CanonicalFileName() const
{
if (InitCheck() != B_OK)
return BString();
return BString().SetToFormat("%s-%s-%s.hpkg", fName.String(),
fVersion.ToString().String(), kArchitectureNames[fArchitecture]);
}
bool
BPackageInfo::Matches(const BPackageResolvableExpression& expression) const
{
if (expression.Name().StartsWith("pkg:")) {
return fName == expression.Name().String() + 4
&& expression.Matches(fVersion, fVersion);
}
int32 count = fProvidesList.CountItems();
for (int32 i = 0; i < count; i++) {
const BPackageResolvable* provides = fProvidesList.ItemAt(i);
if (expression.Matches(*provides))
return true;
}
return false;
}
void
BPackageInfo::SetName(const BString& name)
{
fName = name;
fName.ToLower();
}
void
BPackageInfo::SetSummary(const BString& summary)
{
fSummary = summary;
}
void
BPackageInfo::SetDescription(const BString& description)
{
fDescription = description;
}
void
BPackageInfo::SetVendor(const BString& vendor)
{
fVendor = vendor;
}
void
BPackageInfo::SetPackager(const BString& packager)
{
fPackager = packager;
}
void
BPackageInfo::SetBasePackage(const BString& basePackage)
{
fBasePackage = basePackage;
}
void
BPackageInfo::SetChecksum(const BString& checksum)
{
fChecksum = checksum;
}
void
BPackageInfo::SetInstallPath(const BString& installPath)
{
fInstallPath = installPath;
}
void
BPackageInfo::SetFileName(const BString& fileName)
{
fFileName = fileName;
}
void
BPackageInfo::SetVersion(const BPackageVersion& version)
{
fVersion = version;
}
void
BPackageInfo::SetFlags(uint32 flags)
{
fFlags = flags;
}
void
BPackageInfo::SetArchitecture(BPackageArchitecture architecture)
{
fArchitecture = architecture;
}
void
BPackageInfo::ClearCopyrightList()
{
fCopyrightList.MakeEmpty();
}
status_t
BPackageInfo::AddCopyright(const BString& copyright)
{
return fCopyrightList.Add(copyright) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearLicenseList()
{
fLicenseList.MakeEmpty();
}
status_t
BPackageInfo::AddLicense(const BString& license)
{
return fLicenseList.Add(license) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearURLList()
{
fURLList.MakeEmpty();
}
status_t
BPackageInfo::AddURL(const BString& url)
{
return fURLList.Add(url) ? B_OK : B_NO_MEMORY;
}
void
BPackageInfo::ClearSourceURLList()
{
fSourceURLList.MakeEmpty();
}
status_t
BPackageInfo::AddSourceURL(const BString& url)
{
return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
}
void
BPackageInfo::ClearGlobalWritableFileInfos()
{
fGlobalWritableFileInfos.MakeEmpty();
}
status_t
BPackageInfo::AddGlobalWritableFileInfo(const BGlobalWritableFileInfo& info)
{
BGlobalWritableFileInfo* newInfo
= new (std::nothrow) BGlobalWritableFileInfo(info);
if (newInfo == NULL || !fGlobalWritableFileInfos.AddItem(newInfo)) {
delete newInfo;
return B_NO_MEMORY;
}
return B_OK;
}
void
BPackageInfo::ClearUserSettingsFileInfos()
{
fUserSettingsFileInfos.MakeEmpty();
}
status_t
BPackageInfo::AddUserSettingsFileInfo(const BUserSettingsFileInfo& info)
{
BUserSettingsFileInfo* newInfo
= new (std::nothrow) BUserSettingsFileInfo(info);
if (newInfo == NULL || !fUserSettingsFileInfos.AddItem(newInfo)) {
delete newInfo;
return B_NO_MEMORY;
}
return B_OK;
}
void
BPackageInfo::ClearUsers()
{
fUsers.MakeEmpty();
}
status_t
BPackageInfo::AddUser(const BUser& user)
{
BUser* newUser = new (std::nothrow) BUser(user);
if (newUser == NULL || !fUsers.AddItem(newUser)) {
delete newUser;
return B_NO_MEMORY;
}
return B_OK;
}
void
BPackageInfo::ClearGroups()
{
fGroups.MakeEmpty();
}
status_t
BPackageInfo::AddGroup(const BString& group)
{
return fGroups.Add(group) ? B_OK : B_NO_MEMORY;
}
void
BPackageInfo::ClearPostInstallScripts()
{
fPostInstallScripts.MakeEmpty();
}
void
BPackageInfo::ClearPreUninstallScripts()
{
fPreUninstallScripts.MakeEmpty();
}
status_t
BPackageInfo::AddPostInstallScript(const BString& path)
{
return fPostInstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
}
status_t
BPackageInfo::AddPreUninstallScript(const BString& path)
{
return fPreUninstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
}
void
BPackageInfo::ClearProvidesList()
{
fProvidesList.MakeEmpty();
}
status_t
BPackageInfo::AddProvides(const BPackageResolvable& provides)
{
BPackageResolvable* newProvides
= new (std::nothrow) BPackageResolvable(provides);
if (newProvides == NULL)
return B_NO_MEMORY;
return fProvidesList.AddItem(newProvides) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearRequiresList()
{
fRequiresList.MakeEmpty();
}
status_t
BPackageInfo::AddRequires(const BPackageResolvableExpression& packageRequires)
{
BPackageResolvableExpression* newRequires
= new (std::nothrow) BPackageResolvableExpression(packageRequires);
if (newRequires == NULL)
return B_NO_MEMORY;
return fRequiresList.AddItem(newRequires) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearSupplementsList()
{
fSupplementsList.MakeEmpty();
}
status_t
BPackageInfo::AddSupplements(const BPackageResolvableExpression& supplements)
{
BPackageResolvableExpression* newSupplements
= new (std::nothrow) BPackageResolvableExpression(supplements);
if (newSupplements == NULL)
return B_NO_MEMORY;
return fSupplementsList.AddItem(newSupplements) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearConflictsList()
{
fConflictsList.MakeEmpty();
}
status_t
BPackageInfo::AddConflicts(const BPackageResolvableExpression& conflicts)
{
BPackageResolvableExpression* newConflicts
= new (std::nothrow) BPackageResolvableExpression(conflicts);
if (newConflicts == NULL)
return B_NO_MEMORY;
return fConflictsList.AddItem(newConflicts) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearFreshensList()
{
fFreshensList.MakeEmpty();
}
status_t
BPackageInfo::AddFreshens(const BPackageResolvableExpression& freshens)
{
BPackageResolvableExpression* newFreshens
= new (std::nothrow) BPackageResolvableExpression(freshens);
if (newFreshens == NULL)
return B_NO_MEMORY;
return fFreshensList.AddItem(newFreshens) ? B_OK : B_ERROR;
}
void
BPackageInfo::ClearReplacesList()
{
fReplacesList.MakeEmpty();
}
status_t
BPackageInfo::AddReplaces(const BString& replaces)
{
return fReplacesList.Add(BString(replaces).ToLower()) ? B_OK : B_ERROR;
}
void
BPackageInfo::Clear()
{
fName.Truncate(0);
fSummary.Truncate(0);
fDescription.Truncate(0);
fVendor.Truncate(0);
fPackager.Truncate(0);
fBasePackage.Truncate(0);
fChecksum.Truncate(0);
fInstallPath.Truncate(0);
fFileName.Truncate(0);
fFlags = 0;
fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT;
fVersion.Clear();
fCopyrightList.MakeEmpty();
fLicenseList.MakeEmpty();
fURLList.MakeEmpty();
fSourceURLList.MakeEmpty();
fGlobalWritableFileInfos.MakeEmpty();
fUserSettingsFileInfos.MakeEmpty();
fUsers.MakeEmpty();
fGroups.MakeEmpty();
fPostInstallScripts.MakeEmpty();
fPreUninstallScripts.MakeEmpty();
fRequiresList.MakeEmpty();
fProvidesList.MakeEmpty();
fSupplementsList.MakeEmpty();
fConflictsList.MakeEmpty();
fFreshensList.MakeEmpty();
fReplacesList.MakeEmpty();
}
status_t
BPackageInfo::Archive(BMessage* archive, bool deep) const
{
status_t error = BArchivable::Archive(archive, deep);
if (error != B_OK)
return error;
if ((error = archive->AddString("name", fName)) != B_OK
|| (error = archive->AddString("summary", fSummary)) != B_OK
|| (error = archive->AddString("description", fDescription)) != B_OK
|| (error = archive->AddString("vendor", fVendor)) != B_OK
|| (error = archive->AddString("packager", fPackager)) != B_OK
|| (error = archive->AddString("basePackage", fBasePackage)) != B_OK
|| (error = archive->AddUInt32("flags", fFlags)) != B_OK
|| (error = archive->AddInt32("architecture", fArchitecture)) != B_OK
|| (error = _AddVersion(archive, "version", fVersion)) != B_OK
|| (error = archive->AddStrings("copyrights", fCopyrightList))
!= B_OK
|| (error = archive->AddStrings("licenses", fLicenseList)) != B_OK
|| (error = archive->AddStrings("urls", fURLList)) != B_OK
|| (error = archive->AddStrings("source-urls", fSourceURLList))
!= B_OK
|| (error = _AddGlobalWritableFileInfos(archive,
"global-writable-files", fGlobalWritableFileInfos)) != B_OK
|| (error = _AddUserSettingsFileInfos(archive,
"user-settings-files", fUserSettingsFileInfos)) != B_OK
|| (error = _AddUsers(archive, "users", fUsers)) != B_OK
|| (error = archive->AddStrings("groups", fGroups)) != B_OK
|| (error = archive->AddStrings("post-install-scripts",
fPostInstallScripts)) != B_OK
|| (error = archive->AddStrings("pre-uninstall-scripts",
fPreUninstallScripts)) != B_OK
|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
|| (error = _AddResolvableExpressions(archive, "requires",
fRequiresList)) != B_OK
|| (error = _AddResolvableExpressions(archive, "supplements",
fSupplementsList)) != B_OK
|| (error = _AddResolvableExpressions(archive, "conflicts",
fConflictsList)) != B_OK
|| (error = _AddResolvableExpressions(archive, "freshens",
fFreshensList)) != B_OK
|| (error = archive->AddStrings("replaces", fReplacesList)) != B_OK
|| (error = archive->AddString("checksum", fChecksum)) != B_OK
|| (error = archive->AddString("install-path", fInstallPath)) != B_OK
|| (error = archive->AddString("file-name", fFileName)) != B_OK) {
return error;
}
return B_OK;
}
BArchivable*
BPackageInfo::Instantiate(BMessage* archive)
{
if (validate_instantiation(archive, "BPackageInfo"))
return new(std::nothrow) BPackageInfo(archive);
return NULL;
}
status_t
BPackageInfo::GetConfigString(BString& _string) const
{
return StringBuilder()
.Write("name", fName)
.Write("version", fVersion)
.Write("summary", fSummary)
.Write("description", fDescription)
.Write("vendor", fVendor)
.Write("packager", fPackager)
.Write("architecture", kArchitectureNames[fArchitecture])
.Write("copyrights", fCopyrightList)
.Write("licenses", fLicenseList)
.Write("urls", fURLList)
.Write("source-urls", fSourceURLList)
.Write("global-writable-files", fGlobalWritableFileInfos)
.Write("user-settings-files", fUserSettingsFileInfos)
.Write("users", fUsers)
.Write("groups", fGroups)
.Write("post-install-scripts", fPostInstallScripts)
.Write("pre-uninstall-scripts", fPreUninstallScripts)
.Write("provides", fProvidesList)
.BeginRequires(fBasePackage)
.Write("requires", fRequiresList)
.EndRequires()
.Write("supplements", fSupplementsList)
.Write("conflicts", fConflictsList)
.Write("freshens", fFreshensList)
.Write("replaces", fReplacesList)
.WriteFlags("flags", fFlags)
.Write("checksum", fChecksum)
.GetString(_string);
}
BString
BPackageInfo::ToString() const
{
BString string;
GetConfigString(string);
return string;
}
status_t
BPackageInfo::GetArchitectureByName(const BString& name,
BPackageArchitecture& _architecture)
{
for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) {
if (name.ICompare(kArchitectureNames[i]) == 0) {
_architecture = (BPackageArchitecture)i;
return B_OK;
}
}
return B_NAME_NOT_FOUND;
}
status_t
BPackageInfo::ParseVersionString(const BString& string, bool revisionIsOptional,
BPackageVersion& _version, ParseErrorListener* listener)
{
return Parser(listener).ParseVersion(string, revisionIsOptional, _version);
}
status_t
BPackageInfo::ParseResolvableString(const BString& string,
BPackageResolvable& _expression, ParseErrorListener* listener)
{
return Parser(listener).ParseResolvable(string, _expression);
}
status_t
BPackageInfo::ParseResolvableExpressionString(const BString& string,
BPackageResolvableExpression& _expression, ParseErrorListener* listener)
{
return Parser(listener).ParseResolvableExpression(string, _expression);
}
status_t
BPackageInfo::_ReadFromPackageFile(const PackageFileLocation& fileLocation)
{
BHPKG::BNoErrorOutput errorOutput;
{
BHPKG::BPackageReader packageReader(&errorOutput);
status_t error = fileLocation.Path() != NULL
? packageReader.Init(fileLocation.Path())
: packageReader.Init(fileLocation.FD(), false);
if (error == B_OK) {
BPackageInfoContentHandler handler(*this);
return packageReader.ParseContent(&handler);
}
if (error != B_MISMATCHED_VALUES)
return error;
}
BHPKG::V1::BPackageReader packageReader(&errorOutput);
status_t error = fileLocation.Path() != NULL
? packageReader.Init(fileLocation.Path())
: packageReader.Init(fileLocation.FD(), false);
if (error != B_OK)
return error;
BHPKG::V1::BPackageInfoContentHandler handler(*this);
return packageReader.ParseContent(&handler);
}
status_t
BPackageInfo::_AddVersion(BMessage* archive, const char* field,
const BPackageVersion& version)
{
size_t fieldLength = strlen(field);
FieldName fieldName(field, ":major");
if (!fieldName.IsValid())
return B_BAD_VALUE;
status_t error = archive->AddString(fieldName, version.Major());
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
return B_BAD_VALUE;
error = archive->AddString(fieldName, version.Minor());
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
return B_BAD_VALUE;
error = archive->AddString(fieldName, version.Micro());
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
return B_BAD_VALUE;
error = archive->AddString(fieldName, version.PreRelease());
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
return B_BAD_VALUE;
return archive->AddUInt32(fieldName, version.Revision());
}
status_t
BPackageInfo::_AddResolvables(BMessage* archive, const char* field,
const ResolvableList& resolvables)
{
FieldName nameField(field, ":name");
FieldName typeField(field, ":type");
FieldName versionField(field, ":version");
FieldName compatibleVersionField(field, ":compat");
if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
|| !compatibleVersionField.IsValid()) {
return B_BAD_VALUE;
}
int32 count = resolvables.CountItems();
for (int32 i = 0; i < count; i++) {
const BPackageResolvable* resolvable = resolvables.ItemAt(i);
status_t error;
if ((error = archive->AddString(nameField, resolvable->Name())) != B_OK
|| (error = _AddVersion(archive, versionField,
resolvable->Version())) != B_OK
|| (error = _AddVersion(archive, compatibleVersionField,
resolvable->CompatibleVersion())) != B_OK) {
return error;
}
}
return B_OK;
}
status_t
BPackageInfo::_AddResolvableExpressions(BMessage* archive, const char* field,
const ResolvableExpressionList& expressions)
{
FieldName nameField(field, ":name");
FieldName operatorField(field, ":operator");
FieldName versionField(field, ":version");
if (!nameField.IsValid() || !operatorField.IsValid()
|| !versionField.IsValid()) {
return B_BAD_VALUE;
}
int32 count = expressions.CountItems();
for (int32 i = 0; i < count; i++) {
const BPackageResolvableExpression* expression = expressions.ItemAt(i);
status_t error;
if ((error = archive->AddString(nameField, expression->Name())) != B_OK
|| (error = archive->AddInt32(operatorField,
expression->Operator())) != B_OK
|| (error = _AddVersion(archive, versionField,
expression->Version())) != B_OK) {
return error;
}
}
return B_OK;
}
status_t
BPackageInfo::_AddGlobalWritableFileInfos(BMessage* archive, const char* field,
const GlobalWritableFileInfoList& infos)
{
FieldName pathField(field, ":path");
FieldName updateTypeField(field, ":updateType");
FieldName isDirectoryField(field, ":isDirectory");
if (!pathField.IsValid() || !updateTypeField.IsValid()
|| !isDirectoryField.IsValid()) {
return B_BAD_VALUE;
}
int32 count = infos.CountItems();
for (int32 i = 0; i < count; i++) {
const BGlobalWritableFileInfo* info = infos.ItemAt(i);
status_t error;
if ((error = archive->AddString(pathField, info->Path())) != B_OK
|| (error = archive->AddInt32(updateTypeField, info->UpdateType()))
!= B_OK
|| (error = archive->AddBool(isDirectoryField,
info->IsDirectory())) != B_OK) {
return error;
}
}
return B_OK;
}
status_t
BPackageInfo::_AddUserSettingsFileInfos(BMessage* archive, const char* field,
const UserSettingsFileInfoList& infos)
{
FieldName pathField(field, ":path");
FieldName templatePathField(field, ":templatePath");
FieldName isDirectoryField(field, ":isDirectory");
if (!pathField.IsValid() || !templatePathField.IsValid()
|| !isDirectoryField.IsValid()) {
return B_BAD_VALUE;
}
int32 count = infos.CountItems();
for (int32 i = 0; i < count; i++) {
const BUserSettingsFileInfo* info = infos.ItemAt(i);
status_t error;
if ((error = archive->AddString(pathField, info->Path())) != B_OK
|| (error = archive->AddString(templatePathField,
info->TemplatePath())) != B_OK
|| (error = archive->AddBool(isDirectoryField,
info->IsDirectory())) != B_OK) {
return error;
}
}
return B_OK;
}
status_t
BPackageInfo::_AddUsers(BMessage* archive, const char* field,
const UserList& users)
{
FieldName nameField(field, ":name");
FieldName realNameField(field, ":realName");
FieldName homeField(field, ":home");
FieldName shellField(field, ":shell");
FieldName groupsField(field, ":groups");
if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
|| !shellField.IsValid() || !groupsField.IsValid())
return B_BAD_VALUE;
int32 count = users.CountItems();
for (int32 i = 0; i < count; i++) {
const BUser* user = users.ItemAt(i);
BString groups = user->Groups().Join(" ");
if (groups.IsEmpty() && !user->Groups().IsEmpty())
return B_NO_MEMORY;
status_t error;
if ((error = archive->AddString(nameField, user->Name())) != B_OK
|| (error = archive->AddString(realNameField, user->RealName()))
!= B_OK
|| (error = archive->AddString(homeField, user->Home())) != B_OK
|| (error = archive->AddString(shellField, user->Shell())) != B_OK
|| (error = archive->AddString(groupsField, groups)) != B_OK) {
return error;
}
}
return B_OK;
}
status_t
BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
BPackageVersion& _version)
{
size_t fieldLength = strlen(field);
FieldName fieldName(field, ":major");
if (!fieldName.IsValid())
return B_BAD_VALUE;
BString major;
status_t error = archive->FindString(fieldName, index, &major);
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
return B_BAD_VALUE;
BString minor;
error = archive->FindString(fieldName, index, &minor);
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
return B_BAD_VALUE;
BString micro;
error = archive->FindString(fieldName, index, µ);
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
return B_BAD_VALUE;
BString preRelease;
error = archive->FindString(fieldName, index, &preRelease);
if (error != B_OK)
return error;
if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
return B_BAD_VALUE;
uint32 revision;
error = archive->FindUInt32(fieldName, index, &revision);
if (error != B_OK)
return error;
_version.SetTo(major, minor, micro, preRelease, revision);
return B_OK;
}
status_t
BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
BStringList& _list)
{
status_t error = archive->FindStrings(field, &_list);
return error == B_NAME_NOT_FOUND ? B_OK : error;
}
status_t
BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field,
ResolvableList& _resolvables)
{
FieldName nameField(field, ":name");
FieldName typeField(field, ":type");
FieldName versionField(field, ":version");
FieldName compatibleVersionField(field, ":compat");
if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
|| !compatibleVersionField.IsValid()) {
return B_BAD_VALUE;
}
type_code type;
int32 count;
if (archive->GetInfo(nameField, &type, &count) != B_OK) {
return B_OK;
}
for (int32 i = 0; i < count; i++) {
BString name;
status_t error = archive->FindString(nameField, i, &name);
if (error != B_OK)
return error;
BPackageVersion version;
error = _ExtractVersion(archive, versionField, i, version);
if (error != B_OK)
return error;
BPackageVersion compatibleVersion;
error = _ExtractVersion(archive, compatibleVersionField, i,
compatibleVersion);
if (error != B_OK)
return error;
BPackageResolvable* resolvable = new(std::nothrow) BPackageResolvable(
name, version, compatibleVersion);
if (resolvable == NULL || !_resolvables.AddItem(resolvable)) {
delete resolvable;
return B_NO_MEMORY;
}
}
return B_OK;
}
status_t
BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
const char* field, ResolvableExpressionList& _expressions)
{
FieldName nameField(field, ":name");
FieldName operatorField(field, ":operator");
FieldName versionField(field, ":version");
if (!nameField.IsValid() || !operatorField.IsValid()
|| !versionField.IsValid()) {
return B_BAD_VALUE;
}
type_code type;
int32 count;
if (archive->GetInfo(nameField, &type, &count) != B_OK) {
return B_OK;
}
for (int32 i = 0; i < count; i++) {
BString name;
status_t error = archive->FindString(nameField, i, &name);
if (error != B_OK)
return error;
int32 operatorType;
error = archive->FindInt32(operatorField, i, &operatorType);
if (error != B_OK)
return error;
if (operatorType < 0
|| operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
return B_BAD_DATA;
}
BPackageVersion version;
error = _ExtractVersion(archive, versionField, i, version);
if (error != B_OK)
return error;
BPackageResolvableExpression* expression
= new(std::nothrow) BPackageResolvableExpression(name,
(BPackageResolvableOperator)operatorType, version);
if (expression == NULL || !_expressions.AddItem(expression)) {
delete expression;
return B_NO_MEMORY;
}
}
return B_OK;
}
status_t
BPackageInfo::_ExtractGlobalWritableFileInfos(BMessage* archive,
const char* field, GlobalWritableFileInfoList& _infos)
{
FieldName pathField(field, ":path");
FieldName updateTypeField(field, ":updateType");
FieldName isDirectoryField(field, ":isDirectory");
if (!pathField.IsValid() || !updateTypeField.IsValid()
|| !isDirectoryField.IsValid()) {
return B_BAD_VALUE;
}
type_code type;
int32 count;
if (archive->GetInfo(pathField, &type, &count) != B_OK) {
return B_OK;
}
for (int32 i = 0; i < count; i++) {
BString path;
status_t error = archive->FindString(pathField, i, &path);
if (error != B_OK)
return error;
int32 updateType;
error = archive->FindInt32(updateTypeField, i, &updateType);
if (error != B_OK)
return error;
if (updateType < 0
|| updateType > B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT) {
return B_BAD_DATA;
}
bool isDirectory;
error = archive->FindBool(isDirectoryField, i, &isDirectory);
if (error != B_OK)
return error;
BGlobalWritableFileInfo* info
= new(std::nothrow) BGlobalWritableFileInfo(path,
(BWritableFileUpdateType)updateType, isDirectory);
if (info == NULL || !_infos.AddItem(info)) {
delete info;
return B_NO_MEMORY;
}
}
return B_OK;
}
status_t
BPackageInfo::_ExtractUserSettingsFileInfos(BMessage* archive,
const char* field, UserSettingsFileInfoList& _infos)
{
FieldName pathField(field, ":path");
FieldName templatePathField(field, ":templatePath");
FieldName isDirectoryField(field, ":isDirectory");
if (!pathField.IsValid() || !templatePathField.IsValid()
|| !isDirectoryField.IsValid()) {
return B_BAD_VALUE;
}
type_code type;
int32 count;
if (archive->GetInfo(pathField, &type, &count) != B_OK) {
return B_OK;
}
for (int32 i = 0; i < count; i++) {
BString path;
status_t error = archive->FindString(pathField, i, &path);
if (error != B_OK)
return error;
BString templatePath;
error = archive->FindString(templatePathField, i, &templatePath);
if (error != B_OK)
return error;
bool isDirectory;
error = archive->FindBool(isDirectoryField, i, &isDirectory);
if (error != B_OK)
return error;
BUserSettingsFileInfo* info = isDirectory
? new(std::nothrow) BUserSettingsFileInfo(path, true)
: new(std::nothrow) BUserSettingsFileInfo(path, templatePath);
if (info == NULL || !_infos.AddItem(info)) {
delete info;
return B_NO_MEMORY;
}
}
return B_OK;
}
status_t
BPackageInfo::_ExtractUsers(BMessage* archive, const char* field,
UserList& _users)
{
FieldName nameField(field, ":name");
FieldName realNameField(field, ":realName");
FieldName homeField(field, ":home");
FieldName shellField(field, ":shell");
FieldName groupsField(field, ":groups");
if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
|| !shellField.IsValid() || !groupsField.IsValid())
return B_BAD_VALUE;
type_code type;
int32 count;
if (archive->GetInfo(nameField, &type, &count) != B_OK) {
return B_OK;
}
for (int32 i = 0; i < count; i++) {
BString name;
status_t error = archive->FindString(nameField, i, &name);
if (error != B_OK)
return error;
BString realName;
error = archive->FindString(realNameField, i, &realName);
if (error != B_OK)
return error;
BString home;
error = archive->FindString(homeField, i, &home);
if (error != B_OK)
return error;
BString shell;
error = archive->FindString(shellField, i, &shell);
if (error != B_OK)
return error;
BString groupsString;
error = archive->FindString(groupsField, i, &groupsString);
if (error != B_OK)
return error;
BStringList groups;
if (!groupsString.IsEmpty() && !groupsString.Split(" ", false, groups))
return B_NO_MEMORY;
BUser* user = new(std::nothrow) BUser(name, realName, home, shell,
groups);
if (user == NULL || !_users.AddItem(user)) {
delete user;
return B_NO_MEMORY;
}
}
return B_OK;
}
}