diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h index 8f013b286f..22e60d8d24 100644 --- a/headers/os/package/hpkg/PackageWriter.h +++ b/headers/os/package/hpkg/PackageWriter.h @@ -35,6 +35,7 @@ public: uint64 uncompressedMainSize, uint64 uncompressedTOCSize) = 0; virtual void OnPackageAttributesSizeInfo( + uint32 stringCount, uint32 uncompressedSize) = 0; virtual void OnPackageSizeInfo(uint32 headerSize, uint64 heapSize, uint64 tocSize, diff --git a/headers/os/package/hpkg/RepositoryWriter.h b/headers/os/package/hpkg/RepositoryWriter.h new file mode 100644 index 0000000000..d262a86e42 --- /dev/null +++ b/headers/os/package/hpkg/RepositoryWriter.h @@ -0,0 +1,62 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__REPOSITORY_WRITER_H_ +#define _PACKAGE__HPKG__REPOSITORY_WRITER_H_ + + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +namespace BPrivate { + class RepositoryWriterImpl; +} +using BPrivate::RepositoryWriterImpl; + + +class BRepositoryWriterListener : public BErrorOutput { +public: + virtual void PrintErrorVarArgs(const char* format, + va_list args) = 0; + + virtual void OnPackageAdded( + const BPackageInfo& packageInfo) = 0; + + virtual void OnPackageAttributesSizeInfo( + uint32 uncompressedSize) = 0; + virtual void OnRepositorySizeInfo(uint32 headerSize, + uint32 packageAttributesSize, + uint64 totalSize) = 0; +}; + + +class BRepositoryWriter { +public: +public: + BRepositoryWriter( + BRepositoryWriterListener* listener); + ~BRepositoryWriter(); + + status_t Init(const char* fileName); + status_t AddPackage(const BPackageInfo& packageInfo); + status_t Finish(); + +private: + RepositoryWriterImpl* fImpl; +}; + + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__REPOSITORY_WRITER_H_ diff --git a/headers/private/package/hpkg/PackageReaderImpl.h b/headers/private/package/hpkg/PackageReaderImpl.h index f81bbdbf4e..7ba2518e3b 100644 --- a/headers/private/package/hpkg/PackageReaderImpl.h +++ b/headers/private/package/hpkg/PackageReaderImpl.h @@ -65,17 +65,22 @@ private: 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; } }; @@ -90,7 +95,8 @@ private: const SectionInfo& section) const; status_t _ParseTOCAttributeTypes(); - status_t _ParseTOCStrings(); + + status_t _ParseStrings(); status_t _ParseContent(AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler); @@ -153,15 +159,12 @@ private: uint64 fTOCAttributeTypesLength; uint64 fTOCAttributeTypesCount; - uint64 fTOCStringsLength; - uint64 fTOCStringsCount; SectionInfo fTOCSection; SectionInfo fPackageAttributesSection; SectionInfo* fCurrentSection; AttributeTypeReference* fAttributeTypes; - char** fStrings; AttributeHandlerList* fAttributeHandlerStack; diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h index 23b5553232..f173a6b402 100644 --- a/headers/private/package/hpkg/PackageWriterImpl.h +++ b/headers/private/package/hpkg/PackageWriterImpl.h @@ -10,9 +10,9 @@ #include #include -#include #include #include +#include namespace BPackageKit { @@ -29,7 +29,7 @@ namespace BPrivate { struct hpkg_header; -class PackageWriterImpl { +class PackageWriterImpl : public WriterImplBase { public: PackageWriterImpl( BPackageWriterListener* listener); @@ -40,18 +40,13 @@ public: status_t Finish(); private: - struct AttributeValue; struct AttributeTypeKey; struct AttributeType; struct AttributeTypeHashDefinition; struct Attribute; struct AttributeTypeUsageGreater; struct Entry; - struct DataWriter; - struct DummyDataWriter; - struct FDDataWriter; struct SubPathAdder; - struct ZlibDataWriter; typedef BOpenHashTable AttributeTypeTable; @@ -66,33 +61,25 @@ private: const char* name, size_t nameLength, bool isImplicit); - void _WriteTOC(hpkg_header& header); - int32 _WriteTOCSections(uint64& _attributeTypesSize, - uint64& _stringsSize, uint64& _mainSize); - void _WriteAttributeTypes(); - int32 _WriteCachedStrings(); - void _WriteAttributeChildren(Attribute* attribute); - - void _WritePackageAttributes(hpkg_header& header); - - void _WriteAttributeValue( - const AttributeValue& value, - uint8 encoding); - void _WriteUnsignedLEB128(uint64 value); - inline void _WriteString(const char* string); - - void _WritePackageVersion( + void _RegisterPackageInfo( + PackageAttributeList& attributeList, + const BPackageInfo& packageInfo); + void _RegisterPackageVersion( + PackageAttributeList& attributeList, const BPackageVersion& version); - void _WritePackageResolvableExpressionList( + void _RegisterPackageResolvableExpressionList( + PackageAttributeList& attributeList, const BObjectList< BPackageResolvableExpression>& list, uint8 id); - template - inline void _Write(const Type& value); + void _WriteTOC(hpkg_header& header); + int32 _WriteTOCSections(uint64& _attributeTypesSize, + uint64& _stringsSize, uint64& _mainSize); + void _WriteAttributeTypes(); + void _WriteAttributeChildren(Attribute* attribute); - void _WriteBuffer(const void* buffer, size_t size, - off_t offset); + void _WritePackageAttributes(hpkg_header& header); void _AddEntry(int dirFD, Entry* entry, const char* fileName, char* pathBuffer); @@ -111,38 +98,30 @@ private: Attribute* _AddDataAttribute(const char* attributeName, uint64 dataSize, const uint8* data); - CachedString* _GetCachedString(const char* value); AttributeType* _GetAttributeType(const char* attributeName, uint8 type); status_t _AddData(BDataReader& dataReader, off_t size); + status_t _WriteUncompressedData(BDataReader& dataReader, off_t size, uint64 writeOffset); - status_t _WriteZlibCompressedData(BDataReader& dataReader, + status_t _WriteZlibCompressedData( + BDataReader& dataReader, off_t size, uint64 writeOffset, uint64& _compressedSize); private: BPackageWriterListener* fListener; - const char* fFileName; - int fFD; - bool fFinished; off_t fHeapOffset; off_t fHeapEnd; - void* fDataBuffer; - size_t fDataBufferSize; - - BPackageInfo fPackageInfo; - - DataWriter* fDataWriter; Entry* fRootEntry; Attribute* fRootAttribute; Attribute* fTopAttribute; - CachedStringTable* fCachedStrings; + StringCache fStringCache; AttributeTypeTable* fAttributeTypes; }; diff --git a/headers/private/package/hpkg/Strings.h b/headers/private/package/hpkg/Strings.h index 275ab183eb..afdbd826e6 100644 --- a/headers/private/package/hpkg/Strings.h +++ b/headers/private/package/hpkg/Strings.h @@ -6,6 +6,8 @@ #define _PACKAGE__HPKG__PRIVATE__STRINGS_H_ +#include + #include @@ -86,6 +88,15 @@ struct CachedStringUsageGreater { }; +struct StringCache : public CachedStringTable { + StringCache(); + ~StringCache(); + + CachedString* Get(const char* value); + +}; + + } // namespace BPrivate } // namespace BHPKG diff --git a/headers/private/package/hpkg/WriterImplBase.h b/headers/private/package/hpkg/WriterImplBase.h new file mode 100644 index 0000000000..8027c6af04 --- /dev/null +++ b/headers/private/package/hpkg/WriterImplBase.h @@ -0,0 +1,234 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _PACKAGE__HPKG__PRIVATE__WRITER_IMPL_BASE_H_ +#define _PACKAGE__HPKG__PRIVATE__WRITER_IMPL_BASE_H_ + + +#include + +#include + +#include +#include +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +class BDataReader; +class BErrorOutput; + + +namespace BPrivate { + + +struct hpkg_header; + +class WriterImplBase { +public: + WriterImplBase(BErrorOutput* errorOutput); + ~WriterImplBase(); + +protected: + + + struct AttributeValue { + union { + int64 signedInt; + uint64 unsignedInt; + CachedString* string; + struct { + uint64 size; + union { + uint64 offset; + uint8 raw[B_HPKG_MAX_INLINE_DATA_SIZE]; + }; + } data; + }; + uint8 type; + int8 encoding; + + AttributeValue(); + ~AttributeValue(); + + void SetTo(int8 value); + void SetTo(uint8 value); + void SetTo(int16 value); + void SetTo(uint16 value); + void SetTo(int32 value); + void SetTo(uint32 value); + void SetTo(int64 value); + void SetTo(uint64 value); + void SetTo(CachedString* value); + void SetToData(uint64 size, uint64 offset); + void SetToData(uint64 size, const void* rawData); + uint8 ApplicableEncoding() const; + + private: + static uint8 _ApplicableIntEncoding(uint64 value); + }; + + + struct PackageAttribute : + public DoublyLinkedListLinkImpl, + public AttributeValue { + HPKGPackageAttributeID id; + DoublyLinkedList children; + + PackageAttribute(HPKGPackageAttributeID id_, uint8 type, + uint8 encoding); + ~PackageAttribute(); + + void AddChild(PackageAttribute* child); + + private: + void _DeleteChildren(); + }; + + + struct DataWriter { + DataWriter(); + virtual ~DataWriter(); + + uint64 BytesWritten() const; + + virtual status_t WriteDataNoThrow(const void* buffer, + size_t size) = 0; + + void WriteDataThrows(const void* buffer, size_t size); + + protected: + uint64 fBytesWritten; + }; + + + struct FDDataWriter : DataWriter { + FDDataWriter(int fd, off_t offset, BErrorOutput* errorOutput); + + virtual status_t WriteDataNoThrow(const void* buffer, + size_t size); + + off_t Offset() const; + + private: + int fFD; + off_t fOffset; + BErrorOutput* fErrorOutput; + }; + + + struct ZlibDataWriter : DataWriter, private BDataOutput { + ZlibDataWriter(DataWriter* dataWriter); + + void Init(); + + void Finish(); + + virtual status_t WriteDataNoThrow(const void* buffer, + size_t size); + + private: + // BDataOutput + virtual status_t WriteData(const void* buffer, size_t size); + + private: + DataWriter* fDataWriter; + ZlibCompressor fCompressor; + }; + + + typedef DoublyLinkedList PackageAttributeList; + +protected: + status_t Init(const char* fileName, const char* type); + + int32 WriteCachedStrings(const StringCache& cache, + uint32 minUsageCount); + + void WritePackageAttributes( + const PackageAttributeList& attributes); + void WritePackageVersion( + const BPackageVersion& version); + void WritePackageResolvableExpressionList( + const BObjectList< + BPackageResolvableExpression>& list, + uint8 id); + + void WriteAttributeValue(const AttributeValue& value, + uint8 encoding); + void WriteUnsignedLEB128(uint64 value); + inline void WriteString(const char* string); + + template + inline void Write(const Type& value); + + void WriteBuffer(const void* buffer, size_t size, + off_t offset); + +protected: + BErrorOutput* fErrorOutput; + const char* fFileName; + int fFD; + bool fFinished; + void* fDataBuffer; + const size_t fDataBufferSize; + + DataWriter* fDataWriter; + + StringCache fPackageStringCache; + DoublyLinkedList fPackageAttributes; +}; + + +inline uint64 +WriterImplBase::DataWriter::BytesWritten() const +{ + return fBytesWritten; +} + + +inline void +WriterImplBase::DataWriter::WriteDataThrows(const void* buffer, size_t size) +{ + status_t error = WriteDataNoThrow(buffer, size); + if (error != B_OK) + throw status_t(error); +} + +inline off_t +WriterImplBase::FDDataWriter::Offset() const +{ + return fOffset; +} + + +template +inline void +WriterImplBase::Write(const Type& value) +{ + fDataWriter->WriteDataThrows(&value, sizeof(Type)); +} + + +inline void +WriterImplBase::WriteString(const char* string) +{ + fDataWriter->WriteDataThrows(string, strlen(string) + 1); +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit + + +#endif // _PACKAGE__HPKG__PRIVATE__WRITER_IMPL_BASE_H_ diff --git a/headers/private/package/hpkg/haiku_package.h b/headers/private/package/hpkg/haiku_package.h index 2a0723772d..5479b8ffa3 100644 --- a/headers/private/package/hpkg/haiku_package.h +++ b/headers/private/package/hpkg/haiku_package.h @@ -29,6 +29,8 @@ struct hpkg_header { uint32 attributes_compression; uint32 attributes_length_compressed; uint32 attributes_length_uncompressed; + uint32 attributes_strings_length; + uint32 attributes_strings_count; // TOC section uint32 toc_compression; diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp index 58aee1fc64..f37ebf9351 100644 --- a/src/bin/package/command_create.cpp +++ b/src/bin/package/command_create.cpp @@ -63,12 +63,14 @@ public: uncompressedTOCSize); } - virtual void OnPackageAttributesSizeInfo(uint32 uncompressedSize) + virtual void OnPackageAttributesSizeInfo(uint32 stringCount, + uint32 uncompressedSize) { if (fQuiet || !fVerbose) return; printf("----- Package Attribute Info -----\n"); + printf("string count: %10ld\n", stringCount); printf("package attributes size: %10ld (uncompressed)\n", uncompressedSize); } diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index 7553e5dd30..96e9280851 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -26,6 +26,7 @@ HPKG_SOURCES = PackageWriter.cpp PackageWriterImpl.cpp Strings.cpp + WriterImplBase.cpp # compression ZlibCompressionBase.cpp diff --git a/src/kits/package/hpkg/PackageReaderImpl.cpp b/src/kits/package/hpkg/PackageReaderImpl.cpp index bba408fe6c..c16bb0c1f3 100644 --- a/src/kits/package/hpkg/PackageReaderImpl.cpp +++ b/src/kits/package/hpkg/PackageReaderImpl.cpp @@ -620,7 +620,6 @@ PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput) fPackageAttributesSection("package attributes section"), fCurrentSection(NULL), fAttributeTypes(NULL), - fStrings(NULL), fScratchBuffer(NULL), fScratchBufferSize(0) { @@ -633,7 +632,6 @@ PackageReaderImpl::~PackageReaderImpl() close(fFD); delete[] fScratchBuffer; - delete[] fStrings; delete[] fAttributeTypes; } @@ -713,6 +711,10 @@ PackageReaderImpl::Init(int fd, bool keepFD) = B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed); fPackageAttributesSection.uncompressedLength = B_BENDIAN_TO_HOST_INT32(header.attributes_length_uncompressed); + fPackageAttributesSection.stringsLength + = B_BENDIAN_TO_HOST_INT32(header.attributes_strings_length); + fPackageAttributesSection.stringsCount + = B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count); if (const char* errorString = _CheckCompression( fPackageAttributesSection)) { @@ -739,14 +741,16 @@ PackageReaderImpl::Init(int fd, bool keepFD) = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_length); fTOCAttributeTypesCount = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_count); - fTOCStringsLength = B_BENDIAN_TO_HOST_INT64(header.toc_strings_length); - fTOCStringsCount = B_BENDIAN_TO_HOST_INT64(header.toc_strings_count); + fTOCSection.stringsLength + = B_BENDIAN_TO_HOST_INT64(header.toc_strings_length); + fTOCSection.stringsCount + = B_BENDIAN_TO_HOST_INT64(header.toc_strings_count); if (fTOCAttributeTypesLength > fTOCSection.uncompressedLength - || fTOCStringsLength + || fTOCSection.stringsLength > fTOCSection.uncompressedLength - fTOCAttributeTypesLength || fTOCAttributeTypesCount > fTOCAttributeTypesLength - || fTOCStringsCount > fTOCStringsLength) { + || fTOCSection.stringsCount > fTOCSection.stringsLength) { fErrorOutput->PrintError("Error: Invalid package file: Invalid TOC " "subsections description\n"); return B_BAD_DATA; @@ -829,10 +833,10 @@ PackageReaderImpl::Init(int fd, bool keepFD) fCurrentSection->currentOffset += fTOCAttributeTypesLength; // strings - error = _ParseTOCStrings(); + error = _ParseStrings(); if (error != B_OK) return error; - fCurrentSection->currentOffset += fTOCStringsLength; + fCurrentSection->currentOffset += fCurrentSection->stringsLength; return B_OK; } @@ -851,6 +855,12 @@ PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler) fCurrentSection = &fPackageAttributesSection; fCurrentSection->currentOffset = 0; + // strings + status_t error = _ParseStrings(); + if (error != B_OK) + return error; + fCurrentSection->currentOffset += fCurrentSection->stringsLength; + return _ParsePackageAttributes(&context); } @@ -916,7 +926,6 @@ PackageReaderImpl::_ParseTOCAttributeTypes() if (position + 1 != sectionEnd) { fErrorOutput->PrintError("Error: Excess bytes in TOC attribute " "types section\n"); -TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); return B_BAD_DATA; } @@ -941,28 +950,30 @@ TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); fAttributeTypes[index].type = type; fAttributeTypes[index].standardIndex = _GetStandardIndex(type); index++; -TRACE("type: %u, \"%s\"\n", type->type, type->name); } } status_t -PackageReaderImpl::_ParseTOCStrings() +PackageReaderImpl::_ParseStrings() { // allocate table - fStrings = new(std::nothrow) char*[fTOCStringsCount]; - if (fStrings == NULL) { + 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*)fTOCSection.data + fTOCSection.currentOffset; - char* sectionEnd = position + fTOCStringsLength; + char* position + = (char*)fCurrentSection->data + fCurrentSection->currentOffset; + char* sectionEnd = position + fCurrentSection->stringsLength; uint32 index = 0; while (true) { if (position >= sectionEnd) { - fErrorOutput->PrintError("Error: Malformed TOC strings section\n"); + fErrorOutput->PrintError("Error: Malformed %s strings section\n", + fCurrentSection->name); return B_BAD_DATA; } @@ -970,29 +981,31 @@ PackageReaderImpl::_ParseTOCStrings() if (stringLength == 0) { if (position + 1 != sectionEnd) { - fErrorOutput->PrintError("Error: Excess bytes in TOC strings " - "section\n"); -TRACE("position: %p, sectionEnd: %p\n", position, sectionEnd); + fErrorOutput->PrintError( + "Error: %ld excess bytes in %s strings section\n", + sectionEnd - (position + 1), fCurrentSection->name); return B_BAD_DATA; } - if (index != fTOCStringsCount) { - fErrorOutput->PrintError("Error: Invalid TOC strings section: " - "Less strings than specified in the header\n"); + 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 >= fTOCStringsCount) { - fErrorOutput->PrintError("Error: Invalid TOC strings section: " - "More strings than specified in the header\n"); + 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; } - fStrings[index++] = position; -TRACE("string: \"%s\"\n", position); + fCurrentSection->strings[index++] = position; position += stringLength + 1; } } @@ -1003,7 +1016,8 @@ PackageReaderImpl::_ParseContent(AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler) { // parse the TOC - fTOCSection.currentOffset = fTOCAttributeTypesLength + fTOCStringsLength; + fTOCSection.currentOffset = fTOCAttributeTypesLength + + fTOCSection.stringsLength; // prepare attribute handler context context->heapOffset = fHeapOffset; @@ -1491,9 +1505,9 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, } default: { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "invalid encoding %d for int value type %d\n", encoding, - type); + fErrorOutput->PrintError("Error: Invalid %s section: " + "invalid encoding %d for int value type %d\n", + fCurrentSection->name, encoding, type); return B_BAD_VALUE; } } @@ -1517,13 +1531,15 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, if (error != B_OK) return error; - if (index > fTOCStringsCount) { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "string reference out of bounds\n"); + 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(fStrings[index]); + _value.SetTo(fCurrentSection->strings[index]); } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) { const char* string; status_t error = _ReadString(string); @@ -1532,8 +1548,8 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, _value.SetTo(string); } else { - fErrorOutput->PrintError("Error: Invalid TOC section: invalid " - "string encoding (%u)\n", encoding); + fErrorOutput->PrintError("Error: Invalid %s section: invalid " + "string encoding (%u)\n", fCurrentSection->name, encoding); return B_BAD_DATA; } @@ -1554,16 +1570,16 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, return error; if (offset > fHeapSize || size > fHeapSize - offset) { - fErrorOutput->PrintError("Error: Invalid TOC section: " - "invalid data reference\n"); + fErrorOutput->PrintError("Error: Invalid %s section: " + "invalid data reference\n", fCurrentSection->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 TOC section: " - "inline data too long\n"); + fErrorOutput->PrintError("Error: Invalid %s section: " + "inline data too long\n", fCurrentSection->name); return B_BAD_DATA; } @@ -1573,8 +1589,8 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, return error; _value.SetToData(size, buffer); } else { - fErrorOutput->PrintError("Error: Invalid TOC section: invalid " - "raw encoding (%u)\n", encoding); + fErrorOutput->PrintError("Error: Invalid %s section: invalid " + "raw encoding (%u)\n", fCurrentSection->name, encoding); return B_BAD_DATA; } @@ -1582,8 +1598,8 @@ PackageReaderImpl::_ReadAttributeValue(uint8 type, uint8 encoding, } default: - fErrorOutput->PrintError("Error: Invalid TOC section: invalid " - "value type: %d\n", type); + fErrorOutput->PrintError("Error: Invalid %s section: invalid " + "value type: %d\n", fCurrentSection->name, type); return B_BAD_DATA; } } diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index d5eceb45fd..637182ebba 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -30,7 +30,6 @@ #include #include #include -#include using BPrivate::FileDescriptorCloser; @@ -50,139 +49,6 @@ static const size_t kZlibCompressionSizeThreshold = 64; // #pragma mark - Attributes -struct PackageWriterImpl::AttributeValue { - union { - int64 signedInt; - uint64 unsignedInt; - CachedString* string; - struct { - uint64 size; - union { - uint64 offset; - uint8 raw[B_HPKG_MAX_INLINE_DATA_SIZE]; - }; - } data; - }; - uint8 type; - int8 encoding; - - AttributeValue() - : - type(B_HPKG_ATTRIBUTE_TYPE_INVALID), - encoding(-1) - { - } - - ~AttributeValue() - { - } - - void SetTo(int8 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint8 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(int16 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint16 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(int32 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint32 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(int64 value) - { - signedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_INT; - } - - void SetTo(uint64 value) - { - unsignedInt = value; - type = B_HPKG_ATTRIBUTE_TYPE_UINT; - } - - void SetTo(CachedString* value) - { - string = value; - type = B_HPKG_ATTRIBUTE_TYPE_STRING; - } - - void SetToData(uint64 size, uint64 offset) - { - data.size = size; - data.offset = offset; - type = B_HPKG_ATTRIBUTE_TYPE_RAW; - encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP; - } - - void SetToData(uint64 size, const void* rawData) - { - data.size = size; - if (size > 0) - memcpy(data.raw, rawData, size); - type = B_HPKG_ATTRIBUTE_TYPE_RAW; - encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE; - } - - uint8 PreferredEncoding() const - { - switch (type) { - case B_HPKG_ATTRIBUTE_TYPE_INT: - return _PreferredIntEncoding(signedInt >= 0 - ? (uint64)signedInt << 1 - : (uint64)(-(signedInt + 1) << 1)); - case B_HPKG_ATTRIBUTE_TYPE_UINT: - return _PreferredIntEncoding(unsignedInt); - case B_HPKG_ATTRIBUTE_TYPE_STRING: - return string->index >= 0 - ? B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE - : B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE; - case B_HPKG_ATTRIBUTE_TYPE_RAW: - return encoding; - default: - return 0; - } - } - -private: - static uint8 _PreferredIntEncoding(uint64 value) - { - if (value <= 0xff) - return B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT; - if (value <= 0xffff) - return B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT; - if (value <= 0xffffffff) - return B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT; - - return B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT; - } -}; - - struct PackageWriterImpl::AttributeTypeKey { const char* name; uint8 type; @@ -293,7 +159,7 @@ struct PackageWriterImpl::AttributeTypeUsageGreater { }; -// #pragma mark - PackageWriterImpl +// #pragma mark - Entry struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { @@ -385,92 +251,7 @@ private: }; -// #pragma mark - DataWriter - - -struct PackageWriterImpl::DataWriter { - DataWriter() - : - fBytesWritten(0) - { - } - - virtual ~DataWriter() - { - } - - uint64 BytesWritten() const - { - return fBytesWritten; - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) = 0; - - inline void WriteDataThrows(const void* buffer, size_t size) - { - status_t error = WriteDataNoThrow(buffer, size); - if (error != B_OK) - throw status_t(error); - } - -protected: - uint64 fBytesWritten; -}; - - -struct PackageWriterImpl::DummyDataWriter : DataWriter { - DummyDataWriter() - { - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) - { - fBytesWritten += size; - return B_OK; - } -}; - - -struct PackageWriterImpl::FDDataWriter : DataWriter { - FDDataWriter(int fd, off_t offset, BPackageWriterListener* listener) - : - fFD(fd), - fOffset(offset), - fListener(listener) - { - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) - { - ssize_t bytesWritten = pwrite(fFD, buffer, size, fOffset); - if (bytesWritten < 0) { - fListener->PrintError( - "_WriteBuffer(%p, %lu) failed to write data: %s\n", - buffer, size, strerror(errno)); - return errno; - } - if ((size_t)bytesWritten != size) { - fListener->PrintError( - "_WriteBuffer(%p, %lu) failed to write all data\n", buffer, - size); - return B_ERROR; - } - - fOffset += size; - fBytesWritten += size; - return B_OK; - } - - off_t Offset() const - { - return fOffset; - } - -private: - int fFD; - off_t fOffset; - BPackageWriterListener* fListener; -}; +// #pragma mark - SubPathAdder struct PackageWriterImpl::SubPathAdder { @@ -490,69 +271,9 @@ private: }; - - -struct PackageWriterImpl::ZlibDataWriter : DataWriter, private BDataOutput { - ZlibDataWriter(DataWriter* dataWriter) - : - fDataWriter(dataWriter), - fCompressor(this) - { - } - - void Init() - { - status_t error = fCompressor.Init(); - if (error != B_OK) - throw status_t(error); - } - - void Finish() - { - status_t error = fCompressor.Finish(); - if (error != B_OK) - throw status_t(error); - } - - virtual status_t WriteDataNoThrow(const void* buffer, size_t size) - { - status_t error = fCompressor.CompressNext(buffer, size); - if (error == B_OK) - fBytesWritten += size; - return error; - } - -private: - // BDataOutput - virtual status_t WriteData(const void* buffer, size_t size) - { - return fDataWriter->WriteDataNoThrow(buffer, size); - } - -private: - DataWriter* fDataWriter; - ZlibCompressor fCompressor; -}; - - // #pragma mark - PackageWriterImpl (Inline Methods) -template -inline void -PackageWriterImpl::_Write(const Type& value) -{ - fDataWriter->WriteDataThrows(&value, sizeof(Type)); -} - - -inline void -PackageWriterImpl::_WriteString(const char* string) -{ - fDataWriter->WriteDataThrows(string, strlen(string) + 1); -} - - template inline PackageWriterImpl::Attribute* PackageWriterImpl::_AddAttribute(const char* attributeName, Type value) @@ -568,16 +289,11 @@ PackageWriterImpl::_AddAttribute(const char* attributeName, Type value) PackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener) : + WriterImplBase(listener), fListener(listener), - fFileName(NULL), - fFD(-1), - fFinished(false), - fDataBuffer(NULL), - fDataWriter(NULL), fRootEntry(NULL), fRootAttribute(NULL), fTopAttribute(NULL), - fCachedStrings(NULL), fAttributeTypes(NULL) { } @@ -596,15 +312,6 @@ PackageWriterImpl::~PackageWriterImpl() } } - if (fCachedStrings != NULL) { - CachedString* cachedString = fCachedStrings->Clear(true); - while (cachedString != NULL) { - CachedString* next = cachedString->next; - delete cachedString; - cachedString = next; - } - } - delete fRootEntry; free(fDataBuffer); @@ -647,10 +354,12 @@ PackageWriterImpl::AddEntry(const char* fileName) BPackageWriterListener* listener; } errorListener(fListener); BEntry packageInfoEntry(fileName); - status_t result = fPackageInfo.ReadFromConfigFile(packageInfoEntry, + BPackageInfo packageInfo; + status_t result = packageInfo.ReadFromConfigFile(packageInfoEntry, &errorListener); - if (result != B_OK || (result = fPackageInfo.InitCheck()) != B_OK) + if (result != B_OK || (result = packageInfo.InitCheck()) != B_OK) return result; + _RegisterPackageInfo(fPackageAttributes, packageInfo); } return _RegisterEntry(fileName); @@ -667,7 +376,7 @@ status_t PackageWriterImpl::Finish() { try { - if (fPackageInfo.InitCheck() != B_OK) { + if (fPackageAttributes.IsEmpty()) { fListener->PrintError("No package-info file found (%s)!\n", B_HPKG_PACKAGE_INFO_FILE_NAME); return B_BAD_DATA; @@ -685,36 +394,22 @@ PackageWriterImpl::Finish() status_t PackageWriterImpl::_Init(const char* fileName) { - // create hash tables - fCachedStrings = new CachedStringTable; - if (fCachedStrings->Init() != B_OK) + status_t result = WriterImplBase::Init(fileName, "package"); + if (result != B_OK) + return result; + + if (fStringCache.Init() != B_OK) throw std::bad_alloc(); fAttributeTypes = new AttributeTypeTable; if (fAttributeTypes->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(); - // create entry list fRootEntry = new Entry(NULL, 0, true); - // 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; - } - fRootAttribute = new Attribute(NULL); - fFileName = fileName; fHeapOffset = fHeapEnd = sizeof(hpkg_header); fTopAttribute = fRootAttribute; @@ -758,7 +453,7 @@ PackageWriterImpl::_Finish() header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); // write the header - _WriteBuffer(&header, sizeof(hpkg_header), 0); + WriteBuffer(&header, sizeof(hpkg_header), 0); fFinished = true; return B_OK; @@ -835,6 +530,187 @@ 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) { @@ -894,7 +770,7 @@ PackageWriterImpl::_WriteTOCSections(uint64& _attributeTypesSize, // write the cached strings uint64 cachedStringsOffset = fDataWriter->BytesWritten(); - int32 cachedStringsWritten = _WriteCachedStrings(); + int32 cachedStringsWritten = WriteCachedStrings(fStringCache, 2); // write the main TOC section uint64 mainOffset = fDataWriter->BytesWritten(); @@ -931,52 +807,12 @@ PackageWriterImpl::_WriteAttributeTypes() AttributeType* attributeType = attributeTypes[i]; attributeType->index = i; - _Write(attributeType->type); - _WriteString(attributeType->name); + Write(attributeType->type); + WriteString(attributeType->name); } // write a terminating 0 byte - _Write(0); -} - - -int32 -PackageWriterImpl::_WriteCachedStrings() -{ - // create an array of the cached strings - int32 count = fCachedStrings->CountElements(); - CachedString** cachedStrings = new CachedString*[count]; - ArrayDeleter cachedStringsDeleter(cachedStrings); - - int32 index = 0; - for (CachedStringTable::Iterator it = fCachedStrings->GetIterator(); - CachedString* string = it.Next();) { - cachedStrings[index++] = string; - } - - // sort it by descending usage count - std::sort(cachedStrings, cachedStrings + count, - CachedStringUsageGreater()); - - // assign the indices and write entries to disk - int32 stringsWritten = 0; - for (int32 i = 0; i < count; i++) { - CachedString* cachedString = cachedStrings[i]; - - // strings that are used only once are better stored inline - if (cachedString->usageCount < 2) - break; - - cachedString->index = i; - - _WriteString(cachedString->string); - stringsWritten++; - } - - // write a terminating 0 byte - _Write(0); - - return stringsWritten; + Write(0); } @@ -989,18 +825,18 @@ PackageWriterImpl::_WriteAttributeChildren(Attribute* attribute) AttributeType* type = child->type; // write tag - uint8 encoding = child->value.PreferredEncoding(); - _WriteUnsignedLEB128(HPKG_ATTRIBUTE_TAG_COMPOSE(type->index, + uint8 encoding = child->value.ApplicableEncoding(); + WriteUnsignedLEB128(HPKG_ATTRIBUTE_TAG_COMPOSE(type->index, encoding, !child->children.IsEmpty())); // write value - _WriteAttributeValue(child->value, encoding); + WriteAttributeValue(child->value, encoding); if (!child->children.IsEmpty()) _WriteAttributeChildren(child); } - _WriteUnsignedLEB128(0); + WriteUnsignedLEB128(0); } @@ -1014,109 +850,12 @@ PackageWriterImpl::_WritePackageAttributes(hpkg_header& header) 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()); + // write the cached strings + uint32 stringsCount = WriteCachedStrings(fPackageStringCache, 2); - // 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); + // write package attributes tree + off_t attributesOffset = startOffset + fDataWriter->BytesWritten(); + WritePackageAttributes(fPackageAttributes); zlibWriter.Finish(); fHeapEnd = realWriter.Offset(); @@ -1124,7 +863,8 @@ PackageWriterImpl::_WritePackageAttributes(hpkg_header& header) off_t endOffset = fHeapEnd; - fListener->OnPackageAttributesSizeInfo(zlibWriter.BytesWritten()); + fListener->OnPackageAttributesSizeInfo(stringsCount, + zlibWriter.BytesWritten()); // update the header header.attributes_compression @@ -1133,151 +873,10 @@ PackageWriterImpl::_WritePackageAttributes(hpkg_header& header) = B_HOST_TO_BENDIAN_INT32(endOffset - startOffset); header.attributes_length_uncompressed = B_HOST_TO_BENDIAN_INT32(zlibWriter.BytesWritten()); -} - - -void -PackageWriterImpl::_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 -PackageWriterImpl::_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 -PackageWriterImpl::_WriteAttributeValue(const AttributeValue& value, - uint8 encoding) -{ - switch (value.type) { - case B_HPKG_ATTRIBUTE_TYPE_INT: - case B_HPKG_ATTRIBUTE_TYPE_UINT: - { - uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT - ? (uint64)value.signedInt : value.unsignedInt; - - switch (encoding) { - case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: - _Write((uint8)intValue); - break; - case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: - _Write( - B_HOST_TO_BENDIAN_INT16((uint16)intValue)); - break; - case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: - _Write( - B_HOST_TO_BENDIAN_INT32((uint32)intValue)); - break; - case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: - _Write( - B_HOST_TO_BENDIAN_INT64((uint64)intValue)); - break; - default: - { - fListener->PrintError("_WriteAttributeValue(): invalid " - "encoding %d for int value type %d\n", encoding, - value.type); - throw status_t(B_BAD_VALUE); - } - } - - break; - } - - case B_HPKG_ATTRIBUTE_TYPE_STRING: - { - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) - _WriteUnsignedLEB128(value.string->index); - else - _WriteString(value.string->string); - break; - } - - case B_HPKG_ATTRIBUTE_TYPE_RAW: - { - _WriteUnsignedLEB128(value.data.size); - if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) - _WriteUnsignedLEB128(value.data.offset); - else - fDataWriter->WriteDataThrows(value.data.raw, value.data.size); - break; - } - - default: - fListener->PrintError("_WriteAttributeValue(): invalid value type: " - "%d\n", value.type); - throw status_t(B_BAD_VALUE); - } -} - - -void -PackageWriterImpl::_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 -PackageWriterImpl::_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); - } + header.attributes_strings_count + = B_HOST_TO_BENDIAN_INT32(stringsCount); + header.attributes_strings_length + = B_HOST_TO_BENDIAN_INT32(attributesOffset - startOffset); } @@ -1469,7 +1068,7 @@ PackageWriterImpl::_AddStringAttribute(const char* attributeName, const char* value) { AttributeValue attributeValue; - attributeValue.SetTo(_GetCachedString(value)); + attributeValue.SetTo(fStringCache.Get(value)); return _AddAttribute(attributeName, attributeValue); } @@ -1494,26 +1093,6 @@ PackageWriterImpl::_AddDataAttribute(const char* attributeName, uint64 dataSize, } -CachedString* -PackageWriterImpl::_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; -} - - PackageWriterImpl::AttributeType* PackageWriterImpl::_GetAttributeType(const char* attributeName, uint8 type) { diff --git a/src/kits/package/hpkg/Strings.cpp b/src/kits/package/hpkg/Strings.cpp index 47a488634c..4f87d8e20c 100644 --- a/src/kits/package/hpkg/Strings.cpp +++ b/src/kits/package/hpkg/Strings.cpp @@ -34,6 +34,42 @@ hash_string(const char* string) } +StringCache::StringCache() +{ +} + + +StringCache::~StringCache() +{ + CachedString* cachedString = Clear(true); + while (cachedString != NULL) { + CachedString* next = cachedString->next; + delete cachedString; + cachedString = next; + } +} + + +CachedString* +StringCache::Get(const char* value) +{ + CachedString* string = Lookup(value); + if (string != NULL) { + string->usageCount++; + return string; + } + + string = new CachedString; + if (!string->Init(value)) { + delete string; + throw std::bad_alloc(); + } + + Insert(string); + return string; +} + + } // namespace BPrivate } // namespace BHPKG diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp new file mode 100644 index 0000000000..6cc287d691 --- /dev/null +++ b/src/kits/package/hpkg/WriterImplBase.cpp @@ -0,0 +1,533 @@ +/* + * 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 { + + +// #pragma mark - AttributeValue + + +WriterImplBase::AttributeValue::AttributeValue() + : + type(B_HPKG_ATTRIBUTE_TYPE_INVALID), + encoding(-1) +{ +} + + +WriterImplBase::AttributeValue::~AttributeValue() +{ +} + + +void +WriterImplBase::AttributeValue::SetTo(int8 value) +{ + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; +} + + +void +WriterImplBase::AttributeValue::SetTo(uint8 value) +{ + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; +} + + +void +WriterImplBase::AttributeValue::SetTo(int16 value) +{ + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; +} + + +void +WriterImplBase::AttributeValue::SetTo(uint16 value) +{ + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; +} + + +void +WriterImplBase::AttributeValue::SetTo(int32 value) +{ + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; +} + + +void +WriterImplBase::AttributeValue::SetTo(uint32 value) +{ + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; +} + + +void +WriterImplBase::AttributeValue::SetTo(int64 value) +{ + signedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_INT; +} + + +void +WriterImplBase::AttributeValue::SetTo(uint64 value) +{ + unsignedInt = value; + type = B_HPKG_ATTRIBUTE_TYPE_UINT; +} + + +void +WriterImplBase::AttributeValue::SetTo(CachedString* value) +{ + string = value; + type = B_HPKG_ATTRIBUTE_TYPE_STRING; +} + + +void +WriterImplBase::AttributeValue::SetToData(uint64 size, uint64 offset) +{ + data.size = size; + data.offset = offset; + type = B_HPKG_ATTRIBUTE_TYPE_RAW; + encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP; +} + + +void +WriterImplBase::AttributeValue::SetToData(uint64 size, const void* rawData) +{ + data.size = size; + if (size > 0) + memcpy(data.raw, rawData, size); + type = B_HPKG_ATTRIBUTE_TYPE_RAW; + encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE; +} + + +uint8 +WriterImplBase::AttributeValue::ApplicableEncoding() const +{ + switch (type) { + case B_HPKG_ATTRIBUTE_TYPE_INT: + return _ApplicableIntEncoding(signedInt >= 0 + ? (uint64)signedInt << 1 + : (uint64)(-(signedInt + 1) << 1)); + case B_HPKG_ATTRIBUTE_TYPE_UINT: + return _ApplicableIntEncoding(unsignedInt); + case B_HPKG_ATTRIBUTE_TYPE_STRING: + return string->index >= 0 + ? B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE + : B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE; + case B_HPKG_ATTRIBUTE_TYPE_RAW: + return encoding; + default: + return 0; + } +} + + +/*static*/ uint8 +WriterImplBase::AttributeValue::_ApplicableIntEncoding(uint64 value) +{ + if (value <= 0xff) + return B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT; + if (value <= 0xffff) + return B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT; + if (value <= 0xffffffff) + return B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT; + + return B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT; +} + + +// #pragma mark - DataWriter + + +WriterImplBase::DataWriter::DataWriter() + : + fBytesWritten(0) +{ +} + + +WriterImplBase::DataWriter::~DataWriter() +{ +} + + +// #pragma mark - FDDataWriter + + +WriterImplBase::FDDataWriter::FDDataWriter(int fd, off_t offset, + BErrorOutput* errorOutput) + : + fFD(fd), + fOffset(offset), + fErrorOutput(errorOutput) +{ +} + + +status_t +WriterImplBase::FDDataWriter::WriteDataNoThrow(const void* buffer, size_t size) +{ + ssize_t bytesWritten = pwrite(fFD, buffer, size, fOffset); + if (bytesWritten < 0) { + fErrorOutput->PrintError( + "WriteDataNoThrow(%p, %lu) failed to write data: %s\n", buffer, + size, strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != size) { + fErrorOutput->PrintError( + "WriteDataNoThrow(%p, %lu) failed to write all data\n", buffer, + size); + return B_ERROR; + } + + fOffset += size; + fBytesWritten += size; + return B_OK; +} + + +// #pragma mark - ZlibDataWriter + + +WriterImplBase::ZlibDataWriter::ZlibDataWriter(DataWriter* dataWriter) + : + fDataWriter(dataWriter), + fCompressor(this) +{ +} + + +void +WriterImplBase::ZlibDataWriter::Init() +{ + status_t error = fCompressor.Init(); + if (error != B_OK) + throw status_t(error); +} + + +void +WriterImplBase::ZlibDataWriter::Finish() +{ + status_t error = fCompressor.Finish(); + if (error != B_OK) + throw status_t(error); +} + + +status_t +WriterImplBase::ZlibDataWriter::WriteDataNoThrow(const void* buffer, + size_t size) +{ + status_t error = fCompressor.CompressNext(buffer, size); + if (error == B_OK) + fBytesWritten += size; + return error; +} + + +status_t +WriterImplBase::ZlibDataWriter::WriteData(const void* buffer, size_t size) +{ + return fDataWriter->WriteDataNoThrow(buffer, size); +} + + +// #pragma mark - PackageAttribute + +WriterImplBase::PackageAttribute::PackageAttribute(HPKGPackageAttributeID id_, + uint8 type_, uint8 encoding_) + : + id(id_) +{ + type = type_; + encoding = encoding_; +} + + +WriterImplBase::PackageAttribute::~PackageAttribute() +{ + _DeleteChildren(); +} + + +void +WriterImplBase::PackageAttribute::AddChild(PackageAttribute* child) +{ + children.Add(child); +} + + +void +WriterImplBase::PackageAttribute::_DeleteChildren() +{ + while (PackageAttribute* child = children.RemoveHead()) + delete child; +} + + +// #pragma mark - WriterImplBase + + +WriterImplBase::WriterImplBase(BErrorOutput* errorOutput) + : + fErrorOutput(errorOutput), + fFileName(NULL), + fFD(-1), + fFinished(false), + fDataBuffer(NULL), + fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB), + fDataWriter(NULL) +{ +} + + +WriterImplBase::~WriterImplBase() +{ + if (fFD >= 0) + close(fFD); + + if (!fFinished && fFileName != NULL) + unlink(fFileName); +} + + +status_t +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); + if (fFD < 0) { + fErrorOutput->PrintError("Failed to open %s file \"%s\": %s\n", type, + fileName, strerror(errno)); + return errno; + } + + fFileName = fileName; + + return B_OK; +} + + +int32 +WriterImplBase::WriteCachedStrings(const StringCache& cache, + uint32 minUsageCount) +{ + // create an array of the cached strings + int32 count = cache.CountElements(); + CachedString** cachedStrings = new CachedString*[count]; + ArrayDeleter cachedStringsDeleter(cachedStrings); + + int32 index = 0; + for (CachedStringTable::Iterator it = cache.GetIterator(); + CachedString* string = it.Next();) { + cachedStrings[index++] = string; + } + + // sort it by descending usage count + std::sort(cachedStrings, cachedStrings + count, CachedStringUsageGreater()); + + // assign the indices and write entries to disk + int32 stringsWritten = 0; + for (int32 i = 0; i < count; i++) { + CachedString* cachedString = cachedStrings[i]; + + // empty strings must be stored inline, as they can't be distinguished + // from the end-marker! + if (strlen(cachedString->string) == 0) + continue; + + // strings that are used only once are better stored inline + if (cachedString->usageCount < minUsageCount) + break; + + WriteString(cachedString->string); + + cachedString->index = stringsWritten++; + } + + // write a terminating 0 byte + Write(0); + + return stringsWritten; +} + + +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); +} + + +void +WriterImplBase::WriteAttributeValue(const AttributeValue& value, uint8 encoding) +{ + switch (value.type) { + case B_HPKG_ATTRIBUTE_TYPE_INT: + case B_HPKG_ATTRIBUTE_TYPE_UINT: + { + uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT + ? (uint64)value.signedInt : value.unsignedInt; + + switch (encoding) { + case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: + Write((uint8)intValue); + break; + case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: + Write( + B_HOST_TO_BENDIAN_INT16((uint16)intValue)); + break; + case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: + Write( + B_HOST_TO_BENDIAN_INT32((uint32)intValue)); + break; + case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: + Write( + B_HOST_TO_BENDIAN_INT64((uint64)intValue)); + break; + default: + { + fErrorOutput->PrintError("WriteAttributeValue(): invalid " + "encoding %d for int value type %d\n", encoding, + value.type); + throw status_t(B_BAD_VALUE); + } + } + + break; + } + + case B_HPKG_ATTRIBUTE_TYPE_STRING: + { + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) + WriteUnsignedLEB128(value.string->index); + else + WriteString(value.string->string); + break; + } + + case B_HPKG_ATTRIBUTE_TYPE_RAW: + { + WriteUnsignedLEB128(value.data.size); + if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) + WriteUnsignedLEB128(value.data.offset); + else + fDataWriter->WriteDataThrows(value.data.raw, value.data.size); + break; + } + + default: + fErrorOutput->PrintError( + "WriteAttributeValue(): invalid value type: %d\n", value.type); + throw status_t(B_BAD_VALUE); + } +} + + +void +WriterImplBase::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 +WriterImplBase::WriteBuffer(const void* buffer, size_t size, off_t offset) +{ + ssize_t bytesWritten = pwrite(fFD, buffer, size, offset); + if (bytesWritten < 0) { + fErrorOutput->PrintError( + "WriteBuffer(%p, %lu) failed to write data: %s\n", buffer, size, + strerror(errno)); + throw status_t(errno); + } + if ((size_t)bytesWritten != size) { + fErrorOutput->PrintError( + "WriteBuffer(%p, %lu) failed to write all data\n", buffer, size); + throw status_t(B_ERROR); + } +} + + +} // namespace BPrivate + +} // namespace BHPKG + +} // namespace BPackageKit