From 689605bf2a397b17927c848e0e730427408817c9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 15 Nov 2009 21:29:53 +0000 Subject: [PATCH] * Added support for iterative operation to ZlibCompressor/ZlibDecompressor. * Added support for compressing/decompressing the TOC section of the package to PackageWriter/PackageReader. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34063 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/bin/package/DataOutput.cpp | 44 +++ src/bin/package/DataOutput.h | 35 ++ src/bin/package/Jamfile | 1 + src/bin/package/PackageDataReader.cpp | 5 +- src/bin/package/PackageReader.cpp | 80 ++++- src/bin/package/PackageReader.h | 11 +- src/bin/package/PackageWriter.cpp | 308 +++++++++++++++--- src/bin/package/PackageWriter.h | 36 +- .../package/compression/ZlibCompressor.cpp | 106 +++++- src/bin/package/compression/ZlibCompressor.h | 23 +- .../package/compression/ZlibDecompressor.cpp | 114 ++++++- .../package/compression/ZlibDecompressor.h | 23 +- 12 files changed, 686 insertions(+), 100 deletions(-) create mode 100644 src/bin/package/DataOutput.cpp create mode 100644 src/bin/package/DataOutput.h diff --git a/src/bin/package/DataOutput.cpp b/src/bin/package/DataOutput.cpp new file mode 100644 index 0000000000..dc600c1bb4 --- /dev/null +++ b/src/bin/package/DataOutput.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "DataOutput.h" + +#include + + +// #pragma mark - DataOutput + + +DataOutput::~DataOutput() +{ +} + + +// #pragma mark - BufferDataOutput + + +BufferDataOutput::BufferDataOutput(void* buffer, size_t size) + : + fBuffer(buffer), + fSize(size), + fBytesWritten(0) +{ +} + + +status_t +BufferDataOutput::WriteData(const void* buffer, size_t size) +{ + if (size == 0) + return B_OK; + if (size > fSize - fBytesWritten) + return B_BAD_VALUE; + + memcpy((uint8*)fBuffer + fBytesWritten, buffer, size); + fBytesWritten += size; + + return B_OK; +} diff --git a/src/bin/package/DataOutput.h b/src/bin/package/DataOutput.h new file mode 100644 index 0000000000..ecf13688b4 --- /dev/null +++ b/src/bin/package/DataOutput.h @@ -0,0 +1,35 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DATA_OUTPUT_H +#define DATA_OUTPUT_H + + +#include + + +class DataOutput { +public: + virtual ~DataOutput(); + + virtual status_t WriteData(const void* buffer, size_t size) = 0; +}; + + +class BufferDataOutput : public DataOutput { +public: + BufferDataOutput(void* buffer, size_t size); + + size_t BytesWritten() const { return fBytesWritten; } + + virtual status_t WriteData(const void* buffer, size_t size); + +private: + void* fBuffer; + size_t fSize; + size_t fBytesWritten; +}; + + +#endif // DATA_OUTPUT_H diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile index a5b1036171..097d6a1615 100644 --- a/src/bin/package/Jamfile +++ b/src/bin/package/Jamfile @@ -14,6 +14,7 @@ BinCommand package : command_dump.cpp command_extract.cpp command_list.cpp + DataOutput.cpp DataReader.cpp package.cpp PackageData.cpp diff --git a/src/bin/package/PackageDataReader.cpp b/src/bin/package/PackageDataReader.cpp index d9b0e2d362..29303db668 100644 --- a/src/bin/package/PackageDataReader.cpp +++ b/src/bin/package/PackageDataReader.cpp @@ -236,8 +236,9 @@ private: return error; size_t actuallyUncompressedSize; - error = ZlibDecompressor().Decompress(fReadBuffer, compressedSize, - fUncompressBuffer, uncompressedSize, actuallyUncompressedSize); + error = ZlibDecompressor::DecompressSingleBuffer(fReadBuffer, + compressedSize, fUncompressBuffer, uncompressedSize, + actuallyUncompressedSize); if (error == B_OK && actuallyUncompressedSize != uncompressedSize) error = B_BAD_DATA; } diff --git a/src/bin/package/PackageReader.cpp b/src/bin/package/PackageReader.cpp index 0888b89e5e..45e8ef9573 100644 --- a/src/bin/package/PackageReader.cpp +++ b/src/bin/package/PackageReader.cpp @@ -14,20 +14,25 @@ #include #include +#include #include #include #include +#include "DataOutput.h" #include "PackageData.h" #include "PackageEntry.h" #include "PackageEntryAttribute.h" +#include "ZlibDecompressor.h" -// maximum TOC size, we support reading +// maximum TOC size we support reading static const size_t kMaxTOCSize = 64 * 1024 * 1024; +static const size_t kScratchBufferSize = 64 * 1024; + enum { ATTRIBUTE_INDEX_DIRECTORY_ENTRY = 0, @@ -604,7 +609,9 @@ PackageReader::PackageReader() fFD(-1), fTOCSection(NULL), fAttributeTypes(NULL), - fStrings(NULL) + fStrings(NULL), + fScratchBuffer(NULL), + fScratchBufferSize(0) { } @@ -614,6 +621,7 @@ PackageReader::~PackageReader() if (fFD >= 0) close(fFD); + delete[] fScratchBuffer; delete[] fStrings; delete[] fAttributeTypes; delete[] fTOCSection; @@ -641,7 +649,7 @@ PackageReader::Init(const char* fileName) // read the header hpkg_header header; - status_t error = _ReadBuffer(&header, sizeof(header), 0); + status_t error = _ReadBuffer(0, &header, sizeof(header)); if (error != B_OK) return error; @@ -751,6 +759,14 @@ PackageReader::Init(const char* fileName) return B_UNSUPPORTED; } + // allocate a scratch buffer + fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize]; + if (fScratchBuffer == NULL) { + fprintf(stderr, "Error: Out of memory!\n"); + return B_NO_MEMORY; + } + fScratchBufferSize = kScratchBufferSize; + // read in the complete TOC fTOCSection = new(std::nothrow) uint8[fTOCUncompressedLength]; if (fTOCSection == NULL) { @@ -758,7 +774,8 @@ PackageReader::Init(const char* fileName) return B_NO_MEMORY; } - error = _ReadBuffer(fTOCSection, fTOCUncompressedLength, fTOCSectionOffset); + error = _ReadCompressedBuffer(fTOCSectionOffset, fTOCSection, + fTOCCompressedLength, fTOCUncompressedLength, fTOCCompression); if (error != B_OK) return error; @@ -1249,7 +1266,7 @@ PackageReader::_ReadTOCBuffer(void* buffer, size_t size) status_t -PackageReader::_ReadBuffer(void* buffer, size_t size, off_t offset) +PackageReader::_ReadBuffer(off_t offset, void* buffer, size_t size) { ssize_t bytesRead = pread(fFD, buffer, size, offset); if (bytesRead < 0) { @@ -1267,6 +1284,59 @@ PackageReader::_ReadBuffer(void* buffer, size_t size, off_t offset) } +status_t +PackageReader::_ReadCompressedBuffer(off_t offset, void* buffer, + size_t compressedSize, size_t uncompressedSize, uint32 compression) +{ + switch (compression) { + case B_HPKG_COMPRESSION_NONE: + return _ReadBuffer(offset, buffer, compressedSize); + + case B_HPKG_COMPRESSION_ZLIB: + { + // init the decompressor + BufferDataOutput bufferOutput(buffer, uncompressedSize); + ZlibDecompressor decompressor(&bufferOutput); + status_t error = decompressor.Init(); + if (error != B_OK) + return error; + + while (compressedSize > 0) { + // read compressed buffer + size_t toRead = std::min(compressedSize, fScratchBufferSize); + error = _ReadBuffer(offset, fScratchBuffer, toRead); + if (error != B_OK) + return error; + + // uncompress + error = decompressor.DecompressNext(fScratchBuffer, toRead); + if (error != B_OK) + return error; + + compressedSize -= toRead; + offset += toRead; + } + + error = decompressor.Finish(); + if (error != B_OK) + return error; + + // verify that all data have been read + if (bufferOutput.BytesWritten() != uncompressedSize) { + fprintf(stderr, "Error: Missing bytes in uncompressed " + "buffer!\n"); + return B_BAD_DATA; + } + + return B_OK; + } + + default: + return B_BAD_DATA; + } +} + + /*static*/ int8 PackageReader::_GetStandardIndex(const AttributeType* type) { diff --git a/src/bin/package/PackageReader.h b/src/bin/package/PackageReader.h index a2e16d50e8..9a75f7d8ea 100644 --- a/src/bin/package/PackageReader.h +++ b/src/bin/package/PackageReader.h @@ -104,8 +104,12 @@ private: const void*& _buffer); status_t _ReadTOCBuffer(void* buffer, size_t size); - status_t _ReadBuffer(void* buffer, size_t size, - off_t offset); + status_t _ReadBuffer(off_t offset, void* buffer, + size_t size); + status_t _ReadCompressedBuffer(off_t offset, + void* buffer, size_t compressedSize, + size_t uncompressedSize, + uint32 compression); static int8 _GetStandardIndex(const AttributeType* type); @@ -141,6 +145,9 @@ private: char** fStrings; AttributeHandlerList* fAttributeHandlerStack; + + uint8* fScratchBuffer; + size_t fScratchBufferSize; }; diff --git a/src/bin/package/PackageWriter.cpp b/src/bin/package/PackageWriter.cpp index e56ea8ac7a..12b02000e3 100644 --- a/src/bin/package/PackageWriter.cpp +++ b/src/bin/package/PackageWriter.cpp @@ -25,6 +25,7 @@ #include +#include "DataOutput.h" #include "DataReader.h" #include "FDCloser.h" #include "Stacker.h" @@ -373,7 +374,149 @@ private: }; -// #pragma mark - PackageWriter +// #pragma mark - DataWriter + + +struct PackageWriter::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 PackageWriter::DummyDataWriter : DataWriter { + DummyDataWriter() + { + } + + virtual status_t WriteDataNoThrow(const void* buffer, size_t size) + { + fBytesWritten += size; + return B_OK; + } +}; + + +struct PackageWriter::FDDataWriter : DataWriter { + FDDataWriter(int fd, off_t offset) + : + fFD(fd), + fOffset(offset) + { + } + + virtual status_t WriteDataNoThrow(const void* buffer, size_t size) + { + ssize_t bytesWritten = pwrite(fFD, buffer, size, fOffset); + if (bytesWritten < 0) { + fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write data: %s\n", + buffer, size, strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != size) { + fprintf(stderr, "_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; +}; + + +struct PackageWriter::ZlibDataWriter : DataWriter, private DataOutput { + 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: + // DataOutput + virtual status_t WriteData(const void* buffer, size_t size) + { + return fDataWriter->WriteDataNoThrow(buffer, size); + } + +private: + DataWriter* fDataWriter; + ZlibCompressor fCompressor; +}; + + +// #pragma mark - PackageWriter (Inline Methods) + + +template +inline void +PackageWriter::_Write(const Type& value) +{ + fDataWriter->WriteDataThrows(&value, sizeof(Type)); +} + + +inline void +PackageWriter::_WriteString(const char* string) +{ + fDataWriter->WriteDataThrows(string, strlen(string) + 1); +} template @@ -386,12 +529,16 @@ PackageWriter::_AddAttribute(const char* attributeName, Type value) } +// #pragma mark - PackageWriter + + PackageWriter::PackageWriter() : fFileName(NULL), fFD(-1), fFinished(false), fDataBuffer(NULL), + fDataWriter(NULL), fRootEntry(NULL), fRootAttribute(NULL), fTopAttribute(NULL), @@ -529,26 +676,11 @@ PackageWriter::_Finish() printf("header size: %lu\n", sizeof(hpkg_header)); printf("heap size: %lld\n", fHeapEnd - sizeof(hpkg_header)); - // write the attribute type abbreviations - off_t attributeTypesOffset = fHeapEnd; - _WriteAttributeTypes(); -printf("attributes types size: %lld\n", fHeapEnd - attributeTypesOffset); + hpkg_header header; - // write the cached strings - off_t cachedStringsOffset = fHeapEnd; - int32 cachedStringsWritten = _WriteCachedStrings(); -printf("cached strings size: %lld\n", fHeapEnd - cachedStringsOffset); - - // write the TOC - off_t tocOffset = fHeapEnd; - _WriteAttributeChildren(fRootAttribute); -printf("toc size: %lld\n", fHeapEnd - tocOffset); - - // write the package attributes - off_t packageAttributesOffset = fHeapEnd; - _Write(0); - // TODO: Write them for real! -printf("package attributes size: %lld\n", fHeapEnd - packageAttributesOffset); + // write the TOC and package attributes + _WriteTOC(header); + _WritePackageAttributes(header); off_t totalSize = fHeapEnd; printf("total size: %lld\n", totalSize); @@ -556,38 +688,12 @@ printf("total size: %lld\n", totalSize); // prepare the header // general - hpkg_header header; header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC); header.header_size = B_HOST_TO_BENDIAN_INT16( (uint16)sizeof(hpkg_header)); header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION); header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); - // package attributes - header.attributes_compression = B_HOST_TO_BENDIAN_INT32( - B_HPKG_COMPRESSION_NONE); - header.attributes_length_compressed - = B_HOST_TO_BENDIAN_INT32(fHeapEnd - packageAttributesOffset); - header.attributes_length_uncompressed - = header.attributes_length_compressed; - // TODO: Support compression! - - // TOC - header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_NONE); - header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64( - packageAttributesOffset - attributeTypesOffset); - header.toc_length_uncompressed = header.toc_length_compressed; - // TODO: Support compression! - - // TOC subsections - header.toc_attribute_types_length = B_HOST_TO_BENDIAN_INT64( - cachedStringsOffset - attributeTypesOffset); - header.toc_attribute_types_count = B_HOST_TO_BENDIAN_INT64( - fAttributeTypes->CountElements()); - header.toc_strings_length = B_HOST_TO_BENDIAN_INT64( - tocOffset - cachedStringsOffset); - header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten); - // write the header _WriteBuffer(&header, sizeof(hpkg_header), 0); @@ -666,6 +772,79 @@ PackageWriter::_RegisterEntry(Entry* parent, const char* name, } +void +PackageWriter::_WriteTOC(hpkg_header& header) +{ + // prepare the writer (zlib writer on top of a file writer) + off_t startOffset = fHeapEnd; + FDDataWriter realWriter(fFD, startOffset); + 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; + +printf("attributes types size: %llu\n", uncompressedAttributeTypesSize); +printf("cached strings size: %llu\n", uncompressedStringsSize); +printf("TOC main size: %llu\n", uncompressedMainSize); + off_t endOffset = fHeapEnd; +printf("total TOC size: %llu (%llu)\n", endOffset - startOffset, 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()); + + // TOC subsections + header.toc_attribute_types_length = B_HOST_TO_BENDIAN_INT64( + uncompressedAttributeTypesSize); + header.toc_attribute_types_count = B_HOST_TO_BENDIAN_INT64( + fAttributeTypes->CountElements()); + header.toc_strings_length = B_HOST_TO_BENDIAN_INT64( + uncompressedStringsSize); + header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten); +} + + +int32 +PackageWriter::_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 PackageWriter::_WriteAttributeTypes() { @@ -762,6 +941,34 @@ PackageWriter::_WriteAttributeChildren(Attribute* attribute) } +void +PackageWriter::_WritePackageAttributes(hpkg_header& header) +{ + // write the package attributes + off_t startOffset = fHeapEnd; + FDDataWriter realWriter(fFD, startOffset); + fDataWriter = &realWriter; + + _Write(0); + // TODO: Write them for real! + fHeapEnd = realWriter.Offset(); + fDataWriter = NULL; + + off_t endOffset = fHeapEnd; + +printf("package attributes size: %lld\n", endOffset - startOffset); + + // update the header + header.attributes_compression = B_HOST_TO_BENDIAN_INT32( + B_HPKG_COMPRESSION_NONE); + header.attributes_length_compressed + = B_HOST_TO_BENDIAN_INT32(endOffset - startOffset); + header.attributes_length_uncompressed + = header.attributes_length_compressed; + // TODO: Support compression! +} + + void PackageWriter::_WriteAttributeValue(const AttributeValue& value, uint8 encoding) { @@ -815,7 +1022,7 @@ PackageWriter::_WriteAttributeValue(const AttributeValue& value, uint8 encoding) if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) _WriteUnsignedLEB128(value.data.offset); else - _WriteBuffer(value.data.raw, value.data.size); + fDataWriter->WriteDataThrows(value.data.raw, value.data.size); break; } @@ -838,7 +1045,7 @@ PackageWriter::_WriteUnsignedLEB128(uint64 value) bytes[count++] = byte | (value != 0 ? 0x80 : 0); } while (value != 0); - _WriteBuffer(bytes, count); + fDataWriter->WriteDataThrows(bytes, count); } @@ -1237,10 +1444,9 @@ PackageWriter::_WriteZlibCompressedData(DataReader& dataReader, off_t size, } // compress - ZlibCompressor compressor; size_t compressedSize; - error = compressor.Compress(inputBuffer, toCopy, outputBuffer, - toCopy, compressedSize); + error = ZlibCompressor::CompressSingleBuffer(inputBuffer, toCopy, + outputBuffer, toCopy, compressedSize); const void* writeBuffer; size_t bytesToWrite; diff --git a/src/bin/package/PackageWriter.h b/src/bin/package/PackageWriter.h index b441edb89b..4c0f513436 100644 --- a/src/bin/package/PackageWriter.h +++ b/src/bin/package/PackageWriter.h @@ -13,6 +13,7 @@ class DataReader; +struct hpkg_header; class PackageWriter { @@ -32,6 +33,10 @@ private: struct Attribute; struct AttributeTypeUsageGreater; struct Entry; + struct DataWriter; + struct DummyDataWriter; + struct FDDataWriter; + struct ZlibDataWriter; typedef BOpenHashTable AttributeTypeTable; @@ -46,10 +51,15 @@ 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); @@ -61,7 +71,6 @@ private: void _WriteBuffer(const void* buffer, size_t size, off_t offset); - inline void _WriteBuffer(const void* buffer, size_t size); void _AddEntry(int dirFD, Entry* entry, const char* fileName); @@ -100,6 +109,8 @@ private: void* fDataBuffer; size_t fDataBufferSize; + DataWriter* fDataWriter; + Entry* fRootEntry; Attribute* fRootAttribute; @@ -110,27 +121,4 @@ private: }; -template -inline void -PackageWriter::_Write(const Type& value) -{ - _WriteBuffer(&value, sizeof(Type)); -} - - -inline void -PackageWriter::_WriteString(const char* string) -{ - _WriteBuffer(string, strlen(string) + 1); -} - - -inline void -PackageWriter::_WriteBuffer(const void* buffer, size_t size) -{ - _WriteBuffer(buffer, size, fHeapEnd); - fHeapEnd += size; -} - - #endif // PACKAGE_WRITER_H diff --git a/src/bin/package/compression/ZlibCompressor.cpp b/src/bin/package/compression/ZlibCompressor.cpp index 26f7715b24..cd636e268f 100644 --- a/src/bin/package/compression/ZlibCompressor.cpp +++ b/src/bin/package/compression/ZlibCompressor.cpp @@ -7,23 +7,121 @@ #include "ZlibCompressor.h" #include +#include -#include +#include "DataOutput.h" -ZlibCompressor::ZlibCompressor() +static const size_t kOutputBufferSize = 1024; + + +ZlibCompressor::ZlibCompressor(DataOutput* output) + : + fOutput(output), + fStreamInitialized(false) { } ZlibCompressor::~ZlibCompressor() { + if (fStreamInitialized) + deflateEnd(&fStream); } status_t -ZlibCompressor::Compress(const void* input, size_t inputSize, void* output, - size_t outputSize, size_t& _compressedSize) +ZlibCompressor::Init() +{ + // initialize the stream + fStream.next_in = NULL; + fStream.avail_in = 0; + fStream.total_in = 0; + fStream.next_out = NULL; + fStream.avail_out = 0; + fStream.total_out = 0; + fStream.msg = 0; + fStream.state = 0; + fStream.zalloc = Z_NULL; + fStream.zfree = Z_NULL; + fStream.opaque = Z_NULL; + fStream.data_type = 0; + fStream.adler = 0; + fStream.reserved = 0; + + int zlibError = deflateInit(&fStream, Z_BEST_COMPRESSION); + if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + fStreamInitialized = true; + + return B_OK; +} + + +status_t +ZlibCompressor::CompressNext(const void* input, size_t inputSize) +{ + fStream.next_in = (Bytef*)input; + fStream.avail_in = inputSize; + + while (fStream.avail_in > 0) { + uint8 outputBuffer[kOutputBufferSize]; + fStream.next_out = (Bytef*)outputBuffer; + fStream.avail_out = sizeof(outputBuffer); + + int zlibError = deflate(&fStream, 0); + if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + if (fStream.avail_out < sizeof(outputBuffer)) { + status_t error = fOutput->WriteData(outputBuffer, + sizeof(outputBuffer) - fStream.avail_out); + if (error != B_OK) + return error; + } + } + + return B_OK; +} + + +status_t +ZlibCompressor::Finish() +{ + fStream.next_in = (Bytef*)NULL; + fStream.avail_in = 0; + + while (true) { + uint8 outputBuffer[kOutputBufferSize]; + fStream.next_out = (Bytef*)outputBuffer; + fStream.avail_out = sizeof(outputBuffer); + + int zlibError = deflate(&fStream, Z_FINISH); + if (zlibError != Z_OK && zlibError != Z_STREAM_END) + return TranslateZlibError(zlibError); + + if (fStream.avail_out < sizeof(outputBuffer)) { + status_t error = fOutput->WriteData(outputBuffer, + sizeof(outputBuffer) - fStream.avail_out); + if (error != B_OK) + return error; + } + + if (zlibError == Z_STREAM_END) + break; + } + + deflateEnd(&fStream); + fStreamInitialized = false; + + return B_OK; +} + + +/*static*/ status_t +ZlibCompressor::CompressSingleBuffer(const void* input, size_t inputSize, + void* output, size_t outputSize, size_t& _compressedSize) { if (inputSize == 0 || outputSize == 0) return B_BAD_VALUE; diff --git a/src/bin/package/compression/ZlibCompressor.h b/src/bin/package/compression/ZlibCompressor.h index 1da8ba4f16..c029162df1 100644 --- a/src/bin/package/compression/ZlibCompressor.h +++ b/src/bin/package/compression/ZlibCompressor.h @@ -6,17 +6,32 @@ #define ZLIB_COMPRESSOR_H +#include + #include "ZlibCompressionBase.h" +class DataOutput; + + class ZlibCompressor : public ZlibCompressionBase { public: - ZlibCompressor(); + ZlibCompressor(DataOutput* output); ~ZlibCompressor(); - status_t Compress(const void* input, size_t inputSize, - void* output, size_t outputSize, - size_t& _compressedSize); + status_t Init(); + status_t CompressNext(const void* input, + size_t inputSize); + status_t Finish(); + + static status_t CompressSingleBuffer(const void* input, + size_t inputSize, void* output, + size_t outputSize, size_t& _compressedSize); + +private: + z_stream fStream; + DataOutput* fOutput; + bool fStreamInitialized; }; diff --git a/src/bin/package/compression/ZlibDecompressor.cpp b/src/bin/package/compression/ZlibDecompressor.cpp index 2da9423095..e6d944ba49 100644 --- a/src/bin/package/compression/ZlibDecompressor.cpp +++ b/src/bin/package/compression/ZlibDecompressor.cpp @@ -7,23 +7,127 @@ #include "ZlibDecompressor.h" #include +#include -#include +#include "DataOutput.h" -ZlibDecompressor::ZlibDecompressor() +// TODO: For the kernel the buffer shouldn't be allocated on the stack. +static const size_t kOutputBufferSize = 1024; + + +ZlibDecompressor::ZlibDecompressor(DataOutput* output) + : + fOutput(output), + fStreamInitialized(false), + fFinished(false) { } ZlibDecompressor::~ZlibDecompressor() { + if (fStreamInitialized) + inflateEnd(&fStream); } status_t -ZlibDecompressor::Decompress(const void* input, size_t inputSize, void* output, - size_t outputSize, size_t& _uncompressedSize) +ZlibDecompressor::Init() +{ + // initialize the stream + fStream.next_in = NULL; + fStream.avail_in = 0; + fStream.total_in = 0; + fStream.next_out = NULL; + fStream.avail_out = 0; + fStream.total_out = 0; + fStream.msg = 0; + fStream.state = 0; + fStream.zalloc = Z_NULL; + fStream.zfree = Z_NULL; + fStream.opaque = Z_NULL; + fStream.data_type = 0; + fStream.adler = 0; + fStream.reserved = 0; + + int zlibError = inflateInit(&fStream); + if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + fStreamInitialized = true; + + return B_OK; +} + + +status_t +ZlibDecompressor::DecompressNext(const void* input, size_t inputSize) +{ + fStream.next_in = (Bytef*)input; + fStream.avail_in = inputSize; + + while (fStream.avail_in > 0) { + if (fFinished) + return B_BAD_DATA; + + uint8 outputBuffer[kOutputBufferSize]; + fStream.next_out = (Bytef*)outputBuffer; + fStream.avail_out = sizeof(outputBuffer); + + int zlibError = inflate(&fStream, 0); + if (zlibError == Z_STREAM_END) + fFinished = true; + else if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + if (fStream.avail_out < sizeof(outputBuffer)) { + status_t error = fOutput->WriteData(outputBuffer, + sizeof(outputBuffer) - fStream.avail_out); + if (error != B_OK) + return error; + } + } + + return B_OK; +} + + +status_t +ZlibDecompressor::Finish() +{ + fStream.next_in = (Bytef*)NULL; + fStream.avail_in = 0; + + while (!fFinished) { + uint8 outputBuffer[kOutputBufferSize]; + fStream.next_out = (Bytef*)outputBuffer; + fStream.avail_out = sizeof(outputBuffer); + + int zlibError = inflate(&fStream, Z_FINISH); + if (zlibError == Z_STREAM_END) + fFinished = true; + else if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + if (fStream.avail_out < sizeof(outputBuffer)) { + status_t error = fOutput->WriteData(outputBuffer, + sizeof(outputBuffer) - fStream.avail_out); + if (error != B_OK) + return error; + } + } + + inflateEnd(&fStream); + fStreamInitialized = false; + + return B_OK; +} + + +/*static*/ status_t +ZlibDecompressor::DecompressSingleBuffer(const void* input, size_t inputSize, + void* output, size_t outputSize, size_t& _uncompressedSize) { if (inputSize == 0 || outputSize == 0) return B_BAD_VALUE; @@ -51,7 +155,7 @@ ZlibDecompressor::Decompress(const void* input, size_t inputSize, void* output, return TranslateZlibError(zlibError); - // deflate + // inflate status_t error = B_OK; zlibError = inflate(&zStream, Z_FINISH); if (zlibError != Z_STREAM_END) { diff --git a/src/bin/package/compression/ZlibDecompressor.h b/src/bin/package/compression/ZlibDecompressor.h index 52af867ac1..c0093a54b4 100644 --- a/src/bin/package/compression/ZlibDecompressor.h +++ b/src/bin/package/compression/ZlibDecompressor.h @@ -6,17 +6,34 @@ #define ZLIB_DECOMPRESSOR_H +#include + #include "ZlibCompressionBase.h" +class DataOutput; + + class ZlibDecompressor : public ZlibCompressionBase { public: - ZlibDecompressor(); + ZlibDecompressor(DataOutput* output); ~ZlibDecompressor(); - status_t Decompress(const void* input, size_t inputSize, - void* output, size_t outputSize, + status_t Init(); + status_t DecompressNext(const void* input, + size_t inputSize); + status_t Finish(); + + static status_t DecompressSingleBuffer(const void* input, + size_t inputSize, void* output, + size_t outputSize, size_t& _uncompressedSize); + +private: + z_stream fStream; + DataOutput* fOutput; + bool fStreamInitialized; + bool fFinished; };