From ad6a8dbe2bffcac6a1df7a59ee6119f240a8edee Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Mon, 14 Feb 2011 13:09:09 +0000 Subject: [PATCH] Pulled reusable stuff from PackageReaderImpl into new class ReaderImplBase. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40485 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../private/package/hpkg/PackageReaderImpl.h | 115 +- headers/private/package/hpkg/ReaderImplBase.h | 324 +++++ .../kernel/file_systems/packagefs/Jamfile | 1 + src/kits/package/Jamfile | 1 + src/kits/package/hpkg/PackageReaderImpl.cpp | 1042 ++--------------- src/kits/package/hpkg/ReaderImplBase.cpp | 1001 ++++++++++++++++ 6 files changed, 1408 insertions(+), 1076 deletions(-) create mode 100644 headers/private/package/hpkg/ReaderImplBase.h create mode 100644 src/kits/package/hpkg/ReaderImplBase.cpp diff --git a/headers/private/package/hpkg/PackageReaderImpl.h b/headers/private/package/hpkg/PackageReaderImpl.h index 02a8d8b509..c4522a49e8 100644 --- a/headers/private/package/hpkg/PackageReaderImpl.h +++ b/headers/private/package/hpkg/PackageReaderImpl.h @@ -7,14 +7,7 @@ #define _PACKAGE__HPKG__PRIVATE__PACKAGE_READER_IMPL_H_ -#include - -#include - -#include -#include -#include -#include +#include namespace BPackageKit { @@ -24,13 +17,13 @@ namespace BHPKG { class BPackageEntry; class BPackageEntryAttribute; -class BErrorOutput; namespace BPrivate { -class PackageReaderImpl { +class PackageReaderImpl : public ReaderImplBase { + typedef ReaderImplBase inherited; public: PackageReaderImpl( BErrorOutput* errorOutput); @@ -43,120 +36,38 @@ public: status_t ParseContent(BLowLevelPackageContentHandler* contentHandler); - int PackageFileFD() { return fFD; } + int PackageFileFD() const; + +protected: + // from ReaderImplBase + virtual status_t ReadAttributeValue(uint8 type, uint8 encoding, + AttributeValue& _value); private: - struct AttributeHandlerContext; - struct AttributeHandler; - struct IgnoreAttributeHandler; struct DataAttributeHandler; struct AttributeAttributeHandler; struct EntryAttributeHandler; - struct PackageAttributeHandler; - struct PackageVersionAttributeHandler; - struct PackageResolvableAttributeHandler; - struct PackageResolvableExpressionAttributeHandler; struct RootAttributeHandler; - struct LowLevelAttributeHandler; - struct PackageContentListHandler; - - struct SectionInfo { - uint32 compression; - uint32 compressedLength; - uint32 uncompressedLength; - uint8* data; - uint64 offset; - uint64 currentOffset; - uint64 stringsLength; - uint64 stringsCount; - char** strings; - const char* name; - - SectionInfo(const char* _name) - : - data(NULL), - strings(NULL), - name(_name) - { - } - - ~SectionInfo() - { - delete[] strings; - delete[] data; - } - }; - - typedef BPackageAttributeValue AttributeValue; - typedef SinglyLinkedList AttributeHandlerList; private: - status_t _Init(const char* fileName); - - const char* _CheckCompression( - const SectionInfo& section) const; - - status_t _ParseStrings(); - - status_t _ParseContent(AttributeHandlerContext* context, + status_t _ParseTOC(AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler); - status_t _ParseAttributeTree( - AttributeHandlerContext* context); - - status_t _ReadAttribute(uint8& _id, - AttributeValue& _value, - bool* _hasChildren = NULL, - uint64* _tag = NULL); - - status_t _ReadAttributeValue(uint8 type, uint8 encoding, - AttributeValue& _value); - - status_t _ReadUnsignedLEB128(uint64& _value); - status_t _ReadString(const char*& _string, - size_t* _stringLength = NULL); - - template - inline status_t _Read(Type& _value); status_t _GetTOCBuffer(size_t size, const void*& _buffer); - status_t _ReadSectionBuffer(void* buffer, size_t size); - - status_t _ReadBuffer(off_t offset, void* buffer, - size_t size); - status_t _ReadCompressedBuffer( - const SectionInfo& section); - - inline AttributeHandler* _CurrentAttributeHandler() const; - inline void _PushAttributeHandler( - AttributeHandler* handler); - inline AttributeHandler* _PopAttributeHandler(); - private: - BErrorOutput* fErrorOutput; - int fFD; - bool fOwnsFD; - uint64 fTotalSize; uint64 fHeapOffset; uint64 fHeapSize; SectionInfo fTOCSection; - SectionInfo fPackageAttributesSection; - SectionInfo* fCurrentSection; - - AttributeHandlerList* fAttributeHandlerStack; - - uint8* fScratchBuffer; - size_t fScratchBufferSize; }; -template -status_t -PackageReaderImpl::_Read(Type& _value) +inline int +PackageReaderImpl::PackageFileFD() const { - return _ReadSectionBuffer(&_value, sizeof(Type)); + return FD(); } diff --git a/headers/private/package/hpkg/ReaderImplBase.h b/headers/private/package/hpkg/ReaderImplBase.h new file mode 100644 index 0000000000..5ddc5aa73d --- /dev/null +++ b/headers/private/package/hpkg/ReaderImplBase.h @@ -0,0 +1,324 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_ +#define _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_ + + +#include + +#include + +#include +#include +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +class BErrorOutput; + + +namespace BPrivate { + + +class ReaderImplBase { +protected: + ReaderImplBase( + BErrorOutput* errorOutput); + virtual ~ReaderImplBase(); + + virtual status_t Init(int fd, bool keepFD); + + int FD() const; + + BErrorOutput* ErrorOutput() const; + +protected: + struct AttributeHandlerContext { + BErrorOutput* errorOutput; + union { + BPackageContentHandler* packageContentHandler; + BLowLevelPackageContentHandler* lowLevelHandler; + }; + bool hasLowLevelHandler; + + uint64 heapOffset; + uint64 heapSize; + + AttributeHandlerContext(BErrorOutput* errorOutput, + BPackageContentHandler* packageContentHandler); + + AttributeHandlerContext(BErrorOutput* errorOutput, + BLowLevelPackageContentHandler* lowLevelHandler); + + void ErrorOccurred(); + }; + + + typedef BPackageAttributeValue AttributeValue; + + struct AttributeHandler + : SinglyLinkedListLinkImpl { + virtual ~AttributeHandler(); + + void SetLevel(int level); + virtual status_t HandleAttribute( + AttributeHandlerContext* context, uint8 id, + const AttributeValue& value, AttributeHandler** _handler); + + virtual status_t Delete(AttributeHandlerContext* context); + + protected: + int fLevel; + }; + + + struct IgnoreAttributeHandler : AttributeHandler { + }; + + + struct PackageVersionAttributeHandler : AttributeHandler { + PackageVersionAttributeHandler( + BPackageInfoAttributeValue& packageInfoValue, + BPackageVersionData& versionData, bool notify); + + virtual status_t HandleAttribute( + AttributeHandlerContext* context, uint8 id, + const AttributeValue& value, AttributeHandler** _handler); + + virtual status_t Delete(AttributeHandlerContext* context); + + private: + BPackageInfoAttributeValue& fPackageInfoValue; + BPackageVersionData& fPackageVersionData; + bool fNotify; + }; + + + struct PackageResolvableAttributeHandler : AttributeHandler { + PackageResolvableAttributeHandler( + BPackageInfoAttributeValue& packageInfoValue); + + virtual status_t HandleAttribute( + AttributeHandlerContext* context, uint8 id, + const AttributeValue& value, AttributeHandler** _handler); + + virtual status_t Delete(AttributeHandlerContext* context); + + private: + BPackageInfoAttributeValue& fPackageInfoValue; + }; + + + struct PackageResolvableExpressionAttributeHandler + : AttributeHandler { + PackageResolvableExpressionAttributeHandler( + BPackageInfoAttributeValue& packageInfoValue); + + virtual status_t HandleAttribute( + AttributeHandlerContext* context, uint8 id, + const AttributeValue& value, AttributeHandler** _handler); + + virtual status_t Delete(AttributeHandlerContext* context); + + private: + BPackageInfoAttributeValue& fPackageInfoValue; + }; + + + struct PackageAttributeHandler : AttributeHandler { + virtual status_t HandleAttribute( + AttributeHandlerContext* context, uint8 id, + const AttributeValue& value, AttributeHandler** _handler); + + private: + BPackageInfoAttributeValue fPackageInfoValue; + }; + + + struct LowLevelAttributeHandler : AttributeHandler { + LowLevelAttributeHandler(); + LowLevelAttributeHandler(uint8 id, + const BPackageAttributeValue& value, void* token); + + virtual status_t HandleAttribute( + AttributeHandlerContext* context, uint8 id, + const AttributeValue& value, AttributeHandler** _handler); + virtual status_t Delete(AttributeHandlerContext* context); + + private: + void* fToken; + uint8 fID; + AttributeValue fValue; + }; + + + struct SectionInfo { + uint32 compression; + uint32 compressedLength; + uint32 uncompressedLength; + uint8* data; + uint64 offset; + uint64 currentOffset; + uint64 stringsLength; + uint64 stringsCount; + char** strings; + const char* name; + + SectionInfo(const char* _name) + : + data(NULL), + strings(NULL), + name(_name) + { + } + + ~SectionInfo() + { + delete[] strings; + delete[] data; + } + }; + + typedef SinglyLinkedList AttributeHandlerList; + +protected: + const char* CheckCompression( + const SectionInfo& section) const; + + status_t ParseStrings(); + + status_t ParsePackageAttributesSection( + AttributeHandlerContext* context, + AttributeHandler* rootAttributeHandler); + status_t ParseAttributeTree( + AttributeHandlerContext* context); + + virtual status_t ReadAttributeValue(uint8 type, uint8 encoding, + AttributeValue& _value); + + status_t ReadUnsignedLEB128(uint64& _value); + + status_t ReadBuffer(off_t offset, void* buffer, + size_t size); + status_t ReadCompressedBuffer( + const SectionInfo& section); + + inline AttributeHandler* CurrentAttributeHandler() const; + inline void PushAttributeHandler( + AttributeHandler* handler); + inline AttributeHandler* PopAttributeHandler(); + inline void ClearAttributeHandlerStack(); + + inline SectionInfo* CurrentSection(); + inline void SetCurrentSection(SectionInfo* section); + +protected: + SectionInfo fPackageAttributesSection; + +private: + template + inline status_t _Read(Type& _value); + + status_t _ReadSectionBuffer(void* buffer, size_t size); + + status_t _ReadAttribute(uint8& _id, + AttributeValue& _value, + bool* _hasChildren = NULL, + uint64* _tag = NULL); + + status_t _ReadString(const char*& _string, + size_t* _stringLength = NULL); + +private: + BErrorOutput* fErrorOutput; + int fFD; + bool fOwnsFD; + + SectionInfo* fCurrentSection; + + AttributeHandlerList fAttributeHandlerStack; + + uint8* fScratchBuffer; + size_t fScratchBufferSize; +}; + + +inline int +ReaderImplBase::FD() const +{ + return fFD; +} + + +inline BErrorOutput* +ReaderImplBase::ErrorOutput() const +{ + return fErrorOutput; +} + + +ReaderImplBase::SectionInfo* +ReaderImplBase::CurrentSection() +{ + return fCurrentSection; +} + + +void +ReaderImplBase::SetCurrentSection(SectionInfo* section) +{ + fCurrentSection = section; +} + + +template +status_t +ReaderImplBase::_Read(Type& _value) +{ + return _ReadSectionBuffer(&_value, sizeof(Type)); +} + + +inline ReaderImplBase::AttributeHandler* +ReaderImplBase::CurrentAttributeHandler() const +{ + return fAttributeHandlerStack.Head(); +} + + +inline void +ReaderImplBase::PushAttributeHandler(AttributeHandler* handler) +{ + fAttributeHandlerStack.Add(handler); +} + + +inline ReaderImplBase::AttributeHandler* +ReaderImplBase::PopAttributeHandler() +{ + return fAttributeHandlerStack.RemoveHead(); +} + + +inline void +ReaderImplBase::ClearAttributeHandlerStack() +{ + fAttributeHandlerStack.MakeEmpty(); +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_ diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 77345e8e09..48a331eab6 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -41,6 +41,7 @@ HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES = PackageEntry.cpp PackageEntryAttribute.cpp PackageReaderImpl.cpp + ReaderImplBase.cpp # compression ZlibCompressionBase.cpp diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index f480a20ac0..98d95692a1 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -25,6 +25,7 @@ HPKG_SOURCES = PackageReaderImpl.cpp PackageWriter.cpp PackageWriterImpl.cpp + ReaderImplBase.cpp RepositoryWriter.cpp RepositoryWriterImpl.cpp Strings.cpp diff --git a/src/kits/package/hpkg/PackageReaderImpl.cpp b/src/kits/package/hpkg/PackageReaderImpl.cpp index 3c43b21a62..fb518ea786 100644 --- a/src/kits/package/hpkg/PackageReaderImpl.cpp +++ b/src/kits/package/hpkg/PackageReaderImpl.cpp @@ -47,83 +47,8 @@ static const size_t kMaxTOCSize = 64 * 1024 * 1024; // maximum package attributes size we support reading static const size_t kMaxPackageAttributesSize = 1 * 1024 * 1024; -static const size_t kScratchBufferSize = 64 * 1024; - -// #pragma mark - AttributeHandler - - -struct PackageReaderImpl::AttributeHandlerContext { - BErrorOutput* errorOutput; - union { - BPackageContentHandler* packageContentHandler; - BLowLevelPackageContentHandler* lowLevelPackageContentHandler; - }; - bool hasLowLevelHandler; - - uint64 heapOffset; - uint64 heapSize; - - - AttributeHandlerContext(BErrorOutput* errorOutput, - BPackageContentHandler* packageContentHandler) - : - errorOutput(errorOutput), - packageContentHandler(packageContentHandler), - hasLowLevelHandler(false) - { - } - - AttributeHandlerContext(BErrorOutput* errorOutput, - BLowLevelPackageContentHandler* lowLevelPackageContentHandler) - : - errorOutput(errorOutput), - lowLevelPackageContentHandler(lowLevelPackageContentHandler), - hasLowLevelHandler(true) - { - } - - void ErrorOccurred() - { - if (hasLowLevelHandler) - lowLevelPackageContentHandler->HandleErrorOccurred(); - else - packageContentHandler->HandleErrorOccurred(); - } -}; - - -struct PackageReaderImpl::AttributeHandler - : SinglyLinkedListLinkImpl { - - virtual ~AttributeHandler() - { - } - - void SetLevel(int level) - { - fLevel = level; - } - - virtual status_t HandleAttribute(AttributeHandlerContext* context, - uint8 id, const AttributeValue& value, AttributeHandler** _handler) - { - return B_OK; - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - delete this; - return B_OK; - } - -protected: - int fLevel; -}; - - -struct PackageReaderImpl::IgnoreAttributeHandler : AttributeHandler { -}; +// #pragma mark - DataAttributeHandler struct PackageReaderImpl::DataAttributeHandler : AttributeHandler { @@ -199,6 +124,9 @@ private: }; +// #pragma mark - AttributeAttributeHandler + + struct PackageReaderImpl::AttributeAttributeHandler : AttributeHandler { AttributeAttributeHandler(BPackageEntry* entry, const char* name) : @@ -242,6 +170,9 @@ private: }; +// #pragma mark - EntryAttributeHandler + + struct PackageReaderImpl::EntryAttributeHandler : AttributeHandler { EntryAttributeHandler(AttributeHandlerContext* context, BPackageEntry* parentEntry, const char* name) @@ -420,322 +351,7 @@ private: }; -struct PackageReaderImpl::PackageVersionAttributeHandler : AttributeHandler { - PackageVersionAttributeHandler(BPackageInfoAttributeValue& packageInfoValue, - BPackageVersionData& versionData, bool notify) - : - fPackageInfoValue(packageInfoValue), - fPackageVersionData(versionData), - fNotify(notify) - { - } - - virtual status_t HandleAttribute(AttributeHandlerContext* context, - uint8 id, const AttributeValue& value, AttributeHandler** _handler) - { - switch (id) { - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR: - fPackageVersionData.minor = value.string; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO: - fPackageVersionData.micro = value.string; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE: - fPackageVersionData.release = value.unsignedInt; - break; - - default: - context->errorOutput->PrintError("Error: Invalid package " - "attribute section: unexpected package attribute id %d " - "encountered when parsing package version\n", id); - return B_BAD_DATA; - } - - return B_OK; - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - status_t error = B_OK; - if (fNotify) { - fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION; - error = context->packageContentHandler->HandlePackageAttribute( - fPackageInfoValue); - fPackageInfoValue.Clear(); - } - - delete this; - return error; - } - -private: - BPackageInfoAttributeValue& fPackageInfoValue; - BPackageVersionData& fPackageVersionData; - bool fNotify; -}; - - -struct PackageReaderImpl::PackageResolvableAttributeHandler : AttributeHandler { - PackageResolvableAttributeHandler( - BPackageInfoAttributeValue& packageInfoValue) - : - fPackageInfoValue(packageInfoValue) - { - } - - virtual status_t HandleAttribute(AttributeHandlerContext* context, - uint8 id, const AttributeValue& value, AttributeHandler** _handler) - { - switch (id) { - case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_TYPE: - fPackageInfoValue.resolvable.type - = (BPackageResolvableType)value.unsignedInt; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR: - fPackageInfoValue.resolvable.haveVersion = true; - fPackageInfoValue.resolvable.version.major = value.string; - if (_handler != NULL) { - *_handler - = new(std::nothrow) PackageVersionAttributeHandler( - fPackageInfoValue, - fPackageInfoValue.resolvable.version, false); - if (*_handler == NULL) - return B_NO_MEMORY; - } - break; - - default: - context->errorOutput->PrintError("Error: Invalid package " - "attribute section: unexpected package attribute id %d " - "encountered when parsing package resolvable\n", id); - return B_BAD_DATA; - } - - return B_OK; - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - status_t error = context->packageContentHandler->HandlePackageAttribute( - fPackageInfoValue); - fPackageInfoValue.Clear(); - - delete this; - return error; - } - -private: - BPackageInfoAttributeValue& fPackageInfoValue; -}; - - -struct PackageReaderImpl::PackageResolvableExpressionAttributeHandler - : AttributeHandler { - PackageResolvableExpressionAttributeHandler( - BPackageInfoAttributeValue& packageInfoValue) - : - fPackageInfoValue(packageInfoValue) - { - } - - virtual status_t HandleAttribute(AttributeHandlerContext* context, - uint8 id, const AttributeValue& value, AttributeHandler** _handler) - { - switch (id) { - case B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR: - if (value.unsignedInt >= B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) { - context->errorOutput->PrintError( - "Error: Invalid package attribute section: invalid " - "package resolvable operator %lld encountered\n", - value.unsignedInt); - return B_BAD_DATA; - } - fPackageInfoValue.resolvableExpression.op - = (BPackageResolvableOperator)value.unsignedInt; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR: - fPackageInfoValue.resolvableExpression.haveOpAndVersion = true; - fPackageInfoValue.resolvableExpression.version.major - = value.string; - if (_handler != NULL) { - *_handler - = new(std::nothrow) PackageVersionAttributeHandler( - fPackageInfoValue, - fPackageInfoValue.resolvableExpression.version, - false); - if (*_handler == NULL) - return B_NO_MEMORY; - } - return B_OK; - - default: - context->errorOutput->PrintError("Error: Invalid package " - "attribute section: unexpected package attribute id %d " - "encountered when parsing package resolvable-expression\n", - id); - return B_BAD_DATA; - } - - return B_OK; - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - status_t error = context->packageContentHandler->HandlePackageAttribute( - fPackageInfoValue); - fPackageInfoValue.Clear(); - - delete this; - return error; - } - -private: - BPackageInfoAttributeValue& fPackageInfoValue; -}; - - -struct PackageReaderImpl::PackageAttributeHandler : AttributeHandler { - virtual status_t HandleAttribute(AttributeHandlerContext* context, - uint8 id, const AttributeValue& value, AttributeHandler** _handler) - { - switch (id) { - case B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_NAME, value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_SUMMARY, value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_DESCRIPTION, - value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_VENDOR, value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_PACKAGER, value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_FLAGS, - (uint32)value.unsignedInt); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE: - if (value.unsignedInt - >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) { - context->errorOutput->PrintError( - "Error: Invalid package attribute section: " - "Invalid package architecture %lld encountered\n", - value.unsignedInt); - return B_BAD_DATA; - } - fPackageInfoValue.SetTo(B_PACKAGE_INFO_ARCHITECTURE, - (uint8)value.unsignedInt); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR: - fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION; - fPackageInfoValue.version.major = value.string; - if (_handler != NULL) { - *_handler - = new(std::nothrow) PackageVersionAttributeHandler( - fPackageInfoValue, fPackageInfoValue.version, true); - if (*_handler == NULL) - return B_NO_MEMORY; - } - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_COPYRIGHTS, - value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_LICENSES, - value.string); - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES: - fPackageInfoValue.resolvable.name = value.string; - fPackageInfoValue.attributeID = B_PACKAGE_INFO_PROVIDES; - if (_handler != NULL) { - *_handler - = new(std::nothrow) PackageResolvableAttributeHandler( - fPackageInfoValue); - if (*_handler == NULL) - return B_NO_MEMORY; - } - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES: - case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS: - case B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS: - case B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS: - fPackageInfoValue.resolvableExpression.name = value.string; - switch (id) { - case B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES: - fPackageInfoValue.attributeID = B_PACKAGE_INFO_REQUIRES; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS: - fPackageInfoValue.attributeID - = B_PACKAGE_INFO_SUPPLEMENTS; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS: - fPackageInfoValue.attributeID - = B_PACKAGE_INFO_CONFLICTS; - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS: - fPackageInfoValue.attributeID = B_PACKAGE_INFO_FRESHENS; - break; - } - if (_handler != NULL) { - *_handler = new(std::nothrow) - PackageResolvableExpressionAttributeHandler( - fPackageInfoValue); - if (*_handler == NULL) - return B_NO_MEMORY; - } - break; - - case B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES: - fPackageInfoValue.SetTo(B_PACKAGE_INFO_REPLACES, value.string); - break; - - default: - context->errorOutput->PrintError( - "Error: Invalid package attribute section: unexpected " - "package attribute id %d encountered\n", id); - return B_BAD_DATA; - } - - // notify unless the current attribute has children, in which case - // the child-handler will notify when it's done - if (_handler == NULL) { - status_t error = context->packageContentHandler - ->HandlePackageAttribute(fPackageInfoValue); - fPackageInfoValue.Clear(); - if (error != B_OK) - return error; - } - - return B_OK; - } - -private: - BPackageInfoAttributeValue fPackageInfoValue; -}; +// #pragma mark - RootAttributeHandler struct PackageReaderImpl::RootAttributeHandler : PackageAttributeHandler { @@ -757,114 +373,19 @@ struct PackageReaderImpl::RootAttributeHandler : PackageAttributeHandler { }; -struct PackageReaderImpl::LowLevelAttributeHandler : AttributeHandler { - LowLevelAttributeHandler() - : - fToken(NULL), - fID(B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) - { - } - - LowLevelAttributeHandler(uint8 id, const BPackageAttributeValue& value, - void* token) - : - fToken(token), - fID(id), - fValue(value) - { - } - - virtual status_t HandleAttribute(AttributeHandlerContext* context, - uint8 id, const AttributeValue& value, AttributeHandler** _handler) - { - // notify the content handler - void* token; - status_t error = context->lowLevelPackageContentHandler - ->HandleAttribute((BHPKGAttributeID)id, value, fToken, token); - if (error != B_OK) - return error; - - // create a subhandler for the attribute, if it has children - if (_handler != NULL) { - *_handler = new(std::nothrow) LowLevelAttributeHandler(id, value, - token); - if (*_handler == NULL) { - context->lowLevelPackageContentHandler->HandleAttributeDone( - (BHPKGAttributeID)id, value, token); - return B_NO_MEMORY; - } - return B_OK; - } - - // no children -- just call the done hook - return context->lowLevelPackageContentHandler->HandleAttributeDone( - (BHPKGAttributeID)id, value, token); - } - - virtual status_t Delete(AttributeHandlerContext* context) - { - status_t error = B_OK; - if (fID != B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { - error = context->lowLevelPackageContentHandler->HandleAttributeDone( - (BHPKGAttributeID)fID, fValue, fToken); - } - - delete this; - return error; - } - -private: - - void* fToken; - uint8 fID; - AttributeValue fValue; -}; - - // #pragma mark - PackageReaderImpl -inline PackageReaderImpl::AttributeHandler* -PackageReaderImpl::_CurrentAttributeHandler() const -{ - return fAttributeHandlerStack->Head(); -} - - -inline void -PackageReaderImpl::_PushAttributeHandler(AttributeHandler* handler) -{ - fAttributeHandlerStack->Add(handler); -} - - -inline PackageReaderImpl::AttributeHandler* -PackageReaderImpl::_PopAttributeHandler() -{ - return fAttributeHandlerStack->RemoveHead(); -} - - PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput) : - fErrorOutput(errorOutput), - fFD(-1), - fOwnsFD(false), - fTOCSection("TOC"), - fPackageAttributesSection("package attributes section"), - fCurrentSection(NULL), - fScratchBuffer(NULL), - fScratchBufferSize(0) + inherited(errorOutput), + fTOCSection("TOC") { } PackageReaderImpl::~PackageReaderImpl() { - if (fOwnsFD && fFD >= 0) - close(fFD); - - delete[] fScratchBuffer; } @@ -874,7 +395,7 @@ PackageReaderImpl::Init(const char* fileName) // open file int fd = open(fileName, O_RDONLY); if (fd < 0) { - fErrorOutput->PrintError("Error: Failed to open package file \"%s\": " + ErrorOutput()->PrintError("Error: Failed to open package file \"%s\": " "%s\n", fileName, strerror(errno)); return errno; } @@ -886,28 +407,28 @@ PackageReaderImpl::Init(const char* fileName) status_t PackageReaderImpl::Init(int fd, bool keepFD) { - fFD = fd; - fOwnsFD = keepFD; + status_t error = inherited::Init(fd, keepFD); + if (error != B_OK) + return error; // stat it struct stat st; - if (fstat(fFD, &st) < 0) { - fErrorOutput->PrintError("Error: Failed to access package file: %s\n", + if (fstat(FD(), &st) < 0) { + ErrorOutput()->PrintError("Error: Failed to access package file: %s\n", strerror(errno)); return errno; } // read the header hpkg_header header; - status_t error = _ReadBuffer(0, &header, sizeof(header)); - if (error != B_OK) + if ((error = ReadBuffer(0, &header, sizeof(header))) != B_OK) return error; // check the header // magic if (B_BENDIAN_TO_HOST_INT32(header.magic) != B_HPKG_MAGIC) { - fErrorOutput->PrintError("Error: Invalid package file: Invalid " + ErrorOutput()->PrintError("Error: Invalid package file: Invalid " "magic\n"); return B_BAD_DATA; } @@ -915,14 +436,14 @@ PackageReaderImpl::Init(int fd, bool keepFD) // header size fHeapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size); if ((size_t)fHeapOffset < sizeof(hpkg_header)) { - fErrorOutput->PrintError("Error: Invalid package file: Invalid header " + ErrorOutput()->PrintError("Error: Invalid package file: Invalid header " "size (%llu)\n", fHeapOffset); return B_BAD_DATA; } // version if (B_BENDIAN_TO_HOST_INT16(header.version) != B_HPKG_VERSION) { - fErrorOutput->PrintError("Error: Invalid/unsupported package file " + ErrorOutput()->PrintError("Error: Invalid/unsupported package file " "version (%d)\n", B_BENDIAN_TO_HOST_INT16(header.version)); return B_BAD_DATA; } @@ -930,7 +451,7 @@ PackageReaderImpl::Init(int fd, bool keepFD) // total size fTotalSize = B_BENDIAN_TO_HOST_INT64(header.total_size); if (fTotalSize != (uint64)st.st_size) { - fErrorOutput->PrintError("Error: Invalid package file: Total size in " + ErrorOutput()->PrintError("Error: Invalid package file: Total size in " "header (%llu) doesn't agree with total file size (%lld)\n", fTotalSize, st.st_size); return B_BAD_DATA; @@ -948,9 +469,9 @@ PackageReaderImpl::Init(int fd, bool keepFD) fPackageAttributesSection.stringsCount = B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count); - if (const char* errorString = _CheckCompression( + if (const char* errorString = CheckCompression( fPackageAttributesSection)) { - fErrorOutput->PrintError("Error: Invalid package file: package " + ErrorOutput()->PrintError("Error: Invalid package file: package " "attributes section: %s\n", errorString); return B_BAD_DATA; } @@ -962,8 +483,8 @@ PackageReaderImpl::Init(int fd, bool keepFD) fTOCSection.uncompressedLength = B_BENDIAN_TO_HOST_INT64(header.toc_length_uncompressed); - if (const char* errorString = _CheckCompression(fTOCSection)) { - fErrorOutput->PrintError("Error: Invalid package file: TOC section: " + if (const char* errorString = CheckCompression(fTOCSection)) { + ErrorOutput()->PrintError("Error: Invalid package file: TOC section: " "%s\n", errorString); return B_BAD_DATA; } @@ -976,7 +497,7 @@ PackageReaderImpl::Init(int fd, bool keepFD) if (fTOCSection.stringsLength > fTOCSection.uncompressedLength || fTOCSection.stringsCount > fTOCSection.stringsLength) { - fErrorOutput->PrintError("Error: Invalid package file: Invalid TOC " + ErrorOutput()->PrintError("Error: Invalid package file: Invalid TOC " "subsections description\n"); return B_BAD_DATA; } @@ -988,7 +509,7 @@ PackageReaderImpl::Init(int fd, bool keepFD) || fHeapOffset > fTotalSize - fPackageAttributesSection.compressedLength - fTOCSection.compressedLength) { - fErrorOutput->PrintError("Error: Invalid package file: The sum of the " + ErrorOutput()->PrintError("Error: Invalid package file: The sum of the " "sections sizes is greater than the package size\n"); return B_BAD_DATA; } @@ -1001,7 +522,7 @@ PackageReaderImpl::Init(int fd, bool keepFD) // TOC size sanity check if (fTOCSection.uncompressedLength > kMaxTOCSize) { - fErrorOutput->PrintError("Error: Package file TOC section size " + ErrorOutput()->PrintError("Error: Package file TOC section size " "is %llu bytes. This is beyond the reader's sanity limit\n", fTOCSection.uncompressedLength); return B_UNSUPPORTED; @@ -1010,29 +531,21 @@ PackageReaderImpl::Init(int fd, bool keepFD) // package attributes size sanity check if (fPackageAttributesSection.uncompressedLength > kMaxPackageAttributesSize) { - fErrorOutput->PrintError( + ErrorOutput()->PrintError( "Error: Package file package attributes section size " "is %llu bytes. This is beyond the reader's sanity limit\n", fPackageAttributesSection.uncompressedLength); return B_UNSUPPORTED; } - // allocate a scratch buffer - fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize]; - if (fScratchBuffer == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - fScratchBufferSize = kScratchBufferSize; - // read in the complete TOC fTOCSection.data = new(std::nothrow) uint8[fTOCSection.uncompressedLength]; if (fTOCSection.data == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); + ErrorOutput()->PrintError("Error: Out of memory!\n"); return B_NO_MEMORY; } - error = _ReadCompressedBuffer(fTOCSection); + error = ReadCompressedBuffer(fTOCSection); if (error != B_OK) return error; @@ -1040,34 +553,32 @@ PackageReaderImpl::Init(int fd, bool keepFD) fPackageAttributesSection.data = new(std::nothrow) uint8[fPackageAttributesSection.uncompressedLength]; if (fPackageAttributesSection.data == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); + ErrorOutput()->PrintError("Error: Out of memory!\n"); return B_NO_MEMORY; } - error = _ReadCompressedBuffer(fPackageAttributesSection); + error = ReadCompressedBuffer(fPackageAttributesSection); if (error != B_OK) return error; // start parsing the TOC - fCurrentSection = &fTOCSection; - fCurrentSection->currentOffset = 0; + fTOCSection.currentOffset = 0; + SetCurrentSection(&fTOCSection); // strings - error = _ParseStrings(); + error = ParseStrings(); if (error != B_OK) return error; - fCurrentSection->currentOffset += fCurrentSection->stringsLength; // parse strings from package attributes section - fCurrentSection = &fPackageAttributesSection; - fCurrentSection->currentOffset = 0; + fPackageAttributesSection.currentOffset = 0; + SetCurrentSection(&fPackageAttributesSection); // strings - error = _ParseStrings(); + error = ParseStrings(); if (error != B_OK) return error; - fCurrentSection->currentOffset += fCurrentSection->stringsLength; - fCurrentSection = NULL; + SetCurrentSection(NULL); return B_OK; } @@ -1076,153 +587,58 @@ PackageReaderImpl::Init(int fd, bool keepFD) status_t PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler) { - AttributeHandlerContext context(fErrorOutput, contentHandler); + AttributeHandlerContext context(ErrorOutput(), contentHandler); RootAttributeHandler rootAttributeHandler; - return _ParseContent(&context, &rootAttributeHandler); + status_t error = _ParseTOC(&context, &rootAttributeHandler); + if (error == B_OK) + error = ParsePackageAttributesSection(&context, &rootAttributeHandler); + return error; } status_t PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler) { - AttributeHandlerContext context(fErrorOutput, contentHandler); + AttributeHandlerContext context(ErrorOutput(), contentHandler); LowLevelAttributeHandler rootAttributeHandler; - return _ParseContent(&context, &rootAttributeHandler); -} - - -const char* -PackageReaderImpl::_CheckCompression(const SectionInfo& section) const -{ - switch (section.compression) { - case B_HPKG_COMPRESSION_NONE: - if (section.compressedLength != section.uncompressedLength) { - return "Uncompressed, but compressed and uncompressed length " - "don't match"; - } - return NULL; - - case B_HPKG_COMPRESSION_ZLIB: - if (section.compressedLength >= section.uncompressedLength) { - return "Compressed, but compressed length is not less than " - "uncompressed length"; - } - return NULL; - - default: - return "Invalid compression algorithm ID"; - } + status_t error = _ParseTOC(&context, &rootAttributeHandler); + if (error == B_OK) + error = ParsePackageAttributesSection(&context, &rootAttributeHandler); + return error; } status_t -PackageReaderImpl::_ParseStrings() -{ - // allocate table - fCurrentSection->strings - = new(std::nothrow) char*[fCurrentSection->stringsCount]; - if (fCurrentSection->strings == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - - // parse the section and fill the table - char* position - = (char*)fCurrentSection->data + fCurrentSection->currentOffset; - char* sectionEnd = position + fCurrentSection->stringsLength; - uint32 index = 0; - while (true) { - if (position >= sectionEnd) { - fErrorOutput->PrintError("Error: Malformed %s strings section\n", - fCurrentSection->name); - return B_BAD_DATA; - } - - size_t stringLength = strnlen(position, (char*)sectionEnd - position); - - if (stringLength == 0) { - if (position + 1 != sectionEnd) { - fErrorOutput->PrintError( - "Error: %ld excess bytes in %s strings section\n", - sectionEnd - (position + 1), fCurrentSection->name); - return B_BAD_DATA; - } - - if (index != fCurrentSection->stringsCount) { - fErrorOutput->PrintError("Error: Invalid %s strings section: " - "Less strings (%lld) than specified in the header (%lld)\n", - fCurrentSection->name, index, - fCurrentSection->stringsCount); - return B_BAD_DATA; - } - - return B_OK; - } - - if (index >= fCurrentSection->stringsCount) { - fErrorOutput->PrintError("Error: Invalid %s strings section: " - "More strings (%lld) than specified in the header (%lld)\n", - fCurrentSection->name, index, fCurrentSection->stringsCount); - return B_BAD_DATA; - } - - fCurrentSection->strings[index++] = position; - position += stringLength + 1; - } -} - - -status_t -PackageReaderImpl::_ParseContent(AttributeHandlerContext* context, +PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler) { // parse the TOC - fCurrentSection = &fTOCSection; fTOCSection.currentOffset = fTOCSection.stringsLength; + SetCurrentSection(&fTOCSection); // prepare attribute handler context context->heapOffset = fHeapOffset; context->heapSize = fHeapSize; // init the attribute handler stack - AttributeHandlerList attributeHandlerStack; - fAttributeHandlerStack = &attributeHandlerStack; - fAttributeHandlerStack->Add(rootAttributeHandler); rootAttributeHandler->SetLevel(0); + ClearAttributeHandlerStack(); + PushAttributeHandler(rootAttributeHandler); - status_t error = _ParseAttributeTree(context); + status_t error = ParseAttributeTree(context); if (error == B_OK) { if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) { - fErrorOutput->PrintError("Error: %llu excess byte(s) in TOC " + ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC " "section\n", fTOCSection.uncompressedLength - fTOCSection.currentOffset); error = B_BAD_DATA; } } - // parse package attributes - fCurrentSection = &fPackageAttributesSection; - fAttributeHandlerStack->Add(rootAttributeHandler); - // re-init the attribute handler stack - if (error == B_OK) - error = _ParseAttributeTree(context); - if (error == B_OK) { - if (fPackageAttributesSection.currentOffset - < fPackageAttributesSection.uncompressedLength) { - fErrorOutput->PrintError("Error: %llu excess byte(s) in package " - "attributes section\n", - fPackageAttributesSection.uncompressedLength - - fPackageAttributesSection.currentOffset); - error = B_BAD_DATA; - } - } - - fCurrentSection = NULL; - // clean up on error if (error != B_OK) { context->ErrorOccurred(); - while (AttributeHandler* handler = _PopAttributeHandler()) { + while (AttributeHandler* handler = PopAttributeHandler()) { if (handler != rootAttributeHandler) handler->Delete(context); } @@ -1234,214 +650,34 @@ PackageReaderImpl::_ParseContent(AttributeHandlerContext* context, status_t -PackageReaderImpl::_ParseAttributeTree(AttributeHandlerContext* context) -{ - int level = 0; - - while (true) { - uint8 id; - AttributeValue value; - bool hasChildren; - uint64 tag; - - status_t error = _ReadAttribute(id, value, &hasChildren, &tag); - if (error != B_OK) - return error; - - if (tag == 0) { - AttributeHandler* handler = _PopAttributeHandler(); - if (level-- == 0) - return B_OK; - - error = handler->Delete(context); - if (error != B_OK) - return error; - - continue; - } - - AttributeHandler* childHandler = NULL; - error = _CurrentAttributeHandler()->HandleAttribute(context, id, value, - hasChildren ? &childHandler : NULL); - if (error != B_OK) - return error; - - // parse children - if (hasChildren) { - // create an ignore handler, if necessary - if (childHandler == NULL) { - childHandler = new(std::nothrow) IgnoreAttributeHandler; - if (childHandler == NULL) { - fErrorOutput->PrintError("Error: Out of memory!\n"); - return B_NO_MEMORY; - } - } - - childHandler->SetLevel(++level); - _PushAttributeHandler(childHandler); - } - } -} - - -status_t -PackageReaderImpl::_ReadAttribute(uint8& _id, AttributeValue& _value, - bool* _hasChildren, uint64* _tag) -{ - uint64 tag; - status_t error = _ReadUnsignedLEB128(tag); - if (error != B_OK) - return error; - - if (tag != 0) { - // get the type - uint16 type = HPKG_ATTRIBUTE_TAG_TYPE(tag); - if (type >= B_HPKG_ATTRIBUTE_TYPE_ENUM_COUNT) { - fErrorOutput->PrintError("Error: Invalid %s section: attribute " - "type %d not supported!\n", fCurrentSection->name, type); - return B_BAD_DATA; - } - - // get the value - error = _ReadAttributeValue(type, HPKG_ATTRIBUTE_TAG_ENCODING(tag), - _value); - if (error != B_OK) - return error; - - _id = HPKG_ATTRIBUTE_TAG_ID(tag); - if (_id >= B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { - fErrorOutput->PrintError("Error: Invalid %s section: " - "attribute id %d not supported!\n", fCurrentSection->name, _id); - return B_BAD_DATA; - } - } - - if (_hasChildren != NULL) - *_hasChildren = HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag); - if (_tag != NULL) - *_tag = tag; - - return B_OK; -} - - -status_t -PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, +PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding, AttributeValue& _value) { switch (type) { - case B_HPKG_ATTRIBUTE_TYPE_INT: - case B_HPKG_ATTRIBUTE_TYPE_UINT: - { - uint64 intValue; - status_t error; - - switch (encoding) { - case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: - { - uint8 value; - error = _Read(value); - intValue = value; - break; - } - case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: - { - uint16 value; - error = _Read(value); - intValue = B_BENDIAN_TO_HOST_INT16(value); - break; - } - case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: - { - uint32 value; - error = _Read(value); - intValue = B_BENDIAN_TO_HOST_INT32(value); - break; - } - case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: - { - uint64 value; - error = _Read(value); - intValue = B_BENDIAN_TO_HOST_INT64(value); - break; - } - default: - { - fErrorOutput->PrintError("Error: Invalid %s section: " - "invalid encoding %d for int value type %d\n", - fCurrentSection->name, encoding, type); - return B_BAD_VALUE; - } - } - - if (error != B_OK) - return error; - - if (type == B_HPKG_ATTRIBUTE_TYPE_INT) - _value.SetTo((int64)intValue); - else - _value.SetTo(intValue); - - return B_OK; - } - - case B_HPKG_ATTRIBUTE_TYPE_STRING: - { - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) { - uint64 index; - status_t error = _ReadUnsignedLEB128(index); - if (error != B_OK) - return error; - - if (index > fCurrentSection->stringsCount) { - fErrorOutput->PrintError("Error: Invalid %s section: " - "string reference (%lld) out of bounds (%lld)\n", - fCurrentSection->name, index, - fCurrentSection->stringsCount); - return B_BAD_DATA; - } - - _value.SetTo(fCurrentSection->strings[index]); - } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) { - const char* string; - status_t error = _ReadString(string); - if (error != B_OK) - return error; - - _value.SetTo(string); - } else { - fErrorOutput->PrintError("Error: Invalid %s section: invalid " - "string encoding (%u)\n", fCurrentSection->name, encoding); - return B_BAD_DATA; - } - - return B_OK; - } - case B_HPKG_ATTRIBUTE_TYPE_RAW: { uint64 size; - status_t error = _ReadUnsignedLEB128(size); + status_t error = ReadUnsignedLEB128(size); if (error != B_OK) return error; if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { uint64 offset; - error = _ReadUnsignedLEB128(offset); + error = ReadUnsignedLEB128(offset); if (error != B_OK) return error; if (offset > fHeapSize || size > fHeapSize - offset) { - fErrorOutput->PrintError("Error: Invalid %s section: " - "invalid data reference\n", fCurrentSection->name); + ErrorOutput()->PrintError("Error: Invalid %s section: " + "invalid data reference\n", CurrentSection()->name); return B_BAD_DATA; } _value.SetToData(size, fHeapOffset + offset); } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { if (size > B_HPKG_MAX_INLINE_DATA_SIZE) { - fErrorOutput->PrintError("Error: Invalid %s section: " - "inline data too long\n", fCurrentSection->name); + ErrorOutput()->PrintError("Error: Invalid %s section: " + "inline data too long\n", CurrentSection()->name); return B_BAD_DATA; } @@ -1451,8 +687,8 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, return error; _value.SetToData(size, buffer); } else { - fErrorOutput->PrintError("Error: Invalid %s section: invalid " - "raw encoding (%u)\n", fCurrentSection->name, encoding); + ErrorOutput()->PrintError("Error: Invalid %s section: invalid " + "raw encoding (%u)\n", CurrentSection()->name, encoding); return B_BAD_DATA; } @@ -1460,66 +696,16 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, } default: - fErrorOutput->PrintError("Error: Invalid %s section: invalid " - "value type: %d\n", fCurrentSection->name, type); - return B_BAD_DATA; + return inherited::ReadAttributeValue(type, encoding, _value); } } -status_t -PackageReaderImpl::_ReadUnsignedLEB128(uint64& _value) -{ - uint64 result = 0; - int shift = 0; - while (true) { - uint8 byte; - status_t error = _Read(byte); - if (error != B_OK) - return error; - - result |= uint64(byte & 0x7f) << shift; - if ((byte & 0x80) == 0) - break; - shift += 7; - } - - _value = result; - return B_OK; -} - - -status_t -PackageReaderImpl::_ReadString(const char*& _string, size_t* _stringLength) -{ - const char* string - = (const char*)fCurrentSection->data + fCurrentSection->currentOffset; - size_t stringLength = strnlen(string, - fCurrentSection->uncompressedLength - fCurrentSection->currentOffset); - - if (stringLength - == fCurrentSection->uncompressedLength - - fCurrentSection->currentOffset) { - fErrorOutput->PrintError( - "_ReadString(): string extends beyond %s end\n", - fCurrentSection->name); - return B_BAD_DATA; - } - - _string = string; - if (_stringLength != NULL) - *_stringLength = stringLength; - - fCurrentSection->currentOffset += stringLength + 1; - return B_OK; -} - - status_t PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer) { if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) { - fErrorOutput->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n", + ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n", size); return B_BAD_DATA; } @@ -1530,98 +716,6 @@ PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer) } -status_t -PackageReaderImpl::_ReadSectionBuffer(void* buffer, size_t size) -{ - if (size > fCurrentSection->uncompressedLength - - fCurrentSection->currentOffset) { - fErrorOutput->PrintError("_ReadBuffer(%lu): read beyond %s end\n", - size, fCurrentSection->name); - return B_BAD_DATA; - } - - memcpy(buffer, fCurrentSection->data + fCurrentSection->currentOffset, - size); - fCurrentSection->currentOffset += size; - return B_OK; -} - - -status_t -PackageReaderImpl::_ReadBuffer(off_t offset, void* buffer, size_t size) -{ - ssize_t bytesRead = pread(fFD, buffer, size, offset); - if (bytesRead < 0) { - fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: " - "%s\n", buffer, size, strerror(errno)); - return errno; - } - if ((size_t)bytesRead != size) { - fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read all " - "data\n", buffer, size); - return B_ERROR; - } - - return B_OK; -} - - -status_t -PackageReaderImpl::_ReadCompressedBuffer(const SectionInfo& section) -{ - uint32 compressedSize = section.compressedLength; - uint64 offset = section.offset; - - switch (section.compression) { - case B_HPKG_COMPRESSION_NONE: - return _ReadBuffer(offset, section.data, compressedSize); - - case B_HPKG_COMPRESSION_ZLIB: - { - // init the decompressor - BBufferDataOutput bufferOutput(section.data, - section.uncompressedLength); - ZlibDecompressor decompressor(&bufferOutput); - status_t error = decompressor.Init(); - if (error != B_OK) - return error; - - while (compressedSize > 0) { - // read compressed buffer - size_t toRead = std::min(compressedSize, fScratchBufferSize); - error = _ReadBuffer(offset, fScratchBuffer, toRead); - if (error != B_OK) - return error; - - // uncompress - error = decompressor.DecompressNext(fScratchBuffer, toRead); - if (error != B_OK) - return error; - - compressedSize -= toRead; - offset += toRead; - } - - error = decompressor.Finish(); - if (error != B_OK) - return error; - - // verify that all data have been read - if (bufferOutput.BytesWritten() != section.uncompressedLength) { - fErrorOutput->PrintError("Error: Missing bytes in uncompressed " - "buffer!\n"); - return B_BAD_DATA; - } - - return B_OK; - } - - default: - return B_BAD_DATA; - } -} - - } // namespace BPrivate } // namespace BHPKG diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp new file mode 100644 index 0000000000..9f7d75a55f --- /dev/null +++ b/src/kits/package/hpkg/ReaderImplBase.cpp @@ -0,0 +1,1001 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +static const size_t kScratchBufferSize = 64 * 1024; + + +// #pragma mark - AttributeHandlerContext + + +ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext( + BErrorOutput* errorOutput, BPackageContentHandler* packageContentHandler) + : + errorOutput(errorOutput), + packageContentHandler(packageContentHandler), + hasLowLevelHandler(false) +{ +} + + +ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext( + BErrorOutput* errorOutput, BLowLevelPackageContentHandler* lowLevelHandler) + : + errorOutput(errorOutput), + lowLevelHandler(lowLevelHandler), + hasLowLevelHandler(true) +{ +} + + +void +ReaderImplBase::AttributeHandlerContext::ErrorOccurred() +{ + if (hasLowLevelHandler) + lowLevelHandler->HandleErrorOccurred(); + else + packageContentHandler->HandleErrorOccurred(); +} + + +// #pragma mark - AttributeHandler + + +ReaderImplBase::AttributeHandler::~AttributeHandler() +{ +} + + +void +ReaderImplBase::AttributeHandler::SetLevel(int level) +{ + fLevel = level; +} + + +status_t +ReaderImplBase::AttributeHandler::HandleAttribute( + AttributeHandlerContext* context, uint8 id, const AttributeValue& value, + AttributeHandler** _handler) +{ + return B_OK; +} + + +status_t +ReaderImplBase::AttributeHandler::Delete(AttributeHandlerContext* context) +{ + delete this; + return B_OK; +} + + +// #pragma mark - PackageVersionAttributeHandler + + +ReaderImplBase::PackageVersionAttributeHandler::PackageVersionAttributeHandler( + BPackageInfoAttributeValue& packageInfoValue, + BPackageVersionData& versionData, bool notify) + : + fPackageInfoValue(packageInfoValue), + fPackageVersionData(versionData), + fNotify(notify) +{ +} + + +status_t +ReaderImplBase::PackageVersionAttributeHandler::HandleAttribute( + AttributeHandlerContext* context, uint8 id, const AttributeValue& value, + AttributeHandler** _handler) +{ + switch (id) { + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR: + fPackageVersionData.minor = value.string; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO: + fPackageVersionData.micro = value.string; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE: + fPackageVersionData.release = value.unsignedInt; + break; + + default: + context->errorOutput->PrintError("Error: Invalid package " + "attribute section: unexpected package attribute id %d " + "encountered when parsing package version\n", id); + return B_BAD_DATA; + } + + return B_OK; +} + + +status_t +ReaderImplBase::PackageVersionAttributeHandler::Delete( + AttributeHandlerContext* context) +{ + status_t error = B_OK; + if (fNotify) { + fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION; + error = context->packageContentHandler->HandlePackageAttribute( + fPackageInfoValue); + fPackageInfoValue.Clear(); + } + + delete this; + return error; +} + + +// #pragma mark - PackageResolvableAttributeHandler + + +ReaderImplBase::PackageResolvableAttributeHandler + ::PackageResolvableAttributeHandler( + BPackageInfoAttributeValue& packageInfoValue) + : + fPackageInfoValue(packageInfoValue) +{ +} + + +status_t +ReaderImplBase::PackageResolvableAttributeHandler::HandleAttribute( + AttributeHandlerContext* context, uint8 id, const AttributeValue& value, + AttributeHandler** _handler) +{ + switch (id) { + case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_TYPE: + fPackageInfoValue.resolvable.type + = (BPackageResolvableType)value.unsignedInt; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR: + fPackageInfoValue.resolvable.haveVersion = true; + fPackageInfoValue.resolvable.version.major = value.string; + if (_handler != NULL) { + *_handler + = new(std::nothrow) PackageVersionAttributeHandler( + fPackageInfoValue, + fPackageInfoValue.resolvable.version, false); + if (*_handler == NULL) + return B_NO_MEMORY; + } + break; + + default: + context->errorOutput->PrintError("Error: Invalid package " + "attribute section: unexpected package attribute id %d " + "encountered when parsing package resolvable\n", id); + return B_BAD_DATA; + } + + return B_OK; +} + + +status_t +ReaderImplBase::PackageResolvableAttributeHandler::Delete( + AttributeHandlerContext* context) +{ + status_t error = context->packageContentHandler->HandlePackageAttribute( + fPackageInfoValue); + fPackageInfoValue.Clear(); + + delete this; + return error; +} + + +// #pragma mark - PackageResolvableExpressionAttributeHandler + + +ReaderImplBase::PackageResolvableExpressionAttributeHandler + ::PackageResolvableExpressionAttributeHandler( + BPackageInfoAttributeValue& packageInfoValue) + : + fPackageInfoValue(packageInfoValue) +{ +} + + +status_t +ReaderImplBase::PackageResolvableExpressionAttributeHandler::HandleAttribute( + AttributeHandlerContext* context, uint8 id, const AttributeValue& value, + AttributeHandler** _handler) +{ + switch (id) { + case B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR: + if (value.unsignedInt >= B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) { + context->errorOutput->PrintError( + "Error: Invalid package attribute section: invalid " + "package resolvable operator %lld encountered\n", + value.unsignedInt); + return B_BAD_DATA; + } + fPackageInfoValue.resolvableExpression.op + = (BPackageResolvableOperator)value.unsignedInt; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR: + fPackageInfoValue.resolvableExpression.haveOpAndVersion = true; + fPackageInfoValue.resolvableExpression.version.major + = value.string; + if (_handler != NULL) { + *_handler + = new(std::nothrow) PackageVersionAttributeHandler( + fPackageInfoValue, + fPackageInfoValue.resolvableExpression.version, + false); + if (*_handler == NULL) + return B_NO_MEMORY; + } + return B_OK; + + default: + context->errorOutput->PrintError("Error: Invalid package " + "attribute section: unexpected package attribute id %d " + "encountered when parsing package resolvable-expression\n", + id); + return B_BAD_DATA; + } + + return B_OK; +} + + +status_t +ReaderImplBase::PackageResolvableExpressionAttributeHandler::Delete( + AttributeHandlerContext* context) +{ + status_t error = context->packageContentHandler->HandlePackageAttribute( + fPackageInfoValue); + fPackageInfoValue.Clear(); + + delete this; + return error; +} + + +// #pragma mark - PackageAttributeHandler + + +status_t +ReaderImplBase::PackageAttributeHandler::HandleAttribute( + AttributeHandlerContext* context, uint8 id, const AttributeValue& value, + AttributeHandler** _handler) +{ + switch (id) { + case B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_NAME, value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_SUMMARY, value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_DESCRIPTION, + value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_VENDOR, value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_PACKAGER, value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_FLAGS, + (uint32)value.unsignedInt); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE: + if (value.unsignedInt + >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) { + context->errorOutput->PrintError( + "Error: Invalid package attribute section: " + "Invalid package architecture %lld encountered\n", + value.unsignedInt); + return B_BAD_DATA; + } + fPackageInfoValue.SetTo(B_PACKAGE_INFO_ARCHITECTURE, + (uint8)value.unsignedInt); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR: + fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION; + fPackageInfoValue.version.major = value.string; + if (_handler != NULL) { + *_handler + = new(std::nothrow) PackageVersionAttributeHandler( + fPackageInfoValue, fPackageInfoValue.version, true); + if (*_handler == NULL) + return B_NO_MEMORY; + } + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_COPYRIGHTS, + value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_LICENSES, + value.string); + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES: + fPackageInfoValue.resolvable.name = value.string; + fPackageInfoValue.attributeID = B_PACKAGE_INFO_PROVIDES; + if (_handler != NULL) { + *_handler + = new(std::nothrow) PackageResolvableAttributeHandler( + fPackageInfoValue); + if (*_handler == NULL) + return B_NO_MEMORY; + } + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES: + case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS: + case B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS: + case B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS: + fPackageInfoValue.resolvableExpression.name = value.string; + switch (id) { + case B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES: + fPackageInfoValue.attributeID = B_PACKAGE_INFO_REQUIRES; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS: + fPackageInfoValue.attributeID + = B_PACKAGE_INFO_SUPPLEMENTS; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS: + fPackageInfoValue.attributeID + = B_PACKAGE_INFO_CONFLICTS; + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS: + fPackageInfoValue.attributeID = B_PACKAGE_INFO_FRESHENS; + break; + } + if (_handler != NULL) { + *_handler = new(std::nothrow) + PackageResolvableExpressionAttributeHandler( + fPackageInfoValue); + if (*_handler == NULL) + return B_NO_MEMORY; + } + break; + + case B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES: + fPackageInfoValue.SetTo(B_PACKAGE_INFO_REPLACES, value.string); + break; + + default: + context->errorOutput->PrintError( + "Error: Invalid package attribute section: unexpected " + "package attribute id %d encountered\n", id); + return B_BAD_DATA; + } + + // notify unless the current attribute has children, in which case + // the child-handler will notify when it's done + if (_handler == NULL) { + status_t error = context->packageContentHandler + ->HandlePackageAttribute(fPackageInfoValue); + fPackageInfoValue.Clear(); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +// #pragma mark - LowLevelAttributeHandler + + +ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler() + : + fToken(NULL), + fID(B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) +{ +} + + +ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler(uint8 id, + const BPackageAttributeValue& value, void* token) + : + fToken(token), + fID(id), + fValue(value) +{ +} + + +status_t +ReaderImplBase::LowLevelAttributeHandler::HandleAttribute( + AttributeHandlerContext* context, uint8 id, const AttributeValue& value, + AttributeHandler** _handler) +{ + // notify the content handler + void* token; + status_t error = context->lowLevelHandler->HandleAttribute( + (BHPKGAttributeID)id, value, fToken, token); + if (error != B_OK) + return error; + + // create a subhandler for the attribute, if it has children + if (_handler != NULL) { + *_handler = new(std::nothrow) LowLevelAttributeHandler(id, value, + token); + if (*_handler == NULL) { + context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id, + value, token); + return B_NO_MEMORY; + } + return B_OK; + } + + // no children -- just call the done hook + return context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id, + value, token); +} + + +status_t +ReaderImplBase::LowLevelAttributeHandler::Delete( + AttributeHandlerContext* context) +{ + status_t error = B_OK; + if (fID != B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { + error = context->lowLevelHandler->HandleAttributeDone( + (BHPKGAttributeID)fID, fValue, fToken); + } + + delete this; + return error; +} + + +// #pragma mark - ReaderImplBase + + +ReaderImplBase::ReaderImplBase(BErrorOutput* errorOutput) + : + fPackageAttributesSection("package attributes"), + fErrorOutput(errorOutput), + fFD(-1), + fOwnsFD(false), + fCurrentSection(NULL), + fScratchBuffer(NULL), + fScratchBufferSize(0) +{ +} + + +ReaderImplBase::~ReaderImplBase() +{ + if (fOwnsFD && fFD >= 0) + close(fFD); + + delete[] fScratchBuffer; +} + + +status_t +ReaderImplBase::Init(int fd, bool keepFD) +{ + fFD = fd; + fOwnsFD = keepFD; + + // allocate a scratch buffer + fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize]; + if (fScratchBuffer == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + fScratchBufferSize = kScratchBufferSize; + + return B_OK; +} + + +const char* +ReaderImplBase::CheckCompression(const SectionInfo& section) const +{ + switch (section.compression) { + case B_HPKG_COMPRESSION_NONE: + if (section.compressedLength != section.uncompressedLength) { + return "Uncompressed, but compressed and uncompressed length " + "don't match"; + } + return NULL; + + case B_HPKG_COMPRESSION_ZLIB: + if (section.compressedLength >= section.uncompressedLength) { + return "Compressed, but compressed length is not less than " + "uncompressed length"; + } + return NULL; + + default: + return "Invalid compression algorithm ID"; + } +} + + +status_t +ReaderImplBase::ParseStrings() +{ + // allocate table + fCurrentSection->strings + = new(std::nothrow) char*[fCurrentSection->stringsCount]; + if (fCurrentSection->strings == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + + // parse the section and fill the table + char* position + = (char*)fCurrentSection->data + fCurrentSection->currentOffset; + char* sectionEnd = position + fCurrentSection->stringsLength; + uint32 index = 0; + while (true) { + if (position >= sectionEnd) { + fErrorOutput->PrintError("Error: Malformed %s strings section\n", + fCurrentSection->name); + return B_BAD_DATA; + } + + size_t stringLength = strnlen(position, (char*)sectionEnd - position); + + if (stringLength == 0) { + if (position + 1 != sectionEnd) { + fErrorOutput->PrintError( + "Error: %ld excess bytes in %s strings section\n", + sectionEnd - (position + 1), fCurrentSection->name); + return B_BAD_DATA; + } + + if (index != fCurrentSection->stringsCount) { + fErrorOutput->PrintError("Error: Invalid %s strings section: " + "Less strings (%lld) than specified in the header (%lld)\n", + fCurrentSection->name, index, + fCurrentSection->stringsCount); + return B_BAD_DATA; + } + + fCurrentSection->currentOffset += fCurrentSection->stringsLength; + + return B_OK; + } + + if (index >= fCurrentSection->stringsCount) { + fErrorOutput->PrintError("Error: Invalid %s strings section: " + "More strings (%lld) than specified in the header (%lld)\n", + fCurrentSection->name, index, fCurrentSection->stringsCount); + return B_BAD_DATA; + } + + fCurrentSection->strings[index++] = position; + position += stringLength + 1; + } +} + + +status_t +ReaderImplBase::ParsePackageAttributesSection( + AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler) +{ + // parse package attributes + SetCurrentSection(&fPackageAttributesSection); + + // init the attribute handler stack + rootAttributeHandler->SetLevel(0); + ClearAttributeHandlerStack(); + PushAttributeHandler(rootAttributeHandler); + + status_t error = ParseAttributeTree(context); + if (error == B_OK) { + if (fPackageAttributesSection.currentOffset + < fPackageAttributesSection.uncompressedLength) { + fErrorOutput->PrintError("Error: %llu excess byte(s) in package " + "attributes section\n", + fPackageAttributesSection.uncompressedLength + - fPackageAttributesSection.currentOffset); + error = B_BAD_DATA; + } + } + + SetCurrentSection(NULL); + + // clean up on error + if (error != B_OK) { + context->ErrorOccurred(); + while (AttributeHandler* handler = PopAttributeHandler()) { + if (handler != rootAttributeHandler) + handler->Delete(context); + } + return error; + } + + return B_OK; +} + + +status_t +ReaderImplBase::ParseAttributeTree(AttributeHandlerContext* context) +{ + int level = 0; + + while (true) { + uint8 id; + AttributeValue value; + bool hasChildren; + uint64 tag; + + status_t error = _ReadAttribute(id, value, &hasChildren, &tag); + if (error != B_OK) + return error; + + if (tag == 0) { + AttributeHandler* handler = PopAttributeHandler(); + if (level-- == 0) + return B_OK; + + error = handler->Delete(context); + if (error != B_OK) + return error; + + continue; + } + + AttributeHandler* childHandler = NULL; + error = CurrentAttributeHandler()->HandleAttribute(context, id, value, + hasChildren ? &childHandler : NULL); + if (error != B_OK) + return error; + + // parse children + if (hasChildren) { + // create an ignore handler, if necessary + if (childHandler == NULL) { + childHandler = new(std::nothrow) IgnoreAttributeHandler; + if (childHandler == NULL) { + fErrorOutput->PrintError("Error: Out of memory!\n"); + return B_NO_MEMORY; + } + } + + childHandler->SetLevel(++level); + PushAttributeHandler(childHandler); + } + } +} + + +status_t +ReaderImplBase::_ReadAttribute(uint8& _id, AttributeValue& _value, + bool* _hasChildren, uint64* _tag) +{ + uint64 tag; + status_t error = ReadUnsignedLEB128(tag); + if (error != B_OK) + return error; + + if (tag != 0) { + // get the type + uint16 type = HPKG_ATTRIBUTE_TAG_TYPE(tag); + if (type >= B_HPKG_ATTRIBUTE_TYPE_ENUM_COUNT) { + fErrorOutput->PrintError("Error: Invalid %s section: attribute " + "type %d not supported!\n", fCurrentSection->name, type); + return B_BAD_DATA; + } + + // get the value + error = ReadAttributeValue(type, HPKG_ATTRIBUTE_TAG_ENCODING(tag), + _value); + if (error != B_OK) + return error; + + _id = HPKG_ATTRIBUTE_TAG_ID(tag); + if (_id >= B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { + fErrorOutput->PrintError("Error: Invalid %s section: " + "attribute id %d not supported!\n", fCurrentSection->name, _id); + return B_BAD_DATA; + } + } + + if (_hasChildren != NULL) + *_hasChildren = HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag); + if (_tag != NULL) + *_tag = tag; + + return B_OK; +} + + +status_t +ReaderImplBase::ReadAttributeValue(uint8 type, uint8 encoding, + AttributeValue& _value) +{ + switch (type) { + case B_HPKG_ATTRIBUTE_TYPE_INT: + case B_HPKG_ATTRIBUTE_TYPE_UINT: + { + uint64 intValue; + status_t error; + + switch (encoding) { + case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: + { + uint8 value; + error = _Read(value); + intValue = value; + break; + } + case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: + { + uint16 value; + error = _Read(value); + intValue = B_BENDIAN_TO_HOST_INT16(value); + break; + } + case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: + { + uint32 value; + error = _Read(value); + intValue = B_BENDIAN_TO_HOST_INT32(value); + break; + } + case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: + { + uint64 value; + error = _Read(value); + intValue = B_BENDIAN_TO_HOST_INT64(value); + break; + } + default: + { + fErrorOutput->PrintError("Error: Invalid %s section: " + "invalid encoding %d for int value type %d\n", + fCurrentSection->name, encoding, type); + return B_BAD_VALUE; + } + } + + if (error != B_OK) + return error; + + if (type == B_HPKG_ATTRIBUTE_TYPE_INT) + _value.SetTo((int64)intValue); + else + _value.SetTo(intValue); + + return B_OK; + } + + case B_HPKG_ATTRIBUTE_TYPE_STRING: + { + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) { + uint64 index; + status_t error = ReadUnsignedLEB128(index); + if (error != B_OK) + return error; + + if (index > fCurrentSection->stringsCount) { + fErrorOutput->PrintError("Error: Invalid %s section: " + "string reference (%lld) out of bounds (%lld)\n", + fCurrentSection->name, index, + fCurrentSection->stringsCount); + return B_BAD_DATA; + } + + _value.SetTo(fCurrentSection->strings[index]); + } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) { + const char* string; + status_t error = _ReadString(string); + if (error != B_OK) + return error; + + _value.SetTo(string); + } else { + fErrorOutput->PrintError("Error: Invalid %s section: invalid " + "string encoding (%u)\n", fCurrentSection->name, encoding); + return B_BAD_DATA; + } + + return B_OK; + } + + default: + fErrorOutput->PrintError("Error: Invalid %s section: invalid " + "value type: %d\n", fCurrentSection->name, type); + return B_BAD_DATA; + } +} + + +status_t +ReaderImplBase::ReadUnsignedLEB128(uint64& _value) +{ + uint64 result = 0; + int shift = 0; + while (true) { + uint8 byte; + status_t error = _Read(byte); + if (error != B_OK) + return error; + + result |= uint64(byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + + _value = result; + return B_OK; +} + + +status_t +ReaderImplBase::_ReadString(const char*& _string, size_t* _stringLength) +{ + const char* string + = (const char*)fCurrentSection->data + fCurrentSection->currentOffset; + size_t stringLength = strnlen(string, + fCurrentSection->uncompressedLength - fCurrentSection->currentOffset); + + if (stringLength + == fCurrentSection->uncompressedLength + - fCurrentSection->currentOffset) { + fErrorOutput->PrintError( + "_ReadString(): string extends beyond %s end\n", + fCurrentSection->name); + return B_BAD_DATA; + } + + _string = string; + if (_stringLength != NULL) + *_stringLength = stringLength; + + fCurrentSection->currentOffset += stringLength + 1; + return B_OK; +} + + +status_t +ReaderImplBase::_ReadSectionBuffer(void* buffer, size_t size) +{ + if (size > fCurrentSection->uncompressedLength + - fCurrentSection->currentOffset) { + fErrorOutput->PrintError("_ReadBuffer(%lu): read beyond %s end\n", + size, fCurrentSection->name); + return B_BAD_DATA; + } + + memcpy(buffer, fCurrentSection->data + fCurrentSection->currentOffset, + size); + fCurrentSection->currentOffset += size; + return B_OK; +} + + +status_t +ReaderImplBase::ReadBuffer(off_t offset, void* buffer, size_t size) +{ + ssize_t bytesRead = pread(fFD, buffer, size, offset); + if (bytesRead < 0) { + fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: " + "%s\n", buffer, size, strerror(errno)); + return errno; + } + if ((size_t)bytesRead != size) { + fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read all " + "data\n", buffer, size); + return B_ERROR; + } + + return B_OK; +} + + +status_t +ReaderImplBase::ReadCompressedBuffer(const SectionInfo& section) +{ + uint32 compressedSize = section.compressedLength; + uint64 offset = section.offset; + + switch (section.compression) { + case B_HPKG_COMPRESSION_NONE: + return ReadBuffer(offset, section.data, compressedSize); + + case B_HPKG_COMPRESSION_ZLIB: + { + // init the decompressor + BBufferDataOutput bufferOutput(section.data, + section.uncompressedLength); + ZlibDecompressor decompressor(&bufferOutput); + status_t error = decompressor.Init(); + if (error != B_OK) + return error; + + while (compressedSize > 0) { + // read compressed buffer + size_t toRead = std::min(compressedSize, fScratchBufferSize); + error = ReadBuffer(offset, fScratchBuffer, toRead); + if (error != B_OK) + return error; + + // uncompress + error = decompressor.DecompressNext(fScratchBuffer, toRead); + if (error != B_OK) + return error; + + compressedSize -= toRead; + offset += toRead; + } + + error = decompressor.Finish(); + if (error != B_OK) + return error; + + // verify that all data have been read + if (bufferOutput.BytesWritten() != section.uncompressedLength) { + fErrorOutput->PrintError("Error: Missing bytes in uncompressed " + "buffer!\n"); + return B_BAD_DATA; + } + + return B_OK; + } + + default: + return B_BAD_DATA; + } +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit