/* * 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 namespace BPackageKit { namespace BHPKG { namespace BPrivate { //#define TRACE(format...) printf(format) #define TRACE(format...) do {} while (false) // maximum repository info size we support reading static const size_t kMaxRepositoryInfoSize = 1 * 1024 * 1024; // maximum package attributes size we support reading static const size_t kMaxPackageAttributesSize = 64 * 1024 * 1024; // #pragma mark - PackagesAttributeHandler class RepositoryReaderImpl::PackagesAttributeHandler : public AttributeHandler { private: typedef AttributeHandler super; public: PackagesAttributeHandler(BRepositoryContentHandler* contentHandler) : fContentHandler(contentHandler), fPackageName(NULL) { } virtual status_t HandleAttribute(AttributeHandlerContext* context, uint8 id, const AttributeValue& value, AttributeHandler** _handler) { switch (id) { case B_HPKG_ATTRIBUTE_ID_PACKAGE: { status_t error = _NotifyPackageDone(); if (error != B_OK) return error; if (_handler != NULL) { if (fContentHandler != NULL) { error = fContentHandler->HandlePackage(value.string); if (error != B_OK) return error; } *_handler = new(std::nothrow) PackageAttributeHandler; if (*_handler == NULL) return B_NO_MEMORY; fPackageName = value.string; } break; } default: if (context->ignoreUnknownAttributes) break; context->errorOutput->PrintError( "Error: Invalid package attribute section: unexpected " "top level attribute id %d encountered\n", id); return B_BAD_DATA; } return B_OK; } virtual status_t NotifyDone(AttributeHandlerContext* context) { status_t result = _NotifyPackageDone(); if (result == B_OK) result = super::NotifyDone(context); return result; } private: status_t _NotifyPackageDone() { if (fPackageName == NULL || fContentHandler == NULL) return B_OK; status_t error = fContentHandler->HandlePackageDone(fPackageName); fPackageName = NULL; return error; } private: BRepositoryContentHandler* fContentHandler; const char* fPackageName; }; // #pragma mark - PackageContentHandlerAdapter class RepositoryReaderImpl::PackageContentHandlerAdapter : public BPackageContentHandler { public: PackageContentHandlerAdapter(BRepositoryContentHandler* contentHandler) : fContentHandler(contentHandler) { } virtual status_t HandleEntry(BPackageEntry* entry) { return B_OK; } virtual status_t HandleEntryAttribute(BPackageEntry* entry, BPackageEntryAttribute* attribute) { return B_OK; } virtual status_t HandleEntryDone(BPackageEntry* entry) { return B_OK; } virtual status_t HandlePackageAttribute( const BPackageInfoAttributeValue& value) { return fContentHandler->HandlePackageAttribute(value); } virtual void HandleErrorOccurred() { return fContentHandler->HandleErrorOccurred(); } private: BRepositoryContentHandler* fContentHandler; }; // #pragma mark - RepositoryReaderImpl RepositoryReaderImpl::RepositoryReaderImpl(BErrorOutput* errorOutput) : inherited("repository", errorOutput) { } RepositoryReaderImpl::~RepositoryReaderImpl() { } status_t RepositoryReaderImpl::Init(const char* fileName) { // open file int fd = open(fileName, O_RDONLY); if (fd < 0) { ErrorOutput()->PrintError( "Error: Failed to open repository file \"%s\": %s\n", fileName, strerror(errno)); return errno; } return Init(fd, true); } status_t RepositoryReaderImpl::Init(int fd, bool keepFD) { BFdIO* file = new(std::nothrow) BFdIO(fd, keepFD); if (file == NULL) { if (keepFD && fd >= 0) close(fd); return B_NO_MEMORY; } return Init(file, true); } status_t RepositoryReaderImpl::Init(BPositionIO* file, bool keepFile) { hpkg_repo_header header; status_t error = inherited::Init(file, keepFile, header, 0); if (error != B_OK) return error; // init package attributes section error = InitSection(fPackageAttributesSection, UncompressedHeapSize(), B_BENDIAN_TO_HOST_INT64(header.packages_length), kMaxPackageAttributesSize, B_BENDIAN_TO_HOST_INT64(header.packages_strings_length), B_BENDIAN_TO_HOST_INT64(header.packages_strings_count)); if (error != B_OK) return error; // init repository info section PackageFileSection repositoryInfoSection("repository info"); error = InitSection(repositoryInfoSection, fPackageAttributesSection.offset, B_BENDIAN_TO_HOST_INT32(header.info_length), kMaxRepositoryInfoSize, 0, 0); if (error != B_OK) return error; // prepare the sections for use error = PrepareSection(repositoryInfoSection); if (error != B_OK) return error; error = PrepareSection(fPackageAttributesSection); if (error != B_OK) return error; // unarchive repository info BMessage repositoryInfoArchive; error = repositoryInfoArchive.Unflatten((char*)repositoryInfoSection.data); if (error != B_OK) { ErrorOutput()->PrintError( "Error: Unable to unflatten repository info archive!\n"); return error; } error = fRepositoryInfo.SetTo(&repositoryInfoArchive); if (error != B_OK) { ErrorOutput()->PrintError( "Error: Unable to unarchive repository info!\n"); return error; } return B_OK; } status_t RepositoryReaderImpl::GetRepositoryInfo(BRepositoryInfo* _repositoryInfo) const { if (_repositoryInfo == NULL) return B_BAD_VALUE; *_repositoryInfo = fRepositoryInfo; return B_OK; } status_t RepositoryReaderImpl::ParseContent(BRepositoryContentHandler* contentHandler) { status_t result = contentHandler->HandleRepositoryInfo(fRepositoryInfo); if (result == B_OK) { PackageContentHandlerAdapter contentHandlerAdapter(contentHandler); AttributeHandlerContext context(ErrorOutput(), contentHandler != NULL ? &contentHandlerAdapter : NULL, B_HPKG_SECTION_PACKAGE_ATTRIBUTES, MinorFormatVersion() > B_HPKG_REPO_MINOR_VERSION); PackagesAttributeHandler rootAttributeHandler(contentHandler); result = ParsePackageAttributesSection(&context, &rootAttributeHandler); } return result; } } // namespace BPrivate } // namespace BHPKG } // namespace BPackageKit