From aece77090df2a65ee718a2543dcf0518aec0ea36 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 14 Nov 2009 21:08:33 +0000 Subject: [PATCH] Added support for data compression via zlib. Compression support for the TOC and package attributes sections is still missing, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34043 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/bin/package/Jamfile | 9 + src/bin/package/PackageData.cpp | 1 + src/bin/package/PackageData.h | 4 + src/bin/package/PackageDataReader.cpp | 264 +++++++++++++++++- src/bin/package/PackageReader.cpp | 6 + src/bin/package/PackageWriter.cpp | 175 ++++++++++-- src/bin/package/PackageWriter.h | 5 + .../compression/ZlibCompressionBase.cpp | 40 +++ .../package/compression/ZlibCompressionBase.h | 18 ++ .../package/compression/ZlibCompressor.cpp | 74 +++++ src/bin/package/compression/ZlibCompressor.h | 23 ++ .../package/compression/ZlibDecompressor.cpp | 73 +++++ .../package/compression/ZlibDecompressor.h | 23 ++ 13 files changed, 695 insertions(+), 20 deletions(-) create mode 100644 src/bin/package/compression/ZlibCompressionBase.cpp create mode 100644 src/bin/package/compression/ZlibCompressionBase.h create mode 100644 src/bin/package/compression/ZlibCompressor.cpp create mode 100644 src/bin/package/compression/ZlibCompressor.h create mode 100644 src/bin/package/compression/ZlibDecompressor.cpp create mode 100644 src/bin/package/compression/ZlibDecompressor.h diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile index 2a5530d4c7..a5b1036171 100644 --- a/src/bin/package/Jamfile +++ b/src/bin/package/Jamfile @@ -1,11 +1,14 @@ SubDir HAIKU_TOP src bin package ; +UseLibraryHeaders zlib ; UsePrivateHeaders kernel shared ; UsePrivateHeaders haiku_package ; DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ; # TODO: Remove when it is complete! +SEARCH_SOURCE += [ FDirName $(SUBDIR) compression ] ; + BinCommand package : command_create.cpp command_dump.cpp @@ -20,6 +23,12 @@ BinCommand package : PackageReader.cpp PackageWriter.cpp Strings.cpp + + # compression + ZlibCompressionBase.cpp + ZlibCompressor.cpp + ZlibDecompressor.cpp : + z $(TARGET_LIBSUPC++) ; diff --git a/src/bin/package/PackageData.cpp b/src/bin/package/PackageData.cpp index be9731959e..c724b6bde1 100644 --- a/src/bin/package/PackageData.cpp +++ b/src/bin/package/PackageData.cpp @@ -13,6 +13,7 @@ PackageData::PackageData() : fCompressedSize(0), fUncompressedSize(0), + fChunkSize(0), fCompression(B_HPKG_COMPRESSION_NONE), fEncodedInline(true) { diff --git a/src/bin/package/PackageData.h b/src/bin/package/PackageData.h index 0ba59c0a51..de287261b6 100644 --- a/src/bin/package/PackageData.h +++ b/src/bin/package/PackageData.h @@ -19,6 +19,7 @@ public: { return fUncompressedSize; } uint64 Offset() const { return fOffset; } uint32 Compression() const { return fCompression; } + uint32 ChunkSize() const { return fChunkSize; } bool IsEncodedInline() const { return fEncodedInline; } @@ -31,6 +32,8 @@ public: { fCompression = compression; } void SetUncompressedSize(uint64 size) { fUncompressedSize = size; } + void SetChunkSize(uint32 size) + { fChunkSize = size; } private: uint64 fCompressedSize; @@ -39,6 +42,7 @@ private: uint64 fOffset; uint8 fInlineData[B_HPKG_MAX_INLINE_DATA_SIZE]; }; + uint32 fChunkSize; uint32 fCompression; bool fEncodedInline; }; diff --git a/src/bin/package/PackageDataReader.cpp b/src/bin/package/PackageDataReader.cpp index 52a725668b..d9b0e2d362 100644 --- a/src/bin/package/PackageDataReader.cpp +++ b/src/bin/package/PackageDataReader.cpp @@ -6,11 +6,23 @@ #include "PackageDataReader.h" +#include + +#include #include #include #include "PackageData.h" +#include "ZlibDecompressor.h" + + +// minimum/maximum zlib chunk size we consider sane +static const size_t kMinSaneZlibChunkSize = 1024; +static const size_t kMaxSaneZlibChunkSize = 10 * 1024 * 1024; + +// maximum number of entries in the zlib offset table buffer +static const uint32 kMaxZlibOffsetTableBufferSize = 512; // #pragma mark - PackageDataReader @@ -66,7 +78,7 @@ public: return B_BAD_VALUE; if ((uint64)offset > fSize || size > fSize - offset) - return B_ERROR; + return B_BAD_VALUE; return fDataReader->ReadData(fOffset + offset, buffer, size); } @@ -77,6 +89,252 @@ private: }; +// #pragma mark - ZlibPackageDataReader + + +class ZlibPackageDataReader : public PackageDataReader { +public: + ZlibPackageDataReader(DataReader* dataReader) + : + PackageDataReader(dataReader), + fOffsetTable(NULL), + fReadBuffer(NULL) + { + } + + ~ZlibPackageDataReader() + { + delete[] fOffsetTable; + free(fReadBuffer); + } + + status_t Init(const PackageData& data) + { + fOffset = data.Offset(); + fCompressedSize = data.CompressedSize(); + fUncompressedSize = data.UncompressedSize(); + fChunkSize = data.ChunkSize(); + + // validate chunk size + if (fChunkSize == 0) + fChunkSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; + if (fChunkSize < kMinSaneZlibChunkSize + || fChunkSize > kMaxSaneZlibChunkSize) { + return B_BAD_DATA; + } + + fChunkCount = (fUncompressedSize + (fChunkSize - 1)) / fChunkSize; + fOffsetTableSize = (fChunkCount - 1) * sizeof(uint64); + if (fOffsetTableSize >= fCompressedSize) + return B_BAD_DATA; + + // allocate a buffer for the offset table + if (fChunkCount > 1) { + fOffsetTableBufferEntryCount = std::min(fChunkCount - 1, + (uint64)kMaxZlibOffsetTableBufferSize); + fOffsetTable = new(std::nothrow) uint64[ + fOffsetTableBufferEntryCount]; + if (fOffsetTable == NULL) + return B_NO_MEMORY; + + fOffsetTableIndex = -1; + // mark the table content invalid + } else + fChunkSize = fUncompressedSize; + + // allocate the read/uncompress buffer + fReadBuffer = (uint8*)malloc(fChunkSize * 2); + if (fReadBuffer == NULL) + return B_NO_MEMORY; + + fUncompressBuffer = fReadBuffer + fChunkSize; + fUncompressedChunk = -1; + // mark content invalid + + return B_OK; + } + + virtual uint64 Size() const + { + return fUncompressedSize; + } + + virtual size_t BlockSize() const + { + return fChunkSize; + } + + virtual status_t ReadData(off_t offset, void* _buffer, size_t size) + { + uint8* buffer = (uint8*)_buffer; + + // check offset and size + if (size == 0) + return B_OK; + + if (offset < 0) + return B_BAD_VALUE; + + if ((uint64)offset > fUncompressedSize + || size > fUncompressedSize - offset) { + return B_BAD_VALUE; + } + + // uncompress + int64 chunkIndex = offset / fChunkSize; + off_t chunkOffset = chunkIndex * fChunkSize; + size_t inChunkOffset = offset - chunkOffset; + + while (size > 0) { + // read and uncompress the chunk + status_t error = _ReadChunk(chunkIndex); + if (error != B_OK) + return error; + + // copy data to buffer + size_t toCopy = std::min(size, (size_t)fChunkSize - inChunkOffset); + memcpy(buffer, fUncompressBuffer, toCopy); + + buffer += toCopy; + size -= toCopy; + + chunkIndex++; + chunkOffset += fChunkSize; + inChunkOffset = 0; + } + + return B_OK; + } + +private: + status_t _ReadChunk(int64 chunkIndex) + { + if (chunkIndex == fUncompressedChunk) + return B_OK; + + // get the chunk offset and size + uint64 offset; + uint32 compressedSize; + status_t error = _GetCompressedChunkOffsetAndSize(chunkIndex, offset, + compressedSize); + if (error != B_OK) + return error; + + uint32 uncompressedSize = (uint64)chunkIndex + 1 < fChunkCount + ? fChunkSize : fUncompressedSize - chunkIndex * fChunkSize; + + // read the chunk + if (compressedSize == uncompressedSize) { + // the chunk is not compressed -- read it directly into the + // uncompressed buffer + error = fDataReader->ReadData(offset, fUncompressBuffer, + compressedSize); + } else { + // read to the read buffer and uncompress + error = fDataReader->ReadData(offset, fReadBuffer, compressedSize); + if (error != B_OK) + return error; + + size_t actuallyUncompressedSize; + error = ZlibDecompressor().Decompress(fReadBuffer, compressedSize, + fUncompressBuffer, uncompressedSize, actuallyUncompressedSize); + if (error == B_OK && actuallyUncompressedSize != uncompressedSize) + error = B_BAD_DATA; + } + + if (error != B_OK) { + // error reading/decompressing data -- mark the cached data invalid + fUncompressedChunk = -1; + return error; + } + + fUncompressedChunk = chunkIndex; + return B_OK; + } + + status_t _GetCompressedChunkOffsetAndSize(int64 chunkIndex, uint64& _offset, + uint32& _size) + { + // get the offset + uint64 offset; + if (chunkIndex == 0) { + // first chunk is at 0 + offset = 0; + } else { + status_t error = _GetCompressedChunkRelativeOffset(chunkIndex, + offset); + if (error != B_OK) + return error; + } + + // get the end offset + uint64 endOffset; + if ((uint64)chunkIndex + 1 == fChunkCount) { + // last chunk end with the end of the data + endOffset = fCompressedSize - fOffsetTableSize; + } else { + status_t error = _GetCompressedChunkRelativeOffset(chunkIndex + 1, + endOffset); + if (error != B_OK) + return error; + } + + // sanity check + if (endOffset < offset) + return B_BAD_DATA; + + _offset = fOffset + fOffsetTableSize + offset; + _size = endOffset - offset; + return B_OK; + } + + status_t _GetCompressedChunkRelativeOffset(int64 chunkIndex, + uint64& _offset) + { + if (fOffsetTableIndex < 0 || fOffsetTableIndex > chunkIndex + || fOffsetTableIndex + fOffsetTableBufferEntryCount <= chunkIndex) { + // read the table at the given index, or, if we can, the whole table + int64 readAtIndex = fChunkCount - 1 > fOffsetTableBufferEntryCount + ? chunkIndex : 1; + uint32 entriesToRead = std::min( + (uint64)fOffsetTableBufferEntryCount, + fChunkCount - readAtIndex); + + status_t error = fDataReader->ReadData( + fOffset + (readAtIndex - 1) * sizeof(uint64), + fOffsetTable, entriesToRead * sizeof(uint64)); + if (error != B_OK) { + fOffsetTableIndex = -1; + return error; + } + + fOffsetTableIndex = readAtIndex; + } + + // get and check the offset + _offset = fOffsetTable[chunkIndex - fOffsetTableIndex]; + if (_offset > fCompressedSize - fOffsetTableSize) + return B_BAD_DATA; + + return B_OK; + } + +private: + uint64 fOffset; + uint64 fUncompressedSize; + uint64 fCompressedSize; + uint64 fOffsetTableSize; + uint64 fChunkCount; + uint32 fChunkSize; + uint32 fOffsetTableBufferEntryCount; + uint64* fOffsetTable; + int32 fOffsetTableIndex; + uint8* fReadBuffer; + uint8* fUncompressBuffer; + int64 fUncompressedChunk; +}; + + // #pragma mark - PackageDataReaderFactory @@ -92,8 +350,8 @@ PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader, dataReader); break; case B_HPKG_COMPRESSION_ZLIB: - // TODO:... - return B_UNSUPPORTED;; + reader = new(std::nothrow) ZlibPackageDataReader(dataReader); + break; default: return B_BAD_VALUE; } diff --git a/src/bin/package/PackageReader.cpp b/src/bin/package/PackageReader.cpp index a8606ea221..0888b89e5e 100644 --- a/src/bin/package/PackageReader.cpp +++ b/src/bin/package/PackageReader.cpp @@ -46,6 +46,7 @@ enum { ATTRIBUTE_INDEX_DATA, ATTRIBUTE_INDEX_DATA_SIZE, ATTRIBUTE_INDEX_DATA_COMPRESSION, + ATTRIBUTE_INDEX_DATA_CHUNK_SIZE, ATTRIBUTE_INDEX_SYMLINK_PATH }; @@ -78,6 +79,7 @@ static const standard_attribute_index_entry kStandardAttributeIndices[] = { MAKE_ATTRIBUTE_INDEX_ENTRY(DATA, RAW), MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_SIZE, UINT), MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_COMPRESSION, UINT), + MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_CHUNK_SIZE, UINT), MAKE_ATTRIBUTE_INDEX_ENTRY(SYMLINK_PATH, STRING), {} }; @@ -250,6 +252,10 @@ struct PackageReader::DataAttributeHandler : AttributeHandler { fData->SetCompression(value.unsignedInt); return B_OK; } + + case ATTRIBUTE_INDEX_DATA_CHUNK_SIZE: + fData->SetChunkSize(value.unsignedInt); + return B_OK; } return AttributeHandler::HandleChildAttribute(context, type, typeIndex, diff --git a/src/bin/package/PackageWriter.cpp b/src/bin/package/PackageWriter.cpp index a2b3325532..6dbee3a01e 100644 --- a/src/bin/package/PackageWriter.cpp +++ b/src/bin/package/PackageWriter.cpp @@ -27,6 +27,11 @@ #include "FDCloser.h" #include "Stacker.h" +#include "ZlibCompressor.h" + + +// minimum length of data we require before trying to zlib compress them +static const size_t kZlibCompressionSizeThreshold = 64; // #pragma mark - Data interface @@ -536,7 +541,7 @@ PackageWriter::_Init(const char* fileName) throw std::bad_alloc(); // allocate data buffer - fDataBufferSize = 128 * 1024; + fDataBufferSize = 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; fDataBuffer = malloc(fDataBufferSize); if (fDataBuffer == NULL) throw std::bad_alloc(); @@ -1144,13 +1149,51 @@ PackageWriter::_GetAttributeType(const char* attributeName, uint8 type) status_t PackageWriter::_AddData(Data& data, off_t size) { - uint64 dataOffset = fHeapEnd - fHeapOffset; + uint64 dataOffset = fHeapEnd; + uint64 compression = B_HPKG_COMPRESSION_NONE; + uint64 compressedSize; + + status_t error = _WriteZlibCompressedData(data, size, dataOffset, + compressedSize); + if (error == B_OK) { + compression = B_HPKG_COMPRESSION_ZLIB; + } else { + error = _WriteUncompressedData(data, size, dataOffset); + compressedSize = size; + } + if (error != B_OK) + return error; + + fHeapEnd = dataOffset + compressedSize; + + // add data attribute + Attribute* dataAttribute = _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA, + compressedSize, dataOffset - fHeapOffset); + Stacker attributeAttributeStacker(fTopAttribute, dataAttribute); + + // if compressed, add compression attributes + if (compression != B_HPKG_COMPRESSION_NONE) { + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_COMPRESSION, compression); + _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_SIZE, (uint64)size); + // uncompressed size + } + + // TODO: Support inline data! + + return B_OK; +} + + +status_t +PackageWriter::_WriteUncompressedData(Data& data, off_t size, + uint64 writeOffset) +{ // copy the data to the heap off_t readOffset = 0; off_t remainingSize = size; while (remainingSize > 0) { - // read from FD + // read data size_t toCopy = std::min(remainingSize, (off_t)fDataBufferSize); ssize_t bytesRead = data.Read(fDataBuffer, toCopy, readOffset); if (bytesRead < 0) { @@ -1164,8 +1207,7 @@ PackageWriter::_AddData(Data& data, off_t size) } // write to heap - ssize_t bytesWritten = pwrite(fFD, fDataBuffer, bytesRead, - fHeapEnd); + ssize_t bytesWritten = pwrite(fFD, fDataBuffer, bytesRead, writeOffset); if (bytesWritten < 0) { fprintf(stderr, "Error: Failed to write data: %s\n", strerror(errno)); @@ -1178,19 +1220,118 @@ PackageWriter::_AddData(Data& data, off_t size) remainingSize -= bytesRead; readOffset += bytesRead; - fHeapEnd += bytesRead; + writeOffset += bytesRead; } - // add data attribute - Attribute* dataAttribute = _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA, - size, dataOffset); - Stacker attributeAttributeStacker(fTopAttribute, dataAttribute); - -// _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_SIZE, (uint64)size); - // uncompressed size -- not required for uncompressed data - - // TODO: Support inline data! - // TODO: Support compression! - + return B_OK; +} + + +status_t +PackageWriter::_WriteZlibCompressedData(Data& data, 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); + ssize_t bytesRead = data.Read(inputBuffer, toCopy, readOffset); + if (bytesRead < 0) { + fprintf(stderr, "Error: Failed to read data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesRead != toCopy) { + fprintf(stderr, "Error: Failed to read all data\n"); + return B_ERROR; + } + + // compress + ZlibCompressor compressor; + size_t compressedSize; + status_t error = compressor.Compress(inputBuffer, bytesRead, + outputBuffer, bytesRead, 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 = bytesRead; + } + + // 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) { + fprintf(stderr, "Error: Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != bytesToWrite) { + fprintf(stderr, "Error: Failed to write all data\n"); + return B_ERROR; + } + + remainingSize -= bytesRead; + readOffset += bytesRead; + 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) { + fprintf(stderr, "Error: Failed to write data: %s\n", + strerror(errno)); + return errno; + } + if ((size_t)bytesWritten != bytesToWrite) { + fprintf(stderr, "Error: Failed to write all data\n"); + return B_ERROR; + } + } + + _compressedSize = writeOffset - dataOffset; return B_OK; } diff --git a/src/bin/package/PackageWriter.h b/src/bin/package/PackageWriter.h index 2eb1b61169..0e3cb7f99d 100644 --- a/src/bin/package/PackageWriter.h +++ b/src/bin/package/PackageWriter.h @@ -83,6 +83,11 @@ private: uint8 type); status_t _AddData(Data& data, off_t size); + status_t _WriteUncompressedData(Data& data, off_t size, + uint64 writeOffset); + status_t _WriteZlibCompressedData(Data& data, off_t size, + uint64 writeOffset, + uint64& _compressedSize); private: const char* fFileName; diff --git a/src/bin/package/compression/ZlibCompressionBase.cpp b/src/bin/package/compression/ZlibCompressionBase.cpp new file mode 100644 index 0000000000..879d11955f --- /dev/null +++ b/src/bin/package/compression/ZlibCompressionBase.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ZlibCompressionBase.h" + +#include + +#include + + +/*static*/ status_t +ZlibCompressionBase::TranslateZlibError(int error) +{ + switch (error) { + case Z_OK: + return B_OK; + case Z_STREAM_END: + case Z_NEED_DICT: + // a special event (no error), but the caller doesn't seem to handle + // it + return B_ERROR; + case Z_ERRNO: + return errno; + case Z_STREAM_ERROR: + return B_BAD_VALUE; + case Z_DATA_ERROR: + return B_BAD_DATA; + case Z_MEM_ERROR: + return B_NO_MEMORY; + case Z_BUF_ERROR: + return B_BUFFER_OVERFLOW; + case Z_VERSION_ERROR: + return B_BAD_VALUE; + default: + return B_ERROR; + } +} diff --git a/src/bin/package/compression/ZlibCompressionBase.h b/src/bin/package/compression/ZlibCompressionBase.h new file mode 100644 index 0000000000..f27db828d1 --- /dev/null +++ b/src/bin/package/compression/ZlibCompressionBase.h @@ -0,0 +1,18 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ZLIB_COMPRESSION_BASE_H +#define ZLIB_COMPRESSION_BASE_H + + +#include + + +class ZlibCompressionBase { +public: + static status_t TranslateZlibError(int error); +}; + + +#endif // ZLIB_COMPRESSION_BASE_H diff --git a/src/bin/package/compression/ZlibCompressor.cpp b/src/bin/package/compression/ZlibCompressor.cpp new file mode 100644 index 0000000000..2da9423095 --- /dev/null +++ b/src/bin/package/compression/ZlibCompressor.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ZlibDecompressor.h" + +#include + +#include + + +ZlibDecompressor::ZlibDecompressor() +{ +} + + +ZlibDecompressor::~ZlibDecompressor() +{ +} + + +status_t +ZlibDecompressor::Decompress(const void* input, size_t inputSize, void* output, + size_t outputSize, size_t& _uncompressedSize) +{ + if (inputSize == 0 || outputSize == 0) + return B_BAD_VALUE; + + // prepare stream + z_stream zStream = { + (Bytef*)input, // next_in + inputSize, // avail_in + 0, // total_in + (Bytef*)output, // next_out + outputSize, // avail_out + 0, // total_out + 0, // msg + 0, // state; + Z_NULL, // zalloc + Z_NULL, // zfree + Z_NULL, // opaque + 0, // data_type + 0, // adler + 0 // reserved + }; + + int zlibError = inflateInit(&zStream); + if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + + // deflate + status_t error = B_OK; + zlibError = inflate(&zStream, Z_FINISH); + if (zlibError != Z_STREAM_END) { + if (zlibError == Z_OK) + error = B_BUFFER_OVERFLOW; + else + error = TranslateZlibError(zlibError); + } + + // clean up + zlibError = inflateEnd(&zStream); + if (zlibError != Z_OK && error == B_OK) + error = TranslateZlibError(zlibError); + + if (error != B_OK) + return error; + + _uncompressedSize = zStream.total_out; + return B_OK; +} diff --git a/src/bin/package/compression/ZlibCompressor.h b/src/bin/package/compression/ZlibCompressor.h new file mode 100644 index 0000000000..1da8ba4f16 --- /dev/null +++ b/src/bin/package/compression/ZlibCompressor.h @@ -0,0 +1,23 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ZLIB_COMPRESSOR_H +#define ZLIB_COMPRESSOR_H + + +#include "ZlibCompressionBase.h" + + +class ZlibCompressor : public ZlibCompressionBase { +public: + ZlibCompressor(); + ~ZlibCompressor(); + + status_t Compress(const void* input, size_t inputSize, + void* output, size_t outputSize, + size_t& _compressedSize); +}; + + +#endif // ZLIB_COMPRESSOR_H diff --git a/src/bin/package/compression/ZlibDecompressor.cpp b/src/bin/package/compression/ZlibDecompressor.cpp new file mode 100644 index 0000000000..26f7715b24 --- /dev/null +++ b/src/bin/package/compression/ZlibDecompressor.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ZlibCompressor.h" + +#include + +#include + + +ZlibCompressor::ZlibCompressor() +{ +} + + +ZlibCompressor::~ZlibCompressor() +{ +} + + +status_t +ZlibCompressor::Compress(const void* input, size_t inputSize, void* output, + size_t outputSize, size_t& _compressedSize) +{ + if (inputSize == 0 || outputSize == 0) + return B_BAD_VALUE; + + // prepare stream + z_stream zStream = { + (Bytef*)input, // next_in + inputSize, // avail_in + 0, // total_in + (Bytef*)output, // next_out + outputSize, // avail_out + 0, // total_out + 0, // msg + 0, // state; + Z_NULL, // zalloc + Z_NULL, // zfree + Z_NULL, // opaque + 0, // data_type + 0, // adler + 0 // reserved + }; + + int zlibError = deflateInit(&zStream, Z_BEST_COMPRESSION); + if (zlibError != Z_OK) + return TranslateZlibError(zlibError); + + // deflate + status_t error = B_OK; + zlibError = deflate(&zStream, Z_FINISH); + if (zlibError != Z_STREAM_END) { + if (zlibError == Z_OK) + error = B_BUFFER_OVERFLOW; + else + error = TranslateZlibError(zlibError); + } + + // clean up + zlibError = deflateEnd(&zStream); + if (zlibError != Z_OK && error == B_OK) + error = TranslateZlibError(zlibError); + + if (error != B_OK) + return error; + + _compressedSize = zStream.total_out; + return B_OK; +} diff --git a/src/bin/package/compression/ZlibDecompressor.h b/src/bin/package/compression/ZlibDecompressor.h new file mode 100644 index 0000000000..52af867ac1 --- /dev/null +++ b/src/bin/package/compression/ZlibDecompressor.h @@ -0,0 +1,23 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ZLIB_DECOMPRESSOR_H +#define ZLIB_DECOMPRESSOR_H + + +#include "ZlibCompressionBase.h" + + +class ZlibDecompressor : public ZlibCompressionBase { +public: + ZlibDecompressor(); + ~ZlibDecompressor(); + + status_t Decompress(const void* input, size_t inputSize, + void* output, size_t outputSize, + size_t& _uncompressedSize); +}; + + +#endif // ZLIB_DECOMPRESSOR_H