From 8a4ebe2c469333d0cabc9a9a6d353d4b42f61d6c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 14 Apr 2013 14:09:11 +0200 Subject: [PATCH] Make BPackageInfo archivable --- headers/os/package/PackageInfo.h | 55 +++- src/kits/package/PackageInfo.cpp | 487 ++++++++++++++++++++++++++++++- 2 files changed, 531 insertions(+), 11 deletions(-) diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h index 4d9e3f5d98..1a34a388f5 100644 --- a/headers/os/package/PackageInfo.h +++ b/headers/os/package/PackageInfo.h @@ -6,6 +6,7 @@ #define _PACKAGE__PACKAGE_INFO_H_ +#include #include #include #include @@ -31,7 +32,7 @@ namespace BPackageKit { * these elements have been parsed from a ".PackageInfo" file. * Alternatively, they can be read from an existing package file. */ -class BPackageInfo { +class BPackageInfo : public BArchivable { public: struct ParseErrorListener { virtual ~ParseErrorListener(); @@ -40,7 +41,9 @@ public: public: BPackageInfo(); - ~BPackageInfo(); + BPackageInfo(BMessage* archive, + status_t* _error = NULL); + virtual ~BPackageInfo(); status_t ReadFromConfigFile( const BEntry& packageInfoEntry, @@ -137,6 +140,10 @@ public: void Clear(); + virtual status_t Archive(BMessage* archive, + bool deep = true) const; + static BArchivable* Instantiate(BMessage* archive); + status_t GetConfigString(BString& _string) const; BString ToString() const; @@ -157,6 +164,36 @@ private: class Parser; friend class Parser; struct StringBuilder; + struct FieldName; + + typedef BObjectList ResolvableList; + typedef BObjectList + ResolvableExpressionList; + +private: + static status_t _AddVersion(BMessage* archive, + const char* field, + const BPackageVersion& version); + static status_t _AddStringList(BMessage* archive, + const char* field, const BStringList& list); + static status_t _AddResolvables(BMessage* archive, + const char* field, + const ResolvableList& resolvables); + static status_t _AddResolvableExpressions(BMessage* archive, + const char* field, + const ResolvableExpressionList& + expressions); + static status_t _ExtractVersion(BMessage* archive, + const char* field, int32 index, + BPackageVersion& _version); + static status_t _ExtractStringList(BMessage* archive, + const char* field, BStringList& _list); + static status_t _ExtractResolvables(BMessage* archive, + const char* field, + ResolvableList& _resolvables); + static status_t _ExtractResolvableExpressions(BMessage* archive, + const char* field, + ResolvableExpressionList& _expressions); private: BString fName; @@ -167,7 +204,7 @@ private: uint32 fFlags; - BPackageArchitecture fArchitecture; + BPackageArchitecture fArchitecture; BPackageVersion fVersion; @@ -176,14 +213,12 @@ private: BStringList fURLList; BStringList fSourceURLList; - BObjectList fProvidesList; + ResolvableList fProvidesList; - BObjectList fRequiresList; - BObjectList fSupplementsList; - - BObjectList fConflictsList; - - BObjectList fFreshensList; + ResolvableExpressionList fRequiresList; + ResolvableExpressionList fSupplementsList; + ResolvableExpressionList fConflictsList; + ResolvableExpressionList fFreshensList; BStringList fReplacesList; diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp index 4a1ae56026..6ff7cf9f79 100644 --- a/src/kits/package/PackageInfo.cpp +++ b/src/kits/package/PackageInfo.cpp @@ -1098,12 +1098,58 @@ private: }; -// #pragma mark - BPackageInfo +// #pragma mark - FieldName +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]; +}; + + +// #pragma mark - BPackageInfo + BPackageInfo::BPackageInfo() : + BArchivable(), fFlags(0), fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT), fCopyrightList(5), @@ -1120,6 +1166,65 @@ BPackageInfo::BPackageInfo() } +BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error) + : + BArchivable(archive), + fFlags(0), + fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT), + fCopyrightList(5), + fLicenseList(5), + fURLList(5), + fSourceURLList(5), + fProvidesList(20, true), + fRequiresList(20, true), + fSupplementsList(20, true), + fConflictsList(5, true), + fFreshensList(5, true), + fReplacesList(5) +{ + 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->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 = _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) { + if (architecture >= 0 + || architecture <= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) { + fArchitecture = (BPackageArchitecture)architecture; + } else + error = B_BAD_DATA; + } + + if (_error != NULL) + *_error = error; +} + + BPackageInfo::~BPackageInfo() { } @@ -1624,6 +1729,55 @@ BPackageInfo::Clear() } +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->AddUInt32("flags", fFlags)) != B_OK + || (error = archive->AddInt32("architecture", fArchitecture)) != B_OK + || (error = _AddVersion(archive, "version", fVersion)) != B_OK + || (error = _AddStringList(archive, "copyrights", fCopyrightList)) + != B_OK + || (error = _AddStringList(archive, "licenses", fLicenseList)) != B_OK + || (error = _AddStringList(archive, "urls", fURLList)) != B_OK + || (error = _AddStringList(archive, "source-urls", fSourceURLList)) + != 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 = _AddStringList(archive, "replaces", fReplacesList)) != B_OK + || (error = archive->AddString("checksum", fChecksum)) != B_OK + || (error = archive->AddString("install-path", fInstallPath)) != B_OK) { + return error; + } + + return B_OK; +} + + +/*static*/ 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 { @@ -1683,4 +1837,335 @@ BPackageInfo::ParseVersionString(const BString& string, bool releaseIsOptional, } +/*static*/ status_t +BPackageInfo::_AddVersion(BMessage* archive, const char* field, + const BPackageVersion& version) +{ + // Storing BPackageVersion::ToString() would be nice, but the corresponding + // constructor only works for valid versions and we might want to store + // invalid versions as well. + + // major + 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; + + // minor + if (!fieldName.ReplaceSuffix(fieldLength, ":minor")) + return B_BAD_VALUE; + + error = archive->AddString(fieldName, version.Minor()); + if (error != B_OK) + return error; + + // micro + if (!fieldName.ReplaceSuffix(fieldLength, ":micro")) + return B_BAD_VALUE; + + error = archive->AddString(fieldName, version.Micro()); + if (error != B_OK) + return error; + + // pre-release + if (!fieldName.ReplaceSuffix(fieldLength, ":pre")) + return B_BAD_VALUE; + + error = archive->AddString(fieldName, version.PreRelease()); + if (error != B_OK) + return error; + + // revision + if (!fieldName.ReplaceSuffix(fieldLength, ":revision")) + return B_BAD_VALUE; + + return archive->AddUInt8(fieldName, version.Release()); +} + + +/*static*/ status_t +BPackageInfo::_AddStringList(BMessage* archive, const char* field, + const BStringList& list) +{ + int32 count = list.CountStrings(); + for (int32 i = 0; i < count; i++) { + status_t error = archive->AddString(field, list.StringAt(i)); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +/*static*/ status_t +BPackageInfo::_AddResolvables(BMessage* archive, const char* field, + const ResolvableList& resolvables) +{ + // construct the field names we need + 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; + } + + // add fields + 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 = archive->AddInt32(typeField, resolvable->Type())) + != B_OK + || (error = _AddVersion(archive, versionField, + resolvable->Version())) != B_OK + || (error = _AddVersion(archive, compatibleVersionField, + resolvable->CompatibleVersion())) != B_OK) { + return error; + } + } + + return B_OK; +} + + +/*static*/ status_t +BPackageInfo::_AddResolvableExpressions(BMessage* archive, const char* field, + const ResolvableExpressionList& expressions) +{ + // construct the field names we need + FieldName nameField(field, ":name"); + FieldName operatorField(field, ":operator"); + FieldName versionField(field, ":version"); + + if (!nameField.IsValid() || !operatorField.IsValid() + || !versionField.IsValid()) { + return B_BAD_VALUE; + } + + // add fields + 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; +} + + +/*static*/ status_t +BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index, + BPackageVersion& _version) +{ + // major + 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; + + // minor + if (!fieldName.ReplaceSuffix(fieldLength, ":minor")) + return B_BAD_VALUE; + + BString minor; + error = archive->FindString(fieldName, index, &minor); + if (error != B_OK) + return error; + + // micro + if (!fieldName.ReplaceSuffix(fieldLength, ":micro")) + return B_BAD_VALUE; + + BString micro; + error = archive->FindString(fieldName, index, µ); + if (error != B_OK) + return error; + + // pre-release + if (!fieldName.ReplaceSuffix(fieldLength, ":pre")) + return B_BAD_VALUE; + + BString preRelease; + error = archive->FindString(fieldName, index, &preRelease); + if (error != B_OK) + return error; + + // revision + if (!fieldName.ReplaceSuffix(fieldLength, ":revision")) + return B_BAD_VALUE; + + uint8 revision; + error = archive->FindUInt8(fieldName, index, &revision); + if (error != B_OK) + return error; + + _version.SetTo(major, minor, micro, preRelease, revision); + return B_OK; +} + + +/*static*/ status_t +BPackageInfo::_ExtractStringList(BMessage* archive, const char* field, + BStringList& _list) +{ + // get the number of items + type_code type; + int32 count; + if (archive->GetInfo(field, &type, &count)) { + // the field is missing + return B_OK; + } + if (type != B_STRING_TYPE) + return B_BAD_DATA; + + for (int32 i = 0; i < count; i++) { + BString string; + status_t error = archive->FindString(field, i, &string); + if (error != B_OK) + return error; + if (!_list.Add(string)) + return B_NO_MEMORY; + } + + return B_OK; +} + + +/*static*/ status_t +BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field, + ResolvableList& _resolvables) +{ + // construct the field names we need + 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; + } + + // get the number of items + type_code type; + int32 count; + if (archive->GetInfo(nameField, &type, &count)) { + // the field is missing + return B_OK; + } + + // extract fields + for (int32 i = 0; i < count; i++) { + BString name; + status_t error = archive->FindString(nameField, i, &name); + if (error != B_OK) + return error; + + int32 type; + error = archive->FindInt32(typeField, i, &type); + if (error != B_OK) + return error; + if (type < 0 || type > B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT) + return B_BAD_DATA; + + 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, (BPackageResolvableType)type, version, compatibleVersion); + if (resolvable == NULL || !_resolvables.AddItem(resolvable)) { + delete resolvable; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +/*static*/ status_t +BPackageInfo::_ExtractResolvableExpressions(BMessage* archive, + const char* field, ResolvableExpressionList& _expressions) +{ + // construct the field names we need + FieldName nameField(field, ":name"); + FieldName operatorField(field, ":operator"); + FieldName versionField(field, ":version"); + + if (!nameField.IsValid() || !operatorField.IsValid() + || !versionField.IsValid()) { + return B_BAD_VALUE; + } + + // get the number of items + type_code type; + int32 count; + if (archive->GetInfo(nameField, &type, &count)) { + // the field is missing + return B_OK; + } + + // extract fields + 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; +} + + } // namespace BPackageKit