Add B[Zlib]CompressionAlgorithm
* BCompressionAlgorithm is a base class for classes that provide compression/decompression functionality. There are methods for compressing/decompressing a single buffer and factory methods for a compressing/decompressing input/output BDataIO. * BZlibCompressionAlgorithm is a BCompressionAlgorithm implementation using zlib.
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
#include <../private/support/CompressionAlgorithm.h>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include <../private/support/ZlibCompressionAlgorithm.h>
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _COMPRESSION_ALGORITHM_H_
|
||||||
|
#define _COMPRESSION_ALGORITHM_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <DataIO.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BCompressionParameters {
|
||||||
|
public:
|
||||||
|
BCompressionParameters();
|
||||||
|
virtual ~BCompressionParameters();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BDecompressionParameters {
|
||||||
|
public:
|
||||||
|
BDecompressionParameters();
|
||||||
|
virtual ~BDecompressionParameters();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BCompressionAlgorithm {
|
||||||
|
public:
|
||||||
|
BCompressionAlgorithm();
|
||||||
|
virtual ~BCompressionAlgorithm();
|
||||||
|
|
||||||
|
virtual status_t CreateCompressingInputStream(BDataIO* input,
|
||||||
|
const BCompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
virtual status_t CreateCompressingOutputStream(BDataIO* output,
|
||||||
|
const BCompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
virtual status_t CreateDecompressingInputStream(BDataIO* input,
|
||||||
|
const BDecompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
virtual status_t CreateDecompressingOutputStream(BDataIO* output,
|
||||||
|
const BDecompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
|
||||||
|
virtual status_t CompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output,
|
||||||
|
size_t outputSize, size_t& _compressedSize,
|
||||||
|
const BCompressionParameters* parameters
|
||||||
|
= NULL);
|
||||||
|
virtual status_t DecompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output,
|
||||||
|
size_t outputSize,
|
||||||
|
size_t& _uncompressedSize,
|
||||||
|
const BDecompressionParameters* parameters
|
||||||
|
= NULL);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class BAbstractStream;
|
||||||
|
class BAbstractInputStream;
|
||||||
|
class BAbstractOutputStream;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BCompressionAlgorithm::BAbstractStream : public BDataIO {
|
||||||
|
public:
|
||||||
|
BAbstractStream();
|
||||||
|
virtual ~BAbstractStream();
|
||||||
|
|
||||||
|
status_t Init(size_t bufferSize);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual status_t ProcessData(const void* input, size_t inputSize,
|
||||||
|
void* output, size_t outputSize,
|
||||||
|
size_t& bytesConsumed,
|
||||||
|
size_t& bytesProduced) = 0;
|
||||||
|
// must consume or produce at least 1 byte
|
||||||
|
// or return an error
|
||||||
|
virtual status_t FlushPendingData(void* output,
|
||||||
|
size_t outputSize,
|
||||||
|
size_t& bytesProduced) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8* fBuffer;
|
||||||
|
size_t fBufferCapacity;
|
||||||
|
size_t fBufferOffset;
|
||||||
|
size_t fBufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BCompressionAlgorithm::BAbstractInputStream : public BAbstractStream {
|
||||||
|
public:
|
||||||
|
BAbstractInputStream(BDataIO* input);
|
||||||
|
virtual ~BAbstractInputStream();
|
||||||
|
|
||||||
|
virtual ssize_t Read(void* buffer, size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BDataIO* fInput;
|
||||||
|
bool fEndOfInput;
|
||||||
|
bool fNoMorePendingData;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BCompressionAlgorithm::BAbstractOutputStream : public BAbstractStream {
|
||||||
|
public:
|
||||||
|
BAbstractOutputStream(BDataIO* output);
|
||||||
|
virtual ~BAbstractOutputStream();
|
||||||
|
|
||||||
|
virtual ssize_t Write(const void* buffer, size_t size);
|
||||||
|
|
||||||
|
virtual status_t Flush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ssize_t _Write(const void* buffer, size_t size,
|
||||||
|
bool flush);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BDataIO* fOutput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _COMPRESSION_ALGORITHM_H_
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _ZLIB_COMPRESSION_ALGORITHM_H_
|
||||||
|
#define _ZLIB_COMPRESSION_ALGORITHM_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <CompressionAlgorithm.h>
|
||||||
|
|
||||||
|
|
||||||
|
// compression level
|
||||||
|
enum {
|
||||||
|
B_ZLIB_COMPRESSION_NONE = 0,
|
||||||
|
B_ZLIB_COMPRESSION_FASTEST = 1,
|
||||||
|
B_ZLIB_COMPRESSION_BEST = 9,
|
||||||
|
B_ZLIB_COMPRESSION_DEFAULT = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BZlibCompressionParameters : public BCompressionParameters {
|
||||||
|
public:
|
||||||
|
BZlibCompressionParameters(
|
||||||
|
int compressionLevel
|
||||||
|
= B_ZLIB_COMPRESSION_DEFAULT);
|
||||||
|
virtual ~BZlibCompressionParameters();
|
||||||
|
|
||||||
|
int32 CompressionLevel() const;
|
||||||
|
void SetCompressionLevel(int32 level);
|
||||||
|
|
||||||
|
size_t BufferSize() const;
|
||||||
|
void SetBufferSize(size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 fCompressionLevel;
|
||||||
|
size_t fBufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BZlibDecompressionParameters : public BDecompressionParameters {
|
||||||
|
public:
|
||||||
|
BZlibDecompressionParameters();
|
||||||
|
virtual ~BZlibDecompressionParameters();
|
||||||
|
|
||||||
|
size_t BufferSize() const;
|
||||||
|
void SetBufferSize(size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t fBufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BZlibCompressionAlgorithm : public BCompressionAlgorithm {
|
||||||
|
public:
|
||||||
|
BZlibCompressionAlgorithm();
|
||||||
|
virtual ~BZlibCompressionAlgorithm();
|
||||||
|
|
||||||
|
virtual status_t CreateCompressingInputStream(BDataIO* input,
|
||||||
|
const BCompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
virtual status_t CreateCompressingOutputStream(BDataIO* output,
|
||||||
|
const BCompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
virtual status_t CreateDecompressingInputStream(BDataIO* input,
|
||||||
|
const BDecompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
virtual status_t CreateDecompressingOutputStream(BDataIO* output,
|
||||||
|
const BDecompressionParameters* parameters,
|
||||||
|
BDataIO*& _stream);
|
||||||
|
|
||||||
|
virtual status_t CompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output,
|
||||||
|
size_t outputSize, size_t& _compressedSize,
|
||||||
|
const BCompressionParameters* parameters
|
||||||
|
= NULL);
|
||||||
|
virtual status_t DecompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output,
|
||||||
|
size_t outputSize,
|
||||||
|
size_t& _uncompressedSize,
|
||||||
|
const BDecompressionParameters* parameters
|
||||||
|
= NULL);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CompressionStrategy;
|
||||||
|
struct DecompressionStrategy;
|
||||||
|
|
||||||
|
template<typename BaseClass, typename Strategy> struct Stream;
|
||||||
|
template<typename BaseClass, typename Strategy>
|
||||||
|
friend struct Stream;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static status_t _TranslateZlibError(int error);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _ZLIB_COMPRESSION_ALGORITHM_H_
|
||||||
@@ -10,6 +10,7 @@ BuildPlatformMergeObjectPIC <libbe_build>support_kit.o :
|
|||||||
Archivable.cpp
|
Archivable.cpp
|
||||||
BlockCache.cpp
|
BlockCache.cpp
|
||||||
ByteOrder.cpp
|
ByteOrder.cpp
|
||||||
|
CompressionAlgorithm.cpp
|
||||||
DataIO.cpp
|
DataIO.cpp
|
||||||
Flattenable.cpp
|
Flattenable.cpp
|
||||||
List.cpp
|
List.cpp
|
||||||
@@ -18,6 +19,7 @@ BuildPlatformMergeObjectPIC <libbe_build>support_kit.o :
|
|||||||
Referenceable.cpp
|
Referenceable.cpp
|
||||||
String.cpp
|
String.cpp
|
||||||
StringList.cpp
|
StringList.cpp
|
||||||
|
ZlibCompressionAlgorithm.cpp
|
||||||
ZlibCompressionBase.cpp
|
ZlibCompressionBase.cpp
|
||||||
ZlibCompressor.cpp
|
ZlibCompressor.cpp
|
||||||
ZlibDecompressor.cpp
|
ZlibDecompressor.cpp
|
||||||
|
|||||||
@@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <CompressionAlgorithm.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Errors.h>
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BCompressionParameters
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionParameters::BCompressionParameters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionParameters::~BCompressionParameters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDecompressionParameters
|
||||||
|
|
||||||
|
|
||||||
|
BDecompressionParameters::BDecompressionParameters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BDecompressionParameters::~BDecompressionParameters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BCompressionAlgorithm
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BCompressionAlgorithm()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::~BCompressionAlgorithm()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::CreateCompressingInputStream(BDataIO* input,
|
||||||
|
const BCompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::CreateCompressingOutputStream(BDataIO* output,
|
||||||
|
const BCompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::CreateDecompressingInputStream(BDataIO* input,
|
||||||
|
const BDecompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
|
||||||
|
const BDecompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::CompressBuffer(const void* input, size_t inputSize,
|
||||||
|
void* output, size_t outputSize, size_t& _compressedSize,
|
||||||
|
const BCompressionParameters* parameters)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::DecompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output, size_t outputSize,
|
||||||
|
size_t& _uncompressedSize, const BDecompressionParameters* parameters)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BAbstractStream
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BAbstractStream::BAbstractStream()
|
||||||
|
:
|
||||||
|
BDataIO(),
|
||||||
|
fBuffer(NULL),
|
||||||
|
fBufferCapacity(0),
|
||||||
|
fBufferOffset(0),
|
||||||
|
fBufferSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BAbstractStream::~BAbstractStream()
|
||||||
|
{
|
||||||
|
free(fBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::BAbstractStream::Init(size_t bufferSize)
|
||||||
|
{
|
||||||
|
fBuffer = (uint8*)malloc(bufferSize);
|
||||||
|
fBufferCapacity = bufferSize;
|
||||||
|
|
||||||
|
return fBuffer != NULL ? B_OK : B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BAbstractInputStream
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BAbstractInputStream::BAbstractInputStream(
|
||||||
|
BDataIO* input)
|
||||||
|
:
|
||||||
|
BAbstractStream(),
|
||||||
|
fInput(input),
|
||||||
|
fEndOfInput(false),
|
||||||
|
fNoMorePendingData(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BAbstractInputStream::~BAbstractInputStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
BCompressionAlgorithm::BAbstractInputStream::Read(void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size_t bytesRemaining = size;
|
||||||
|
uint8* output = (uint8*)buffer;
|
||||||
|
|
||||||
|
while (bytesRemaining > 0) {
|
||||||
|
// process the data still in the input buffer
|
||||||
|
if (fBufferSize > 0) {
|
||||||
|
size_t bytesConsumed;
|
||||||
|
size_t bytesProduced;
|
||||||
|
status_t error = ProcessData(fBuffer + fBufferOffset, fBufferSize,
|
||||||
|
output, bytesRemaining, bytesConsumed, bytesProduced);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
fBufferOffset += bytesConsumed;
|
||||||
|
fBufferSize -= bytesConsumed;
|
||||||
|
output += bytesProduced;
|
||||||
|
bytesRemaining -= bytesProduced;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We couldn't process anything, because we don't have any or not enough
|
||||||
|
// bytes in the input buffer.
|
||||||
|
|
||||||
|
if (fEndOfInput)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Move any remaining data to the start of the buffer.
|
||||||
|
if (fBufferSize > 0) {
|
||||||
|
if (fBufferSize == fBufferCapacity)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (fBufferOffset > 0)
|
||||||
|
memmove(fBuffer, fBuffer + fBufferOffset, fBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fBufferOffset = 0;
|
||||||
|
|
||||||
|
// read from the source
|
||||||
|
ssize_t bytesRead = fInput->Read(fBuffer + fBufferSize,
|
||||||
|
fBufferCapacity - fBufferSize);
|
||||||
|
if (bytesRead < 0)
|
||||||
|
return bytesRead;
|
||||||
|
if (bytesRead == 0) {
|
||||||
|
fEndOfInput = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fBufferSize += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've reached the end of the input and still have room in the output
|
||||||
|
// buffer, we have consumed all input data and want to flush all pending
|
||||||
|
// data, now.
|
||||||
|
if (fEndOfInput && bytesRemaining > 0 && !fNoMorePendingData) {
|
||||||
|
size_t bytesProduced;
|
||||||
|
status_t error = FlushPendingData(output, bytesRemaining,
|
||||||
|
bytesProduced);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (bytesProduced < bytesRemaining)
|
||||||
|
fNoMorePendingData = true;
|
||||||
|
|
||||||
|
output += bytesProduced;
|
||||||
|
bytesRemaining -= bytesProduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size - bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BAbstractOutputStream
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BAbstractOutputStream::BAbstractOutputStream(
|
||||||
|
BDataIO* output)
|
||||||
|
:
|
||||||
|
BAbstractStream(),
|
||||||
|
fOutput(output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BCompressionAlgorithm::BAbstractOutputStream::~BAbstractOutputStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
BCompressionAlgorithm::BAbstractOutputStream::Write(const void* buffer,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size_t bytesRemaining = size;
|
||||||
|
uint8* input = (uint8*)buffer;
|
||||||
|
|
||||||
|
while (bytesRemaining > 0) {
|
||||||
|
// try to process more data
|
||||||
|
if (fBufferSize < fBufferCapacity) {
|
||||||
|
size_t bytesConsumed;
|
||||||
|
size_t bytesProduced;
|
||||||
|
status_t error = ProcessData(input, bytesRemaining,
|
||||||
|
fBuffer + fBufferSize, fBufferCapacity - fBufferSize,
|
||||||
|
bytesConsumed, bytesProduced);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
input += bytesConsumed;
|
||||||
|
bytesRemaining -= bytesConsumed;
|
||||||
|
fBufferSize += bytesProduced;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We couldn't process anything, because we don't have any or not enough
|
||||||
|
// room in the output buffer.
|
||||||
|
|
||||||
|
if (fBufferSize == 0)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
// write to the target
|
||||||
|
ssize_t bytesWritten = fOutput->Write(fBuffer, fBufferSize);
|
||||||
|
if (bytesWritten < 0)
|
||||||
|
return bytesWritten;
|
||||||
|
if (bytesWritten == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Move any remaining data to the start of the buffer.
|
||||||
|
fBufferSize -= bytesWritten;
|
||||||
|
if (fBufferSize > 0)
|
||||||
|
memmove(fBuffer, fBuffer + bytesWritten, fBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size - bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BCompressionAlgorithm::BAbstractOutputStream::Flush()
|
||||||
|
{
|
||||||
|
bool noMorePendingData = false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// let the derived class flush all pending data
|
||||||
|
if (fBufferSize < fBufferCapacity && !noMorePendingData) {
|
||||||
|
size_t bytesProduced;
|
||||||
|
status_t error = FlushPendingData(fBuffer + fBufferSize,
|
||||||
|
fBufferCapacity - fBufferSize, bytesProduced);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
noMorePendingData = bytesProduced < fBufferCapacity - fBufferSize;
|
||||||
|
|
||||||
|
fBufferSize += bytesProduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write buffered data to output
|
||||||
|
if (fBufferSize == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
status_t error = fOutput->WriteExactly(fBuffer, fBufferSize);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
fBufferSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fOutput->Flush();
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
BufferedDataIO.cpp
|
BufferedDataIO.cpp
|
||||||
BufferIO.cpp
|
BufferIO.cpp
|
||||||
ByteOrder.cpp
|
ByteOrder.cpp
|
||||||
|
CompressionAlgorithm.cpp
|
||||||
DataIO.cpp
|
DataIO.cpp
|
||||||
DateTime.cpp
|
DateTime.cpp
|
||||||
Flattenable.cpp
|
Flattenable.cpp
|
||||||
@@ -36,6 +37,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
StringList.cpp
|
StringList.cpp
|
||||||
Url.cpp
|
Url.cpp
|
||||||
Uuid.cpp
|
Uuid.cpp
|
||||||
|
ZlibCompressionAlgorithm.cpp
|
||||||
ZlibCompressionBase.cpp
|
ZlibCompressionBase.cpp
|
||||||
ZlibCompressor.cpp
|
ZlibCompressor.cpp
|
||||||
ZlibDecompressor.cpp
|
ZlibDecompressor.cpp
|
||||||
|
|||||||
@@ -0,0 +1,407 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ZlibCompressionAlgorithm.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include <DataIO.h>
|
||||||
|
|
||||||
|
|
||||||
|
// build compression support only for userland
|
||||||
|
#if !defined(_KERNEL_MODE) && !defined(_BOOT_MODE)
|
||||||
|
# define B_ZLIB_COMPRESSION_SUPPORT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static const size_t kMinBufferSize = 1024;
|
||||||
|
static const size_t kMaxBufferSize = 1024 * 1024;
|
||||||
|
static const size_t kDefaultBufferSize = 4 * 1024;
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
sanitize_buffer_size(size_t size)
|
||||||
|
{
|
||||||
|
if (size < kMinBufferSize)
|
||||||
|
return kMinBufferSize;
|
||||||
|
return std::min(size, kMaxBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BZlibCompressionParameters
|
||||||
|
|
||||||
|
|
||||||
|
BZlibCompressionParameters::BZlibCompressionParameters(
|
||||||
|
int compressionLevel)
|
||||||
|
:
|
||||||
|
BCompressionParameters(),
|
||||||
|
fCompressionLevel(compressionLevel),
|
||||||
|
fBufferSize(kDefaultBufferSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BZlibCompressionParameters::~BZlibCompressionParameters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BZlibCompressionParameters::CompressionLevel() const
|
||||||
|
{
|
||||||
|
return fCompressionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BZlibCompressionParameters::SetCompressionLevel(int32 level)
|
||||||
|
{
|
||||||
|
fCompressionLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
BZlibCompressionParameters::BufferSize() const
|
||||||
|
{
|
||||||
|
return fBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BZlibCompressionParameters::SetBufferSize(size_t size)
|
||||||
|
{
|
||||||
|
fBufferSize = sanitize_buffer_size(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BZlibDecompressionParameters
|
||||||
|
|
||||||
|
|
||||||
|
BZlibDecompressionParameters::BZlibDecompressionParameters()
|
||||||
|
:
|
||||||
|
BDecompressionParameters(),
|
||||||
|
fBufferSize(kDefaultBufferSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BZlibDecompressionParameters::~BZlibDecompressionParameters()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
BZlibDecompressionParameters::BufferSize() const
|
||||||
|
{
|
||||||
|
return fBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BZlibDecompressionParameters::SetBufferSize(size_t size)
|
||||||
|
{
|
||||||
|
fBufferSize = sanitize_buffer_size(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - CompressionStrategy
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef B_ZLIB_COMPRESSION_SUPPORT
|
||||||
|
|
||||||
|
|
||||||
|
struct BZlibCompressionAlgorithm::CompressionStrategy {
|
||||||
|
typedef BZlibCompressionParameters Parameters;
|
||||||
|
|
||||||
|
static const bool kNeedsFinalFlush = true;
|
||||||
|
|
||||||
|
static int Init(z_stream& stream,
|
||||||
|
const BZlibCompressionParameters* parameters)
|
||||||
|
{
|
||||||
|
return deflateInit(&stream,
|
||||||
|
parameters != NULL
|
||||||
|
? parameters->CompressionLevel()
|
||||||
|
: B_ZLIB_COMPRESSION_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Uninit(z_stream& stream)
|
||||||
|
{
|
||||||
|
deflateEnd(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Process(z_stream& stream, bool flush)
|
||||||
|
{
|
||||||
|
return deflate(&stream, flush ? Z_FINISH : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // B_ZLIB_COMPRESSION_SUPPORT
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DecompressionStrategy
|
||||||
|
|
||||||
|
|
||||||
|
struct BZlibCompressionAlgorithm::DecompressionStrategy {
|
||||||
|
typedef BZlibDecompressionParameters Parameters;
|
||||||
|
|
||||||
|
static const bool kNeedsFinalFlush = false;
|
||||||
|
|
||||||
|
static int Init(z_stream& stream,
|
||||||
|
const BZlibDecompressionParameters* /*parameters*/)
|
||||||
|
{
|
||||||
|
return inflateInit(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Uninit(z_stream& stream)
|
||||||
|
{
|
||||||
|
inflateEnd(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Process(z_stream& stream, bool flush)
|
||||||
|
{
|
||||||
|
return inflate(&stream, flush ? Z_FINISH : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Stream
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BaseClass, typename Strategy>
|
||||||
|
struct BZlibCompressionAlgorithm::Stream : BaseClass {
|
||||||
|
Stream(BDataIO* io)
|
||||||
|
:
|
||||||
|
BaseClass(io),
|
||||||
|
fStreamInitialized(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Stream()
|
||||||
|
{
|
||||||
|
if (fStreamInitialized) {
|
||||||
|
if (Strategy::kNeedsFinalFlush)
|
||||||
|
this->Flush();
|
||||||
|
Strategy::Uninit(fStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(const typename Strategy::Parameters* parameters)
|
||||||
|
{
|
||||||
|
status_t error = this->BaseClass::Init(parameters->BufferSize());
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
memset(&fStream, 0, sizeof(fStream));
|
||||||
|
|
||||||
|
int zlibError = Strategy::Init(fStream, parameters);
|
||||||
|
if (zlibError != Z_OK)
|
||||||
|
return _TranslateZlibError(zlibError);
|
||||||
|
|
||||||
|
fStreamInitialized = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t ProcessData(const void* input, size_t inputSize,
|
||||||
|
void* output, size_t outputSize, size_t& bytesConsumed,
|
||||||
|
size_t& bytesProduced)
|
||||||
|
{
|
||||||
|
return _ProcessData(input, inputSize, output, outputSize,
|
||||||
|
bytesConsumed, bytesProduced, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t FlushPendingData(void* output, size_t outputSize,
|
||||||
|
size_t& bytesProduced)
|
||||||
|
{
|
||||||
|
size_t bytesConsumed;
|
||||||
|
return _ProcessData(NULL, 0, output, outputSize,
|
||||||
|
bytesConsumed, bytesProduced, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BaseParameters>
|
||||||
|
static status_t Create(BDataIO* io, BaseParameters* _parameters,
|
||||||
|
BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
const typename Strategy::Parameters* parameters
|
||||||
|
= dynamic_cast<const typename Strategy::Parameters*>(_parameters);
|
||||||
|
Stream* stream = new(std::nothrow) Stream(io);
|
||||||
|
if (stream == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = stream->Init(parameters);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete stream;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
_stream = stream;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _ProcessData(const void* input, size_t inputSize,
|
||||||
|
void* output, size_t outputSize, size_t& bytesConsumed,
|
||||||
|
size_t& bytesProduced, bool flush)
|
||||||
|
{
|
||||||
|
fStream.next_in = (Bytef*)input;
|
||||||
|
fStream.avail_in = inputSize;
|
||||||
|
fStream.next_out = (Bytef*)output;
|
||||||
|
fStream.avail_out = outputSize;
|
||||||
|
|
||||||
|
int zlibError = Strategy::Process(fStream, flush);
|
||||||
|
if (zlibError != Z_OK) {
|
||||||
|
if (zlibError == Z_STREAM_END) {
|
||||||
|
if (fStream.avail_in != 0)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
} else
|
||||||
|
return _TranslateZlibError(zlibError);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesConsumed = inputSize - (size_t)fStream.avail_in;
|
||||||
|
bytesProduced = outputSize - (size_t)fStream.avail_out;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
z_stream fStream;
|
||||||
|
bool fStreamInitialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BZlibCompressionAlgorithm
|
||||||
|
|
||||||
|
|
||||||
|
BZlibCompressionAlgorithm::BZlibCompressionAlgorithm()
|
||||||
|
:
|
||||||
|
BCompressionAlgorithm()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BZlibCompressionAlgorithm::~BZlibCompressionAlgorithm()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BZlibCompressionAlgorithm::CreateCompressingInputStream(BDataIO* input,
|
||||||
|
const BCompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
#ifdef B_ZLIB_COMPRESSION_SUPPORT
|
||||||
|
return Stream<BAbstractInputStream, CompressionStrategy>::Create(
|
||||||
|
input, parameters, _stream);
|
||||||
|
#else
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BZlibCompressionAlgorithm::CreateCompressingOutputStream(BDataIO* output,
|
||||||
|
const BCompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
#ifdef B_ZLIB_COMPRESSION_SUPPORT
|
||||||
|
return Stream<BAbstractOutputStream, CompressionStrategy>::Create(
|
||||||
|
output, parameters, _stream);
|
||||||
|
#else
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BZlibCompressionAlgorithm::CreateDecompressingInputStream(BDataIO* input,
|
||||||
|
const BDecompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
return Stream<BAbstractInputStream, DecompressionStrategy>::Create(
|
||||||
|
input, parameters, _stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BZlibCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
|
||||||
|
const BDecompressionParameters* parameters, BDataIO*& _stream)
|
||||||
|
{
|
||||||
|
return Stream<BAbstractOutputStream, DecompressionStrategy>::Create(
|
||||||
|
output, parameters, _stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BZlibCompressionAlgorithm::CompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output, size_t outputSize, size_t& _compressedSize,
|
||||||
|
const BCompressionParameters* parameters)
|
||||||
|
{
|
||||||
|
#ifdef B_ZLIB_COMPRESSION_SUPPORT
|
||||||
|
const BZlibCompressionParameters* zlibParameters
|
||||||
|
= dynamic_cast<const BZlibCompressionParameters*>(parameters);
|
||||||
|
int compressionLevel = zlibParameters != NULL
|
||||||
|
? zlibParameters->CompressionLevel()
|
||||||
|
: B_ZLIB_COMPRESSION_DEFAULT;
|
||||||
|
|
||||||
|
uLongf bytesUsed = outputSize;
|
||||||
|
int zlibError = compress2((Bytef*)output, &bytesUsed, (const Bytef*)input,
|
||||||
|
(uLong)inputSize, compressionLevel);
|
||||||
|
if (zlibError != Z_OK)
|
||||||
|
return _TranslateZlibError(zlibError);
|
||||||
|
|
||||||
|
_compressedSize = (size_t)bytesUsed;
|
||||||
|
return B_OK;
|
||||||
|
#else
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BZlibCompressionAlgorithm::DecompressBuffer(const void* input,
|
||||||
|
size_t inputSize, void* output, size_t outputSize,
|
||||||
|
size_t& _uncompressedSize, const BDecompressionParameters* parameters)
|
||||||
|
{
|
||||||
|
uLongf bytesUsed = outputSize;
|
||||||
|
int zlibError = uncompress((Bytef*)output, &bytesUsed, (const Bytef*)input,
|
||||||
|
(uLong)inputSize);
|
||||||
|
if (zlibError != Z_OK)
|
||||||
|
return _TranslateZlibError(zlibError);
|
||||||
|
|
||||||
|
_uncompressedSize = (size_t)bytesUsed;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ status_t
|
||||||
|
BZlibCompressionAlgorithm::_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user