/* * Copyright 2009-2014, 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 #include #include namespace BPackageKit { namespace BHPKG { namespace BPrivate { static const uint16 kAttributeTypes[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT] = { #define B_DEFINE_HPKG_ATTRIBUTE(id, type, name, constant) \ B_HPKG_ATTRIBUTE_TYPE_##type, #include #undef B_DEFINE_HPKG_ATTRIBUTE }; // #pragma mark - AttributeHandlerContext ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext( BErrorOutput* errorOutput, BPackageContentHandler* packageContentHandler, BHPKGPackageSectionID section, bool ignoreUnknownAttributes) : errorOutput(errorOutput), packageContentHandler(packageContentHandler), hasLowLevelHandler(false), ignoreUnknownAttributes(ignoreUnknownAttributes), section(section) { } ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext( BErrorOutput* errorOutput, BLowLevelPackageContentHandler* lowLevelHandler, BHPKGPackageSectionID section, bool ignoreUnknownAttributes) : errorOutput(errorOutput), lowLevelHandler(lowLevelHandler), hasLowLevelHandler(true), ignoreUnknownAttributes(ignoreUnknownAttributes), section(section) { } 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::NotifyDone( AttributeHandlerContext* context) { return B_OK; } status_t ReaderImplBase::AttributeHandler::Delete(AttributeHandlerContext* context) { delete this; return B_OK; } // #pragma mark - PackageInfoAttributeHandlerBase ReaderImplBase::PackageInfoAttributeHandlerBase ::PackageInfoAttributeHandlerBase( BPackageInfoAttributeValue& packageInfoValue) : fPackageInfoValue(packageInfoValue) { } status_t ReaderImplBase::PackageInfoAttributeHandlerBase::NotifyDone( AttributeHandlerContext* context) { status_t error = context->packageContentHandler->HandlePackageAttribute( fPackageInfoValue); if (context->ignoreUnknownAttributes && error == B_NOT_SUPPORTED) error = B_OK; // Safe to skip a future/unknown attribute. fPackageInfoValue.Clear(); return error; } // #pragma mark - PackageVersionAttributeHandler ReaderImplBase::PackageVersionAttributeHandler::PackageVersionAttributeHandler( BPackageInfoAttributeValue& packageInfoValue, BPackageVersionData& versionData, bool notify) : super(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_PRE_RELEASE: fPackageVersionData.preRelease = value.string; break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION: fPackageVersionData.revision = value.unsignedInt; break; default: if (context->ignoreUnknownAttributes) break; 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::NotifyDone( AttributeHandlerContext* context) { if (!fNotify) return B_OK; fPackageInfoValue.attributeID = B_PACKAGE_INFO_VERSION; return super::NotifyDone(context); } // #pragma mark - PackageResolvableAttributeHandler ReaderImplBase::PackageResolvableAttributeHandler ::PackageResolvableAttributeHandler( BPackageInfoAttributeValue& packageInfoValue) : super(packageInfoValue) { } status_t ReaderImplBase::PackageResolvableAttributeHandler::HandleAttribute( AttributeHandlerContext* context, uint8 id, const AttributeValue& value, AttributeHandler** _handler) { switch (id) { 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; case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE: fPackageInfoValue.resolvable.haveCompatibleVersion = true; fPackageInfoValue.resolvable.compatibleVersion.major = value.string; if (_handler != NULL) { *_handler = new(std::nothrow) PackageVersionAttributeHandler( fPackageInfoValue, fPackageInfoValue.resolvable.compatibleVersion, false); if (*_handler == NULL) return B_NO_MEMORY; } break; default: if (context->ignoreUnknownAttributes) break; 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; } // #pragma mark - PackageResolvableExpressionAttributeHandler ReaderImplBase::PackageResolvableExpressionAttributeHandler ::PackageResolvableExpressionAttributeHandler( BPackageInfoAttributeValue& packageInfoValue) : super(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: if (context->ignoreUnknownAttributes) break; 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; } // #pragma mark - GlobalWritableFileInfoAttributeHandler ReaderImplBase::GlobalWritableFileInfoAttributeHandler ::GlobalWritableFileInfoAttributeHandler( BPackageInfoAttributeValue& packageInfoValue) : super(packageInfoValue) { } status_t ReaderImplBase::GlobalWritableFileInfoAttributeHandler::HandleAttribute( AttributeHandlerContext* context, uint8 id, const AttributeValue& value, AttributeHandler** _handler) { switch (id) { case B_HPKG_ATTRIBUTE_ID_PACKAGE_WRITABLE_FILE_UPDATE_TYPE: if (value.unsignedInt >= B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT) { context->errorOutput->PrintError( "Error: Invalid package attribute section: invalid " "global settings file update type %" B_PRIu64 " encountered\n", value.unsignedInt); return B_BAD_DATA; } fPackageInfoValue.globalWritableFileInfo.updateType = (BWritableFileUpdateType)value.unsignedInt; break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_IS_WRITABLE_DIRECTORY: fPackageInfoValue.globalWritableFileInfo.isDirectory = value.unsignedInt != 0; break; default: if (context->ignoreUnknownAttributes) break; context->errorOutput->PrintError("Error: Invalid package " "attribute section: unexpected package attribute id %d " "encountered when parsing global settings file info\n", id); return B_BAD_DATA; } return B_OK; } // #pragma mark - UserSettingsFileInfoAttributeHandler ReaderImplBase::UserSettingsFileInfoAttributeHandler ::UserSettingsFileInfoAttributeHandler( BPackageInfoAttributeValue& packageInfoValue) : super(packageInfoValue) { } status_t ReaderImplBase::UserSettingsFileInfoAttributeHandler::HandleAttribute( AttributeHandlerContext* context, uint8 id, const AttributeValue& value, AttributeHandler** _handler) { switch (id) { case B_HPKG_ATTRIBUTE_ID_PACKAGE_SETTINGS_FILE_TEMPLATE: fPackageInfoValue.userSettingsFileInfo.templatePath = value.string; break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_IS_WRITABLE_DIRECTORY: fPackageInfoValue.userSettingsFileInfo.isDirectory = value.unsignedInt != 0; break; default: if (context->ignoreUnknownAttributes) break; context->errorOutput->PrintError("Error: Invalid package " "attribute section: unexpected package attribute id %d " "encountered when parsing user settings file info\n", id); return B_BAD_DATA; } return B_OK; } // #pragma mark - UserAttributeHandler ReaderImplBase::UserAttributeHandler::UserAttributeHandler( BPackageInfoAttributeValue& packageInfoValue) : super(packageInfoValue), fGroups() { } status_t ReaderImplBase::UserAttributeHandler::HandleAttribute( AttributeHandlerContext* context, uint8 id, const AttributeValue& value, AttributeHandler** _handler) { switch (id) { case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_REAL_NAME: fPackageInfoValue.user.realName = value.string; break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_HOME: fPackageInfoValue.user.home = value.string; break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SHELL: fPackageInfoValue.user.shell = value.string; break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_GROUP: if (!fGroups.Add(value.string)) return B_NO_MEMORY; break; default: if (context->ignoreUnknownAttributes) break; context->errorOutput->PrintError("Error: Invalid package " "attribute section: unexpected package attribute id %d " "encountered when parsing user settings file info\n", id); return B_BAD_DATA; } return B_OK; } status_t ReaderImplBase::UserAttributeHandler::NotifyDone( AttributeHandlerContext* context) { if (!fGroups.IsEmpty()) { fPackageInfoValue.user.groups = fGroups.Elements(); fPackageInfoValue.user.groupCount = fGroups.Count(); } return super::NotifyDone(context); } // #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_BASE_PACKAGE: fPackageInfoValue.SetTo(B_PACKAGE_INFO_BASE_PACKAGE, 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_URL: fPackageInfoValue.SetTo(B_PACKAGE_INFO_URLS, value.string); break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL: fPackageInfoValue.SetTo(B_PACKAGE_INFO_SOURCE_URLS, 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; case B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM: fPackageInfoValue.SetTo(B_PACKAGE_INFO_CHECKSUM, value.string); break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH: fPackageInfoValue.SetTo(B_PACKAGE_INFO_INSTALL_PATH, value.string); break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_GLOBAL_WRITABLE_FILE: fPackageInfoValue.globalWritableFileInfo.path = value.string; fPackageInfoValue.globalWritableFileInfo.updateType = B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT; fPackageInfoValue.attributeID = B_PACKAGE_INFO_GLOBAL_WRITABLE_FILES; if (_handler != NULL) { *_handler = new(std::nothrow) GlobalWritableFileInfoAttributeHandler( fPackageInfoValue); if (*_handler == NULL) return B_NO_MEMORY; } break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SETTINGS_FILE: fPackageInfoValue.userSettingsFileInfo.path = value.string; fPackageInfoValue.attributeID = B_PACKAGE_INFO_USER_SETTINGS_FILES; if (_handler != NULL) { *_handler = new(std::nothrow) UserSettingsFileInfoAttributeHandler( fPackageInfoValue); if (*_handler == NULL) return B_NO_MEMORY; } break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER: fPackageInfoValue.user.name = value.string; fPackageInfoValue.attributeID = B_PACKAGE_INFO_USERS; if (_handler != NULL) { *_handler = new(std::nothrow) UserAttributeHandler( fPackageInfoValue); if (*_handler == NULL) return B_NO_MEMORY; } break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_GROUP: fPackageInfoValue.SetTo(B_PACKAGE_INFO_GROUPS, value.string); break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_POST_INSTALL_SCRIPT: fPackageInfoValue.SetTo(B_PACKAGE_INFO_POST_INSTALL_SCRIPTS, value.string); break; case B_HPKG_ATTRIBUTE_ID_PACKAGE_PRE_UNINSTALL_SCRIPT: fPackageInfoValue.SetTo(B_PACKAGE_INFO_PRE_UNINSTALL_SCRIPTS, value.string); break; default: if (context->ignoreUnknownAttributes) break; 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); if (context->ignoreUnknownAttributes && error == B_NOT_SUPPORTED) error = B_OK; // Safe to skip a future/unknown attribute. fPackageInfoValue.Clear(); if (error != B_OK) return error; } return B_OK; } // #pragma mark - LowLevelAttributeHandler ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler() : fParentToken(NULL), fToken(NULL), fID(B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { } ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler(uint8 id, const BPackageAttributeValue& value, void* parentToken, void* token) : fParentToken(NULL), 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, fToken, token); if (*_handler == NULL) { context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id, value, fToken, token); return B_NO_MEMORY; } return B_OK; } // no children -- just call the done hook return context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id, value, fToken, token); } status_t ReaderImplBase::LowLevelAttributeHandler::NotifyDone( AttributeHandlerContext* context) { if (fID != B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { status_t error = context->lowLevelHandler->HandleAttributeDone( (BHPKGAttributeID)fID, fValue, fParentToken, fToken); if (error != B_OK) return error; } return super::NotifyDone(context); } // #pragma mark - ReaderImplBase ReaderImplBase::ReaderImplBase(const char* fileType, BErrorOutput* errorOutput) : fPackageAttributesSection("package attributes"), fFileType(fileType), fErrorOutput(errorOutput), fFile(NULL), fOwnsFile(false), fRawHeapReader(NULL), fHeapReader(NULL), fCurrentSection(NULL) { } ReaderImplBase::~ReaderImplBase() { delete fHeapReader; if (fRawHeapReader != fHeapReader) delete fRawHeapReader; if (fOwnsFile) delete fFile; } uint64 ReaderImplBase::UncompressedHeapSize() const { return fRawHeapReader->UncompressedHeapSize(); } BAbstractBufferedDataReader* ReaderImplBase::DetachHeapReader(PackageFileHeapReader*& _rawHeapReader) { BAbstractBufferedDataReader* heapReader = fHeapReader; _rawHeapReader = fRawHeapReader; fHeapReader = NULL; fRawHeapReader = NULL; return heapReader; } status_t ReaderImplBase::InitHeapReader(uint32 compression, uint32 chunkSize, off_t offset, uint64 compressedSize, uint64 uncompressedSize) { DecompressionAlgorithmOwner* decompressionAlgorithm = NULL; BReference decompressionAlgorithmReference; switch (compression) { case B_HPKG_COMPRESSION_NONE: break; case B_HPKG_COMPRESSION_ZLIB: decompressionAlgorithm = DecompressionAlgorithmOwner::Create( new(std::nothrow) BZlibCompressionAlgorithm, new(std::nothrow) BZlibDecompressionParameters); decompressionAlgorithmReference.SetTo(decompressionAlgorithm, true); if (decompressionAlgorithm == NULL || decompressionAlgorithm->algorithm == NULL || decompressionAlgorithm->parameters == NULL) { return B_NO_MEMORY; } break; case B_HPKG_COMPRESSION_ZSTD: decompressionAlgorithm = DecompressionAlgorithmOwner::Create( new(std::nothrow) BZstdCompressionAlgorithm, new(std::nothrow) BZstdDecompressionParameters); decompressionAlgorithmReference.SetTo(decompressionAlgorithm, true); if (decompressionAlgorithm == NULL || decompressionAlgorithm->algorithm == NULL || decompressionAlgorithm->parameters == NULL) { return B_NO_MEMORY; } break; default: fErrorOutput->PrintError("Error: Invalid heap compression\n"); return B_BAD_DATA; } fRawHeapReader = new(std::nothrow) PackageFileHeapReader(fErrorOutput, fFile, offset, compressedSize, uncompressedSize, decompressionAlgorithm); if (fRawHeapReader == NULL) return B_NO_MEMORY; status_t error = fRawHeapReader->Init(); if (error != B_OK) return error; error = CreateCachedHeapReader(fRawHeapReader, fHeapReader); if (error != B_OK) { if (error != B_NOT_SUPPORTED) return error; fHeapReader = fRawHeapReader; } return B_OK; } status_t ReaderImplBase::CreateCachedHeapReader(PackageFileHeapReader* heapReader, BAbstractBufferedDataReader*& _cachedReader) { return B_NOT_SUPPORTED; } status_t ReaderImplBase::InitSection(PackageFileSection& section, uint64 endOffset, uint64 length, uint64 maxSaneLength, uint64 stringsLength, uint64 stringsCount) { // check length vs. endOffset if (length > endOffset) { ErrorOutput()->PrintError("Error: %s file %s section size is %" B_PRIu64 " bytes. This is greater than the available space\n", fFileType, section.name, length); return B_BAD_DATA; } // check sanity length if (maxSaneLength > 0 && length > maxSaneLength) { ErrorOutput()->PrintError("Error: %s file %s section size is %" B_PRIu64 " bytes. This is beyond the reader's sanity limit\n", fFileType, section.name, length); return B_NOT_SUPPORTED; } // check strings subsection size/count if ((stringsLength <= 1) != (stringsCount == 0) || stringsLength > length) { ErrorOutput()->PrintError("Error: strings subsection description of %s " "file %s section is invalid (%" B_PRIu64 " strings, length: %" B_PRIu64 ", section length: %" B_PRIu64 ")\n", fFileType, section.name, stringsCount, stringsLength, length); return B_BAD_DATA; } section.uncompressedLength = length; section.offset = endOffset - length; section.currentOffset = 0; section.stringsLength = stringsLength; section.stringsCount = stringsCount; return B_OK; } status_t ReaderImplBase::PrepareSection(PackageFileSection& section) { // allocate memory for the section data and read it in section.data = new(std::nothrow) uint8[section.uncompressedLength]; if (section.data == NULL) { ErrorOutput()->PrintError("Error: Out of memory!\n"); return B_NO_MEMORY; } status_t error = ReadSection(section); if (error != B_OK) return error; // parse the section strings section.currentOffset = 0; SetCurrentSection(§ion); error = ParseStrings(); if (error != B_OK) return error; return B_OK; } status_t ReaderImplBase::ParseStrings() { // allocate table, if there are any strings if (fCurrentSection->stringsCount == 0) { fCurrentSection->currentOffset += fCurrentSection->stringsLength; return B_OK; } 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); bool sectionHandled; status_t error = ParseAttributeTree(context, sectionHandled); if (error == B_OK && sectionHandled) { 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, bool& _sectionHandled) { if (context->hasLowLevelHandler) { bool handleSection = false; status_t error = context->lowLevelHandler->HandleSectionStart( context->section, handleSection); if (error != B_OK) return error; if (!handleSection) { _sectionHandled = false; return B_OK; } } status_t error = _ParseAttributeTree(context); if (context->hasLowLevelHandler) { status_t endError = context->lowLevelHandler->HandleSectionEnd( context->section); if (error == B_OK) error = endError; } _sectionHandled = true; return error; } status_t ReaderImplBase::_Init(BPositionIO* file, bool keepFile) { fFile = file; fOwnsFile = keepFile; return fFile != NULL ? B_OK : B_BAD_VALUE; } 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(); error = handler->NotifyDone(context); if (error != B_OK) return error; 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 = 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 ID _id = attribute_tag_id(tag); if (_id < B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) { if (type != kAttributeTypes[_id]) { fErrorOutput->PrintError("Error: Invalid %s section: " "unexpected type %d for attribute id %d (expected %d)!\n", fCurrentSection->name, type, _id, kAttributeTypes[_id]); return B_BAD_DATA; } } else if (fMinorFormatVersion <= fCurrentMinorFormatVersion) { fErrorOutput->PrintError("Error: Invalid %s section: " "attribute id %d not supported!\n", fCurrentSection->name, _id); return B_BAD_DATA; } // get the value error = ReadAttributeValue(type, attribute_tag_encoding(tag), _value); if (error != B_OK) return error; } if (_hasChildren != NULL) *_hasChildren = 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( "_ReadSectionBuffer(%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) { status_t error = fFile->ReadAtExactly(offset, buffer, size); if (error != B_OK) { fErrorOutput->PrintError("_ReadBuffer(%p, %lu) failed to read data: " "%s\n", buffer, size, strerror(error)); return error; } return B_OK; } status_t ReaderImplBase::ReadSection(const PackageFileSection& section) { return fHeapReader->ReadData(section.offset, section.data, section.uncompressedLength); } } // namespace BPrivate } // namespace BHPKG } // namespace BPackageKit