diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h index f173a6b402..fe251536aa 100644 --- a/headers/private/package/hpkg/PackageWriterImpl.h +++ b/headers/private/package/hpkg/PackageWriterImpl.h @@ -61,18 +61,6 @@ private: const char* name, size_t nameLength, bool isImplicit); - void _RegisterPackageInfo( - PackageAttributeList& attributeList, - const BPackageInfo& packageInfo); - void _RegisterPackageVersion( - PackageAttributeList& attributeList, - const BPackageVersion& version); - void _RegisterPackageResolvableExpressionList( - PackageAttributeList& attributeList, - const BObjectList< - BPackageResolvableExpression>& list, - uint8 id); - void _WriteTOC(hpkg_header& header); int32 _WriteTOCSections(uint64& _attributeTypesSize, uint64& _stringsSize, uint64& _mainSize); @@ -116,6 +104,9 @@ private: off_t fHeapOffset; off_t fHeapEnd; + void* fDataBuffer; + const size_t fDataBufferSize; + Entry* fRootEntry; Attribute* fRootAttribute; diff --git a/headers/private/package/hpkg/RepositoryWriterImpl.h b/headers/private/package/hpkg/RepositoryWriterImpl.h new file mode 100644 index 0000000000..384151af03 --- /dev/null +++ b/headers/private/package/hpkg/RepositoryWriterImpl.h @@ -0,0 +1,59 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PRIVATE__REPOSITORY_WRITER_IMPL_H_ +#define _PACKAGE__HPKG__PRIVATE__REPOSITORY_WRITER_IMPL_H_ + + +#include +#include + +#include +#include +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +class BDataReader; +class BErrorOutput; + + +namespace BPrivate { + + +struct hpkg_header; + +class RepositoryWriterImpl : public WriterImplBase { +public: + RepositoryWriterImpl( + BRepositoryWriterListener* listener); + ~RepositoryWriterImpl(); + + status_t Init(const char* fileName); + status_t AddPackage(const BPackageInfo& packageInfo); + status_t Finish(); + +private: + status_t _Init(const char* fileName); + status_t _AddPackage(const BPackageInfo& packageInfo); + status_t _Finish(); + +private: + BRepositoryWriterListener* fListener; + +}; + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PRIVATE__REPOSITORY_WRITER_IMPL_H_ diff --git a/headers/private/package/hpkg/WriterImplBase.h b/headers/private/package/hpkg/WriterImplBase.h index 8027c6af04..33af107a50 100644 --- a/headers/private/package/hpkg/WriterImplBase.h +++ b/headers/private/package/hpkg/WriterImplBase.h @@ -93,9 +93,9 @@ protected: }; - struct DataWriter { - DataWriter(); - virtual ~DataWriter(); + struct AbstractDataWriter { + AbstractDataWriter(); + virtual ~AbstractDataWriter(); uint64 BytesWritten() const; @@ -109,7 +109,7 @@ protected: }; - struct FDDataWriter : DataWriter { + struct FDDataWriter : AbstractDataWriter { FDDataWriter(int fd, off_t offset, BErrorOutput* errorOutput); virtual status_t WriteDataNoThrow(const void* buffer, @@ -124,8 +124,8 @@ protected: }; - struct ZlibDataWriter : DataWriter, private BDataOutput { - ZlibDataWriter(DataWriter* dataWriter); + struct ZlibDataWriter : AbstractDataWriter, private BDataOutput { + ZlibDataWriter(AbstractDataWriter* dataWriter); void Init(); @@ -139,8 +139,8 @@ protected: virtual status_t WriteData(const void* buffer, size_t size); private: - DataWriter* fDataWriter; - ZlibCompressor fCompressor; + AbstractDataWriter* fDataWriter; + ZlibCompressor fCompressor; }; @@ -149,11 +149,24 @@ protected: protected: status_t Init(const char* fileName, const char* type); + void RegisterPackageInfo( + PackageAttributeList& attributeList, + const BPackageInfo& packageInfo); + void RegisterPackageVersion( + PackageAttributeList& attributeList, + const BPackageVersion& version); + void RegisterPackageResolvableExpressionList( + PackageAttributeList& attributeList, + const BObjectList< + BPackageResolvableExpression>& list, + uint8 id); + int32 WriteCachedStrings(const StringCache& cache, uint32 minUsageCount); - void WritePackageAttributes( - const PackageAttributeList& attributes); + int32 WritePackageAttributes( + const PackageAttributeList& attributes, + uint32& _stringsLengthUncompressed); void WritePackageVersion( const BPackageVersion& version); void WritePackageResolvableExpressionList( @@ -172,30 +185,40 @@ protected: void WriteBuffer(const void* buffer, size_t size, off_t offset); -protected: + int FD() const; + AbstractDataWriter* DataWriter() const; + const PackageAttributeList& PackageAttributes() const; + PackageAttributeList& PackageAttributes(); + + void SetDataWriter(AbstractDataWriter* dataWriter); + void SetFinished(bool finished); + +private: + void _WritePackageAttributes( + const PackageAttributeList& attributes); + +private: BErrorOutput* fErrorOutput; const char* fFileName; int fFD; bool fFinished; - void* fDataBuffer; - const size_t fDataBufferSize; - DataWriter* fDataWriter; + AbstractDataWriter* fDataWriter; StringCache fPackageStringCache; - DoublyLinkedList fPackageAttributes; + PackageAttributeList fPackageAttributes; }; inline uint64 -WriterImplBase::DataWriter::BytesWritten() const +WriterImplBase::AbstractDataWriter::BytesWritten() const { return fBytesWritten; } inline void -WriterImplBase::DataWriter::WriteDataThrows(const void* buffer, size_t size) +WriterImplBase::AbstractDataWriter::WriteDataThrows(const void* buffer, size_t size) { status_t error = WriteDataNoThrow(buffer, size); if (error != B_OK) @@ -224,6 +247,48 @@ WriterImplBase::WriteString(const char* string) } +inline int +WriterImplBase::FD() const +{ + return fFD; +} + + +inline WriterImplBase::AbstractDataWriter* +WriterImplBase::DataWriter() const +{ + return fDataWriter; +} + + +inline void +WriterImplBase::SetDataWriter(AbstractDataWriter* dataWriter) +{ + fDataWriter = dataWriter; +} + + +inline const WriterImplBase::PackageAttributeList& +WriterImplBase::PackageAttributes() const +{ + return fPackageAttributes; +} + + +inline WriterImplBase::PackageAttributeList& +WriterImplBase::PackageAttributes() +{ + return fPackageAttributes; +} + + +inline void +WriterImplBase::SetFinished(bool finished) +{ + fFinished = finished; +} + + } // namespace BPrivate } // namespace BHPKG diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index 637182ebba..2f4520f8f5 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -291,6 +291,8 @@ PackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener) : WriterImplBase(listener), fListener(listener), + fDataBuffer(NULL), + fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB), fRootEntry(NULL), fRootAttribute(NULL), fTopAttribute(NULL), @@ -315,12 +317,6 @@ PackageWriterImpl::~PackageWriterImpl() delete fRootEntry; free(fDataBuffer); - - if (fFD >= 0) - close(fFD); - - if (!fFinished && fFileName != NULL) - unlink(fFileName); } @@ -359,7 +355,7 @@ PackageWriterImpl::AddEntry(const char* fileName) &errorListener); if (result != B_OK || (result = packageInfo.InitCheck()) != B_OK) return result; - _RegisterPackageInfo(fPackageAttributes, packageInfo); + RegisterPackageInfo(PackageAttributes(), packageInfo); } return _RegisterEntry(fileName); @@ -376,7 +372,7 @@ status_t PackageWriterImpl::Finish() { try { - if (fPackageAttributes.IsEmpty()) { + if (PackageAttributes().IsEmpty()) { fListener->PrintError("No package-info file found (%s)!\n", B_HPKG_PACKAGE_INFO_FILE_NAME); return B_BAD_DATA; @@ -398,6 +394,11 @@ PackageWriterImpl::_Init(const char* fileName) if (result != B_OK) return result; + // allocate data buffer + fDataBuffer = malloc(fDataBufferSize); + if (fDataBuffer == NULL) + throw std::bad_alloc(); + if (fStringCache.Init() != B_OK) throw std::bad_alloc(); @@ -455,7 +456,7 @@ PackageWriterImpl::_Finish() // write the header WriteBuffer(&header, sizeof(hpkg_header), 0); - fFinished = true; + SetFinished(true); return B_OK; } @@ -530,195 +531,14 @@ PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name, } -void -PackageWriterImpl::_RegisterPackageInfo(PackageAttributeList& attributeList, - const BPackageInfo& packageInfo) -{ - // name - PackageAttribute* name = new PackageAttribute(HPKG_PACKAGE_ATTRIBUTE_NAME, - B_HPKG_ATTRIBUTE_TYPE_STRING, B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - name->string = fPackageStringCache.Get(packageInfo.Name().String()); - attributeList.Add(name); - - // summary - PackageAttribute* summary = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_SUMMARY, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - summary->string = fPackageStringCache.Get(packageInfo.Summary().String()); - attributeList.Add(summary); - - // description - PackageAttribute* description = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_DESCRIPTION, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - description->string - = fPackageStringCache.Get(packageInfo.Description().String()); - attributeList.Add(description); - - // vendor - PackageAttribute* vendor = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_VENDOR, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - vendor->string = fPackageStringCache.Get(packageInfo.Vendor().String()); - attributeList.Add(vendor); - - // packager - PackageAttribute* packager = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_PACKAGER, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - packager->string = fPackageStringCache.Get(packageInfo.Packager().String()); - attributeList.Add(packager); - - // architecture - PackageAttribute* architecture = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_ARCHITECTURE, B_HPKG_ATTRIBUTE_TYPE_UINT, - B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); - architecture->unsignedInt = packageInfo.Architecture(); - attributeList.Add(packager); - - // version - _RegisterPackageVersion(attributeList, packageInfo.Version()); - - // copyright list - const BObjectList& copyrightList = packageInfo.CopyrightList(); - for (int i = 0; i < copyrightList.CountItems(); ++i) { - PackageAttribute* copyright = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_COPYRIGHT, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - copyright->string - = fPackageStringCache.Get(copyrightList.ItemAt(i)->String()); - attributeList.Add(copyright); - } - - // license list - const BObjectList& licenseList = packageInfo.LicenseList(); - for (int i = 0; i < licenseList.CountItems(); ++i) { - PackageAttribute* license = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_LICENSE, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - license->string - = fPackageStringCache.Get(licenseList.ItemAt(i)->String()); - attributeList.Add(license); - } - - // provides list - const BObjectList& providesList - = packageInfo.ProvidesList(); - for (int i = 0; i < providesList.CountItems(); ++i) { - BPackageResolvable* resolvable = providesList.ItemAt(i); - bool hasVersion = resolvable->Version().InitCheck() == B_OK; - - PackageAttribute* providesType = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_PROVIDES_TYPE, B_HPKG_ATTRIBUTE_TYPE_UINT, - B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); - providesType->unsignedInt = resolvable->Type(); - attributeList.Add(providesType); - - PackageAttribute* provides = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_PROVIDES, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - provides->string = fPackageStringCache.Get(resolvable->Name().String()); - attributeList.Add(provides); - - if (hasVersion) - _RegisterPackageVersion(provides->children, resolvable->Version()); - } - - // requires list - _RegisterPackageResolvableExpressionList(attributeList, - packageInfo.RequiresList(), HPKG_PACKAGE_ATTRIBUTE_REQUIRES); - - // supplements list - _RegisterPackageResolvableExpressionList(attributeList, - packageInfo.SupplementsList(), HPKG_PACKAGE_ATTRIBUTE_SUPPLEMENTS); - - // conflicts list - _RegisterPackageResolvableExpressionList(attributeList, - packageInfo.ConflictsList(), HPKG_PACKAGE_ATTRIBUTE_CONFLICTS); - - // freshens list - _RegisterPackageResolvableExpressionList(attributeList, - packageInfo.FreshensList(), HPKG_PACKAGE_ATTRIBUTE_FRESHENS); - - // replaces list - const BObjectList& replacesList = packageInfo.ReplacesList(); - for (int i = 0; i < replacesList.CountItems(); ++i) { - PackageAttribute* replaces = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_REPLACES, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - replaces->string - = fPackageStringCache.Get(replacesList.ItemAt(i)->String()); - attributeList.Add(replaces); - } -} - - -void -PackageWriterImpl::_RegisterPackageVersion(PackageAttributeList& attributeList, - const BPackageVersion& version) -{ - PackageAttribute* versionMajor = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_VERSION_MAJOR, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - versionMajor->string = fPackageStringCache.Get(version.Major().String()); - attributeList.Add(versionMajor); - - PackageAttribute* versionMinor = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_VERSION_MINOR, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - versionMinor->string = fPackageStringCache.Get(version.Minor().String()); - attributeList.Add(versionMinor); - - PackageAttribute* versionMicro = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_VERSION_MICRO, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - versionMicro->string = fPackageStringCache.Get(version.Micro().String()); - attributeList.Add(versionMicro); - - PackageAttribute* versionRelease = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_VERSION_RELEASE, B_HPKG_ATTRIBUTE_TYPE_UINT, - B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); - versionRelease->unsignedInt = version.Release(); - attributeList.Add(versionRelease); -} - - -void -PackageWriterImpl::_RegisterPackageResolvableExpressionList( - PackageAttributeList& attributeList, - const BObjectList& expressionList, uint8 id) -{ - for (int i = 0; i < expressionList.CountItems(); ++i) { - BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i); - bool hasVersion = resolvableExpr->Version().InitCheck() == B_OK; - - PackageAttribute* name = new PackageAttribute( - (HPKGPackageAttributeID)id, B_HPKG_ATTRIBUTE_TYPE_STRING, - B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); - name->string = fPackageStringCache.Get(resolvableExpr->Name().String()); - attributeList.Add(name); - - if (hasVersion) { - PackageAttribute* op = new PackageAttribute( - HPKG_PACKAGE_ATTRIBUTE_RESOLVABLE_OPERATOR, - B_HPKG_ATTRIBUTE_TYPE_UINT, - B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); - op->unsignedInt = resolvableExpr->Operator(); - name->children.Add(op); - _RegisterPackageVersion(name->children, resolvableExpr->Version()); - } - } -} - - void PackageWriterImpl::_WriteTOC(hpkg_header& header) { // prepare the writer (zlib writer on top of a file writer) off_t startOffset = fHeapEnd; - FDDataWriter realWriter(fFD, startOffset, fListener); + FDDataWriter realWriter(FD(), startOffset, fListener); ZlibDataWriter zlibWriter(&realWriter); - fDataWriter = &zlibWriter; + SetDataWriter(&zlibWriter); zlibWriter.Init(); // write the sections @@ -732,7 +552,7 @@ PackageWriterImpl::_WriteTOC(hpkg_header& header) // finish the writer zlibWriter.Finish(); fHeapEnd = realWriter.Offset(); - fDataWriter = NULL; + SetDataWriter(NULL); off_t endOffset = fHeapEnd; @@ -765,20 +585,20 @@ PackageWriterImpl::_WriteTOCSections(uint64& _attributeTypesSize, uint64& _stringsSize, uint64& _mainSize) { // write the attribute type abbreviations - uint64 attributeTypesOffset = fDataWriter->BytesWritten(); + uint64 attributeTypesOffset = DataWriter()->BytesWritten(); _WriteAttributeTypes(); // write the cached strings - uint64 cachedStringsOffset = fDataWriter->BytesWritten(); + uint64 cachedStringsOffset = DataWriter()->BytesWritten(); int32 cachedStringsWritten = WriteCachedStrings(fStringCache, 2); // write the main TOC section - uint64 mainOffset = fDataWriter->BytesWritten(); + uint64 mainOffset = DataWriter()->BytesWritten(); _WriteAttributeChildren(fRootAttribute); _attributeTypesSize = cachedStringsOffset - attributeTypesOffset; _stringsSize = mainOffset - cachedStringsOffset; - _mainSize = fDataWriter->BytesWritten() - mainOffset; + _mainSize = DataWriter()->BytesWritten() - mainOffset; return cachedStringsWritten; } @@ -845,21 +665,19 @@ PackageWriterImpl::_WritePackageAttributes(hpkg_header& header) { // write the package attributes (zlib writer on top of a file writer) off_t startOffset = fHeapEnd; - FDDataWriter realWriter(fFD, startOffset, fListener); + FDDataWriter realWriter(FD(), startOffset, fListener); ZlibDataWriter zlibWriter(&realWriter); - fDataWriter = &zlibWriter; + SetDataWriter(&zlibWriter); zlibWriter.Init(); - // write the cached strings - uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2); - - // write package attributes tree - off_t attributesOffset = startOffset + fDataWriter->BytesWritten(); - WritePackageAttributes(fPackageAttributes); + // write cached strings and package attributes tree + uint32 stringsLengthUncompressed; + uint32 stringsCount = WritePackageAttributes(PackageAttributes(), + stringsLengthUncompressed); zlibWriter.Finish(); fHeapEnd = realWriter.Offset(); - fDataWriter = NULL; + SetDataWriter(NULL); off_t endOffset = fHeapEnd; @@ -873,10 +691,9 @@ PackageWriterImpl::_WritePackageAttributes(hpkg_header& header) = B_HOST_TO_BENDIAN_INT32(endOffset - startOffset); header.attributes_length_uncompressed = B_HOST_TO_BENDIAN_INT32(zlibWriter.BytesWritten()); - header.attributes_strings_count - = B_HOST_TO_BENDIAN_INT32(stringsCount); + header.attributes_strings_count = B_HOST_TO_BENDIAN_INT32(stringsCount); header.attributes_strings_length - = B_HOST_TO_BENDIAN_INT32(attributesOffset - startOffset); + = B_HOST_TO_BENDIAN_INT32(stringsLengthUncompressed); } @@ -1182,7 +999,7 @@ PackageWriterImpl::_WriteUncompressedData(BDataReader& dataReader, off_t size, } // write to heap - ssize_t bytesWritten = pwrite(fFD, fDataBuffer, toCopy, writeOffset); + ssize_t bytesWritten = pwrite(FD(), fDataBuffer, toCopy, writeOffset); if (bytesWritten < 0) { fListener->PrintError("Failed to write data: %s\n", strerror(errno)); @@ -1267,7 +1084,7 @@ PackageWriterImpl::_WriteZlibCompressedData(BDataReader& dataReader, off_t size, offsetTable[chunkIndex - 1] = writeOffset - dataOffset; // write to heap - ssize_t bytesWritten = pwrite(fFD, writeBuffer, bytesToWrite, + ssize_t bytesWritten = pwrite(FD(), writeBuffer, bytesToWrite, writeOffset); if (bytesWritten < 0) { fListener->PrintError("Failed to write data: %s\n", @@ -1288,7 +1105,7 @@ PackageWriterImpl::_WriteZlibCompressedData(BDataReader& dataReader, off_t size, // write the offset table if (chunkCount > 1) { size_t bytesToWrite = (chunkCount - 1) * sizeof(uint64); - ssize_t bytesWritten = pwrite(fFD, offsetTable, bytesToWrite, + ssize_t bytesWritten = pwrite(FD(), offsetTable, bytesToWrite, offsetTableOffset); if (bytesWritten < 0) { fListener->PrintError("Failed to write data: %s\n", diff --git a/src/kits/package/hpkg/RepositoryWriter.cpp b/src/kits/package/hpkg/RepositoryWriter.cpp new file mode 100644 index 0000000000..8fd17c5859 --- /dev/null +++ b/src/kits/package/hpkg/RepositoryWriter.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +BRepositoryWriter::BRepositoryWriter(BRepositoryWriterListener* listener) + : + fImpl(new (std::nothrow) RepositoryWriterImpl(listener)) +{ +} + + +BRepositoryWriter::~BRepositoryWriter() +{ + delete fImpl; +} + + +status_t +BRepositoryWriter::Init(const char* fileName) +{ + if (fImpl == NULL) + return B_NO_MEMORY; + + return fImpl->Init(fileName); +} + + +status_t +BRepositoryWriter::AddPackage(const BPackageInfo& packageInfo) +{ + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->AddPackage(packageInfo); +} + + +status_t +BRepositoryWriter::Finish() +{ + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->Finish(); +} + + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/RepositoryWriterImpl.cpp b/src/kits/package/hpkg/RepositoryWriterImpl.cpp new file mode 100644 index 0000000000..92be760d4a --- /dev/null +++ b/src/kits/package/hpkg/RepositoryWriterImpl.cpp @@ -0,0 +1,590 @@ +/* + * 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 +#include + + +using BPrivate::FileDescriptorCloser; + + +namespace BPackageKit { + +namespace BHPKG { + +namespace BPrivate { + + +RepositoryWriterImpl::RepositoryWriterImpl(BRepositoryWriterListener* listener) + : + fListener(listener), + fFileName(NULL), + fFD(-1), + fFinished(false), + fDataWriter(NULL), + fCachedStrings(NULL) +{ +} + + +RepositoryWriterImpl::~RepositoryWriterImpl() +{ + if (fCachedStrings != NULL) { + CachedString* cachedString = fCachedStrings->Clear(true); + while (cachedString != NULL) { + CachedString* next = cachedString->next; + delete cachedString; + cachedString = next; + } + } + + if (fFD >= 0) + close(fFD); + + if (!fFinished && fFileName != NULL) + unlink(fFileName); +} + + +status_t +RepositoryWriterImpl::Init(const char* fileName) +{ + try { + return _Init(fileName); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fListener->PrintError("Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t +RepositoryWriterImpl::AddPackage(const BPackageInfo& packageInfo) +{ + try { + return _RegisterPackage(packageInfo); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fListener->PrintError("Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t +RepositoryWriterImpl::Finish() +{ + try { + return _Finish(); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fListener->PrintError("Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t +RepositoryWriterImpl::_Init(const char* fileName) +{ + // create hash tables + fCachedStrings = new CachedStringTable; + if (fCachedStrings->Init() != B_OK) + throw std::bad_alloc(); + + // allocate data buffer + fDataBufferSize = 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; + fDataBuffer = malloc(fDataBufferSize); + if (fDataBuffer == NULL) + throw std::bad_alloc(); + + // open file + fFD = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fFD < 0) { + fListener->PrintError("Failed to open package file \"%s\": %s\n", + fileName, strerror(errno)); + return errno; + } + + fFileName = fileName; + + return B_OK; +} + + +status_t +RepositoryWriterImpl::_Finish() +{ + hpkg_repo_header header; + + // write the cached strings and package attributes + _WriteCachedStrings(); + WritePackageAttributes(header); + + off_t totalSize = fHeapEnd; + + fListener->OnPackageSizeInfo(sizeof(hpkg_header), heapSize, + B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed), + B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed), + totalSize); + + // prepare the header + + // general + header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_REPO_MAGIC); + header.header_size = B_HOST_TO_BENDIAN_INT16((uint16)sizeof(header)); + header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_REPO_VERSION); + header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); + + // write the header + _WriteBuffer(&header, sizeof(header), 0); + + fFinished = true; + return B_OK; +} + + +status_t +RepositoryWriterImpl::_AddPackage(const BPackageInfo& packageInfo) +{ +// fPackageInfos.AddItem(packageInfo); + + return B_OK; +} + + +void +RepositoryWriterImpl::_WriteTOC(hpkg_header& header) +{ + // prepare the writer (zlib writer on top of a file writer) + off_t startOffset = fHeapEnd; + FDDataWriter realWriter(fFD, startOffset, fListener); + ZlibDataWriter zlibWriter(&realWriter); + fDataWriter = &zlibWriter; + zlibWriter.Init(); + + // write the sections + uint64 uncompressedAttributeTypesSize; + uint64 uncompressedStringsSize; + uint64 uncompressedMainSize; + int32 cachedStringsWritten = _WriteTOCSections( + uncompressedAttributeTypesSize, uncompressedStringsSize, + uncompressedMainSize); + + // finish the writer + zlibWriter.Finish(); + fHeapEnd = realWriter.Offset(); + fDataWriter = NULL; + + off_t endOffset = fHeapEnd; + + fListener->OnTOCSizeInfo(uncompressedAttributeTypesSize, + uncompressedStringsSize, uncompressedMainSize, + zlibWriter.BytesWritten()); + + // update the header + + // TOC + header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB); + header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64( + endOffset - startOffset); + header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64( + zlibWriter.BytesWritten()); + + header.toc_strings_length = B_HOST_TO_BENDIAN_INT64( + uncompressedStringsSize); + header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten); +} + + +int32 +RepositoryWriterImpl::_WriteTOCSections(uint64& _attributeTypesSize, + uint64& _stringsSize, uint64& _mainSize) +{ + // write the attribute type abbreviations + uint64 attributeTypesOffset = fDataWriter->BytesWritten(); + _WriteAttributeTypes(); + + // write the cached strings + uint64 cachedStringsOffset = fDataWriter->BytesWritten(); + int32 cachedStringsWritten = _WriteCachedStrings(); + + // write the main TOC section + uint64 mainOffset = fDataWriter->BytesWritten(); + _WriteAttributeChildren(fRootAttribute); + + _attributeTypesSize = cachedStringsOffset - attributeTypesOffset; + _stringsSize = mainOffset - cachedStringsOffset; + _mainSize = fDataWriter->BytesWritten() - mainOffset; + + return cachedStringsWritten; +} + + +void +RepositoryWriterImpl::_WritePackageAttributes(hpkg_header& header) +{ + // write the package attributes (zlib writer on top of a file writer) + off_t startOffset = fHeapEnd; + FDDataWriter realWriter(fFD, startOffset, fListener); + ZlibDataWriter zlibWriter(&realWriter); + fDataWriter = &zlibWriter; + zlibWriter.Init(); + + // name + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_NAME, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(fPackageInfo.Name().String()); + + // summary + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_SUMMARY, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(fPackageInfo.Summary().String()); + + // description + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_DESCRIPTION, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(fPackageInfo.Description().String()); + + // vendor + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_VENDOR, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(fPackageInfo.Vendor().String()); + + // packager + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_PACKAGER, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(fPackageInfo.Packager().String()); + + // architecture + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_ARCHITECTURE, B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT, 0)); + _Write(fPackageInfo.Architecture()); + + // version + _WritePackageVersion(fPackageInfo.Version()); + + // copyright list + const BObjectList& copyrightList = fPackageInfo.CopyrightList(); + for (int i = 0; i < copyrightList.CountItems(); ++i) { + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_COPYRIGHT, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(copyrightList.ItemAt(i)->String()); + } + + // license list + const BObjectList& licenseList = fPackageInfo.LicenseList(); + for (int i = 0; i < licenseList.CountItems(); ++i) { + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_LICENSE, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(licenseList.ItemAt(i)->String()); + } + + // provides list + const BObjectList& providesList + = fPackageInfo.ProvidesList(); + for (int i = 0; i < providesList.CountItems(); ++i) { + BPackageResolvable* resolvable = providesList.ItemAt(i); + bool hasVersion = resolvable->Version().InitCheck() == B_OK; + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_PROVIDES_TYPE, B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT, 0)); + _Write((uint8)resolvable->Type()); + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_PROVIDES, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, hasVersion)); + _WriteString(resolvable->Name().String()); + if (hasVersion) { + _WritePackageVersion(resolvable->Version()); + _Write(0); + } + } + + // requires list + _WritePackageResolvableExpressionList(fPackageInfo.RequiresList(), + HPKG_PACKAGE_ATTRIBUTE_REQUIRES); + + // supplements list + _WritePackageResolvableExpressionList(fPackageInfo.SupplementsList(), + HPKG_PACKAGE_ATTRIBUTE_SUPPLEMENTS); + + // conflicts list + _WritePackageResolvableExpressionList(fPackageInfo.ConflictsList(), + HPKG_PACKAGE_ATTRIBUTE_CONFLICTS); + + // freshens list + _WritePackageResolvableExpressionList(fPackageInfo.FreshensList(), + HPKG_PACKAGE_ATTRIBUTE_FRESHENS); + + // replaces list + const BObjectList& replacesList = fPackageInfo.ReplacesList(); + for (int i = 0; i < replacesList.CountItems(); ++i) { + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_REPLACES, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(replacesList.ItemAt(i)->String()); + } + + _Write(0); + + zlibWriter.Finish(); + fHeapEnd = realWriter.Offset(); + fDataWriter = NULL; + + off_t endOffset = fHeapEnd; + + fListener->OnPackageAttributesSizeInfo(zlibWriter.BytesWritten()); + + // update the header + header.attributes_compression + = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB); + header.attributes_length_compressed + = B_HOST_TO_BENDIAN_INT32(endOffset - startOffset); + header.attributes_length_uncompressed + = B_HOST_TO_BENDIAN_INT32(zlibWriter.BytesWritten()); +} + + +void +RepositoryWriterImpl::_WritePackageVersion(const BPackageVersion& version) +{ + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_VERSION_MAJOR, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(version.Major()); + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_VERSION_MINOR, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(version.Minor()); + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_VERSION_MICRO, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, 0)); + _WriteString(version.Micro()); + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_VERSION_RELEASE, B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT, 0)); + _Write(version.Release()); +} + + +void +RepositoryWriterImpl::_WritePackageResolvableExpressionList( + const BObjectList& list, uint8 id) +{ + for (int i = 0; i < list.CountItems(); ++i) { + BPackageResolvableExpression* resolvableExpr = list.ItemAt(i); + bool hasVersion = resolvableExpr->Version().InitCheck() == B_OK; + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + id, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE, hasVersion)); + _WriteString(resolvableExpr->Name().String()); + if (hasVersion) { + _WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + HPKG_PACKAGE_ATTRIBUTE_RESOLVABLE_OPERATOR, + B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT, + 0)); + _Write(resolvableExpr->Operator()); + _WritePackageVersion(resolvableExpr->Version()); + _Write(0); + } + } +} + + +void +RepositoryWriterImpl::_WriteUnsignedLEB128(uint64 value) +{ + uint8 bytes[10]; + int32 count = 0; + do { + uint8 byte = value & 0x7f; + value >>= 7; + bytes[count++] = byte | (value != 0 ? 0x80 : 0); + } while (value != 0); + + fDataWriter->WriteDataThrows(bytes, count); +} + + +void +RepositoryWriterImpl::_WriteBuffer(const void* buffer, size_t size, off_t offset) +{ + ssize_t bytesWritten = pwrite(fFD, buffer, size, offset); + if (bytesWritten < 0) { + fListener->PrintError( + "_WriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size, + strerror(errno)); + throw status_t(errno); + } + if ((size_t)bytesWritten != size) { + fListener->PrintError( + "_WriteBuffer(%p, %lu) failed to write all data\n", buffer, size); + throw status_t(B_ERROR); + } +} + + +CachedString* +RepositoryWriterImpl::_GetCachedString(const char* value) +{ + CachedString* string = fCachedStrings->Lookup(value); + if (string != NULL) { + string->usageCount++; + return string; + } + + string = new CachedString; + if (!string->Init(value)) { + delete string; + throw std::bad_alloc(); + } + + fCachedStrings->Insert(string); + return string; +} + + +status_t +RepositoryWriterImpl::_WriteZlibCompressedData(BDataReader& dataReader, off_t size, + uint64 writeOffset, uint64& _compressedSize) +{ + // Use zlib compression only for data large enough. + if (size < kZlibCompressionSizeThreshold) + return B_BAD_VALUE; + + // fDataBuffer is 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, so split it into + // two halves we can use for reading and compressing + const size_t chunkSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; + uint8* inputBuffer = (uint8*)fDataBuffer; + uint8* outputBuffer = (uint8*)fDataBuffer + chunkSize; + + // account for the offset table + uint64 chunkCount = (size + (chunkSize - 1)) / chunkSize; + off_t offsetTableOffset = writeOffset; + uint64* offsetTable = NULL; + if (chunkCount > 1) { + offsetTable = new uint64[chunkCount - 1]; + writeOffset = offsetTableOffset + (chunkCount - 1) * sizeof(uint64); + } + ArrayDeleter offsetTableDeleter(offsetTable); + + const uint64 dataOffset = writeOffset; + const uint64 dataEndLimit = offsetTableOffset + size; + + // read the data, compress them and write them to the heap + off_t readOffset = 0; + off_t remainingSize = size; + uint64 chunkIndex = 0; + while (remainingSize > 0) { + // read data + size_t toCopy = std::min(remainingSize, (off_t)chunkSize); + status_t error = dataReader.ReadData(readOffset, inputBuffer, toCopy); + if (error != B_OK) { + fListener->PrintError("Failed to read data: %s\n", strerror(error)); + return error; + } + + // compress + size_t compressedSize; + error = ZlibCompressor::CompressSingleBuffer(inputBuffer, toCopy, + outputBuffer, toCopy, compressedSize); + + const void* writeBuffer; + size_t bytesToWrite; + if (error == B_OK) { + writeBuffer = outputBuffer; + bytesToWrite = compressedSize; + } else { + if (error != B_BUFFER_OVERFLOW) + return error; + writeBuffer = inputBuffer; + bytesToWrite = toCopy; + } + + // check the total compressed data size + if (writeOffset + bytesToWrite >= dataEndLimit) + return B_BUFFER_OVERFLOW; + + if (chunkIndex > 0) + offsetTable[chunkIndex - 1] = writeOffset - dataOffset; + + // write to heap + ssize_t bytesWritten = pwrite(fFD, writeBuffer, bytesToWrite, + writeOffset); + if (bytesWritten < 0) { + fListener->PrintError("Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != bytesToWrite) { + fListener->PrintError("Failed to write all data\n"); + return B_ERROR; + } + + remainingSize -= toCopy; + readOffset += toCopy; + writeOffset += bytesToWrite; + chunkIndex++; + } + + // write the offset table + if (chunkCount > 1) { + size_t bytesToWrite = (chunkCount - 1) * sizeof(uint64); + ssize_t bytesWritten = pwrite(fFD, offsetTable, bytesToWrite, + offsetTableOffset); + if (bytesWritten < 0) { + fListener->PrintError("Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != bytesToWrite) { + fListener->PrintError("Failed to write all data\n"); + return B_ERROR; + } + } + + _compressedSize = writeOffset - offsetTableOffset; + return B_OK; +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp index 6cc287d691..30854563b8 100644 --- a/src/kits/package/hpkg/WriterImplBase.cpp +++ b/src/kits/package/hpkg/WriterImplBase.cpp @@ -176,17 +176,17 @@ WriterImplBase::AttributeValue::_ApplicableIntEncoding(uint64 value) } -// #pragma mark - DataWriter +// #pragma mark - AbstractDataWriter -WriterImplBase::DataWriter::DataWriter() +WriterImplBase::AbstractDataWriter::AbstractDataWriter() : fBytesWritten(0) { } -WriterImplBase::DataWriter::~DataWriter() +WriterImplBase::AbstractDataWriter::~AbstractDataWriter() { } @@ -230,7 +230,7 @@ WriterImplBase::FDDataWriter::WriteDataNoThrow(const void* buffer, size_t size) // #pragma mark - ZlibDataWriter -WriterImplBase::ZlibDataWriter::ZlibDataWriter(DataWriter* dataWriter) +WriterImplBase::ZlibDataWriter::ZlibDataWriter(AbstractDataWriter* dataWriter) : fDataWriter(dataWriter), fCompressor(this) @@ -316,8 +316,6 @@ WriterImplBase::WriterImplBase(BErrorOutput* errorOutput) fFileName(NULL), fFD(-1), fFinished(false), - fDataBuffer(NULL), - fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB), fDataWriter(NULL) { } @@ -339,11 +337,6 @@ WriterImplBase::Init(const char* fileName, const char* type) if (fPackageStringCache.Init() != B_OK) throw std::bad_alloc(); - // allocate data buffer - fDataBuffer = malloc(fDataBufferSize); - if (fDataBuffer == NULL) - throw std::bad_alloc(); - // open file fFD = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); @@ -359,6 +352,187 @@ WriterImplBase::Init(const char* fileName, const char* type) } +void +WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList, + const BPackageInfo& packageInfo) +{ + // name + PackageAttribute* name = new PackageAttribute(HPKG_PACKAGE_ATTRIBUTE_NAME, + B_HPKG_ATTRIBUTE_TYPE_STRING, B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + name->string = fPackageStringCache.Get(packageInfo.Name().String()); + attributeList.Add(name); + + // summary + PackageAttribute* summary = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_SUMMARY, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + summary->string = fPackageStringCache.Get(packageInfo.Summary().String()); + attributeList.Add(summary); + + // description + PackageAttribute* description = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_DESCRIPTION, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + description->string + = fPackageStringCache.Get(packageInfo.Description().String()); + attributeList.Add(description); + + // vendor + PackageAttribute* vendor = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_VENDOR, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + vendor->string = fPackageStringCache.Get(packageInfo.Vendor().String()); + attributeList.Add(vendor); + + // packager + PackageAttribute* packager = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_PACKAGER, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + packager->string = fPackageStringCache.Get(packageInfo.Packager().String()); + attributeList.Add(packager); + + // architecture + PackageAttribute* architecture = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_ARCHITECTURE, B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); + architecture->unsignedInt = packageInfo.Architecture(); + attributeList.Add(packager); + + // version + RegisterPackageVersion(attributeList, packageInfo.Version()); + + // copyright list + const BObjectList& copyrightList = packageInfo.CopyrightList(); + for (int i = 0; i < copyrightList.CountItems(); ++i) { + PackageAttribute* copyright = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_COPYRIGHT, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + copyright->string + = fPackageStringCache.Get(copyrightList.ItemAt(i)->String()); + attributeList.Add(copyright); + } + + // license list + const BObjectList& licenseList = packageInfo.LicenseList(); + for (int i = 0; i < licenseList.CountItems(); ++i) { + PackageAttribute* license = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_LICENSE, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + license->string + = fPackageStringCache.Get(licenseList.ItemAt(i)->String()); + attributeList.Add(license); + } + + // provides list + const BObjectList& providesList + = packageInfo.ProvidesList(); + for (int i = 0; i < providesList.CountItems(); ++i) { + BPackageResolvable* resolvable = providesList.ItemAt(i); + bool hasVersion = resolvable->Version().InitCheck() == B_OK; + + PackageAttribute* providesType = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_PROVIDES_TYPE, B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); + providesType->unsignedInt = resolvable->Type(); + attributeList.Add(providesType); + + PackageAttribute* provides = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_PROVIDES, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + provides->string = fPackageStringCache.Get(resolvable->Name().String()); + attributeList.Add(provides); + + if (hasVersion) + RegisterPackageVersion(provides->children, resolvable->Version()); + } + + // requires list + RegisterPackageResolvableExpressionList(attributeList, + packageInfo.RequiresList(), HPKG_PACKAGE_ATTRIBUTE_REQUIRES); + + // supplements list + RegisterPackageResolvableExpressionList(attributeList, + packageInfo.SupplementsList(), HPKG_PACKAGE_ATTRIBUTE_SUPPLEMENTS); + + // conflicts list + RegisterPackageResolvableExpressionList(attributeList, + packageInfo.ConflictsList(), HPKG_PACKAGE_ATTRIBUTE_CONFLICTS); + + // freshens list + RegisterPackageResolvableExpressionList(attributeList, + packageInfo.FreshensList(), HPKG_PACKAGE_ATTRIBUTE_FRESHENS); + + // replaces list + const BObjectList& replacesList = packageInfo.ReplacesList(); + for (int i = 0; i < replacesList.CountItems(); ++i) { + PackageAttribute* replaces = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_REPLACES, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + replaces->string + = fPackageStringCache.Get(replacesList.ItemAt(i)->String()); + attributeList.Add(replaces); + } +} + + +void +WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList, + const BPackageVersion& version) +{ + PackageAttribute* versionMajor = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_VERSION_MAJOR, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + versionMajor->string = fPackageStringCache.Get(version.Major().String()); + attributeList.Add(versionMajor); + + PackageAttribute* versionMinor = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_VERSION_MINOR, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + versionMinor->string = fPackageStringCache.Get(version.Minor().String()); + attributeList.Add(versionMinor); + + PackageAttribute* versionMicro = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_VERSION_MICRO, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + versionMicro->string = fPackageStringCache.Get(version.Micro().String()); + attributeList.Add(versionMicro); + + PackageAttribute* versionRelease = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_VERSION_RELEASE, B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); + versionRelease->unsignedInt = version.Release(); + attributeList.Add(versionRelease); +} + + +void +WriterImplBase::RegisterPackageResolvableExpressionList( + PackageAttributeList& attributeList, + const BObjectList& expressionList, uint8 id) +{ + for (int i = 0; i < expressionList.CountItems(); ++i) { + BPackageResolvableExpression* resolvableExpr = expressionList.ItemAt(i); + bool hasVersion = resolvableExpr->Version().InitCheck() == B_OK; + + PackageAttribute* name = new PackageAttribute( + (HPKGPackageAttributeID)id, B_HPKG_ATTRIBUTE_TYPE_STRING, + B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE); + name->string = fPackageStringCache.Get(resolvableExpr->Name().String()); + attributeList.Add(name); + + if (hasVersion) { + PackageAttribute* op = new PackageAttribute( + HPKG_PACKAGE_ATTRIBUTE_RESOLVABLE_OPERATOR, + B_HPKG_ATTRIBUTE_TYPE_UINT, + B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT); + op->unsignedInt = resolvableExpr->Operator(); + name->children.Add(op); + RegisterPackageVersion(name->children, resolvableExpr->Version()); + } + } +} + + int32 WriterImplBase::WriteCachedStrings(const StringCache& cache, uint32 minUsageCount) @@ -403,28 +577,18 @@ WriterImplBase::WriteCachedStrings(const StringCache& cache, } -void +int32 WriterImplBase::WritePackageAttributes( - const PackageAttributeList& packageAttributes) + const PackageAttributeList& packageAttributes, + uint32& _stringsLengthUncompressed) { - DoublyLinkedList::ConstIterator it - = packageAttributes.GetIterator(); - while (PackageAttribute* attribute = it.Next()) { - uint8 encoding = attribute->ApplicableEncoding(); + // write the cached strings + uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2); + _stringsLengthUncompressed = DataWriter()->BytesWritten(); - // write tag - WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( - attribute->id, attribute->type, encoding, - !attribute->children.IsEmpty())); + _WritePackageAttributes(packageAttributes); - // write value - WriteAttributeValue(*attribute, encoding); - - if (!attribute->children.IsEmpty()) - WritePackageAttributes(attribute->children); - } - - WriteUnsignedLEB128(0); + return stringsCount; } @@ -526,6 +690,31 @@ WriterImplBase::WriteBuffer(const void* buffer, size_t size, off_t offset) } +void +WriterImplBase::_WritePackageAttributes( + const PackageAttributeList& packageAttributes) +{ + DoublyLinkedList::ConstIterator it + = packageAttributes.GetIterator(); + while (PackageAttribute* attribute = it.Next()) { + uint8 encoding = attribute->ApplicableEncoding(); + + // write tag + WriteUnsignedLEB128(HPKG_PACKAGE_ATTRIBUTE_TAG_COMPOSE( + attribute->id, attribute->type, encoding, + !attribute->children.IsEmpty())); + + // write value + WriteAttributeValue(*attribute, encoding); + + if (!attribute->children.IsEmpty()) + _WritePackageAttributes(attribute->children); + } + + WriteUnsignedLEB128(0); +} + + } // namespace BPrivate } // namespace BHPKG