2 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include <ZlibCompressionAlgorithm.h>
20 // build compression support only for userland
21 #if !defined(_KERNEL_MODE) && !defined(_BOOT_MODE)
22 # define B_ZLIB_COMPRESSION_SUPPORT 1
26 static const size_t kMinBufferSize
= 1024;
27 static const size_t kMaxBufferSize
= 1024 * 1024;
28 static const size_t kDefaultBufferSize
= 4 * 1024;
32 sanitize_buffer_size(size_t size
)
34 if (size
< kMinBufferSize
)
35 return kMinBufferSize
;
36 return std::min(size
, kMaxBufferSize
);
40 // #pragma mark - BZlibCompressionParameters
43 BZlibCompressionParameters::BZlibCompressionParameters(
46 BCompressionParameters(),
47 fCompressionLevel(compressionLevel
),
48 fBufferSize(kDefaultBufferSize
),
54 BZlibCompressionParameters::~BZlibCompressionParameters()
60 BZlibCompressionParameters::CompressionLevel() const
62 return fCompressionLevel
;
67 BZlibCompressionParameters::SetCompressionLevel(int32 level
)
69 fCompressionLevel
= level
;
74 BZlibCompressionParameters::BufferSize() const
81 BZlibCompressionParameters::SetBufferSize(size_t size
)
83 fBufferSize
= sanitize_buffer_size(size
);
88 BZlibCompressionParameters::IsGzipFormat() const
95 BZlibCompressionParameters::SetGzipFormat(bool gzipFormat
)
97 fGzipFormat
= gzipFormat
;
101 // #pragma mark - BZlibDecompressionParameters
104 BZlibDecompressionParameters::BZlibDecompressionParameters()
106 BDecompressionParameters(),
107 fBufferSize(kDefaultBufferSize
)
112 BZlibDecompressionParameters::~BZlibDecompressionParameters()
118 BZlibDecompressionParameters::BufferSize() const
125 BZlibDecompressionParameters::SetBufferSize(size_t size
)
127 fBufferSize
= sanitize_buffer_size(size
);
131 // #pragma mark - CompressionStrategy
134 #ifdef B_ZLIB_COMPRESSION_SUPPORT
137 struct BZlibCompressionAlgorithm::CompressionStrategy
{
138 typedef BZlibCompressionParameters Parameters
;
140 static const bool kNeedsFinalFlush
= true;
142 static int Init(z_stream
& stream
,
143 const BZlibCompressionParameters
* parameters
)
145 int32 compressionLevel
= B_ZLIB_COMPRESSION_DEFAULT
;
146 bool gzipFormat
= false;
147 if (parameters
!= NULL
) {
148 compressionLevel
= parameters
->CompressionLevel();
149 gzipFormat
= parameters
->IsGzipFormat();
152 return deflateInit2(&stream
, compressionLevel
,
154 MAX_WBITS
+ (gzipFormat
? 16 : 0),
159 static void Uninit(z_stream
& stream
)
164 static int Process(z_stream
& stream
, bool flush
)
166 return deflate(&stream
, flush
? Z_FINISH
: 0);
171 #endif // B_ZLIB_COMPRESSION_SUPPORT
174 // #pragma mark - DecompressionStrategy
177 struct BZlibCompressionAlgorithm::DecompressionStrategy
{
178 typedef BZlibDecompressionParameters Parameters
;
180 static const bool kNeedsFinalFlush
= false;
182 static int Init(z_stream
& stream
,
183 const BZlibDecompressionParameters
* /*parameters*/)
185 // auto-detect zlib/gzip header
186 return inflateInit2(&stream
, 32 + MAX_WBITS
);
189 static void Uninit(z_stream
& stream
)
194 static int Process(z_stream
& stream
, bool flush
)
196 return inflate(&stream
, flush
? Z_FINISH
: 0);
201 // #pragma mark - Stream
204 template<typename BaseClass
, typename Strategy
>
205 struct BZlibCompressionAlgorithm::Stream
: BaseClass
{
209 fStreamInitialized(false)
215 if (fStreamInitialized
) {
216 if (Strategy::kNeedsFinalFlush
)
218 Strategy::Uninit(fStream
);
222 status_t
Init(const typename
Strategy::Parameters
* parameters
)
224 status_t error
= this->BaseClass::Init(
225 parameters
!= NULL
? parameters
->BufferSize() : kDefaultBufferSize
);
229 memset(&fStream
, 0, sizeof(fStream
));
231 int zlibError
= Strategy::Init(fStream
, parameters
);
232 if (zlibError
!= Z_OK
)
233 return _TranslateZlibError(zlibError
);
235 fStreamInitialized
= true;
239 virtual status_t
ProcessData(const void* input
, size_t inputSize
,
240 void* output
, size_t outputSize
, size_t& bytesConsumed
,
241 size_t& bytesProduced
)
243 return _ProcessData(input
, inputSize
, output
, outputSize
,
244 bytesConsumed
, bytesProduced
, false);
247 virtual status_t
FlushPendingData(void* output
, size_t outputSize
,
248 size_t& bytesProduced
)
250 size_t bytesConsumed
;
251 return _ProcessData(NULL
, 0, output
, outputSize
,
252 bytesConsumed
, bytesProduced
, true);
255 template<typename BaseParameters
>
256 static status_t
Create(BDataIO
* io
, BaseParameters
* _parameters
,
259 const typename
Strategy::Parameters
* parameters
261 = static_cast<const typename
Strategy::Parameters
*>(_parameters
);
263 = dynamic_cast<const typename
Strategy::Parameters
*>(_parameters
);
265 Stream
* stream
= new(std::nothrow
) Stream(io
);
269 status_t error
= stream
->Init(parameters
);
280 status_t
_ProcessData(const void* input
, size_t inputSize
,
281 void* output
, size_t outputSize
, size_t& bytesConsumed
,
282 size_t& bytesProduced
, bool flush
)
284 fStream
.next_in
= (Bytef
*)input
;
285 fStream
.avail_in
= inputSize
;
286 fStream
.next_out
= (Bytef
*)output
;
287 fStream
.avail_out
= outputSize
;
289 int zlibError
= Strategy::Process(fStream
, flush
);
290 if (zlibError
!= Z_OK
) {
291 if (zlibError
== Z_STREAM_END
) {
292 if (fStream
.avail_in
!= 0)
295 return _TranslateZlibError(zlibError
);
298 bytesConsumed
= inputSize
- (size_t)fStream
.avail_in
;
299 bytesProduced
= outputSize
- (size_t)fStream
.avail_out
;
305 bool fStreamInitialized
;
309 // #pragma mark - BZlibCompressionAlgorithm
312 BZlibCompressionAlgorithm::BZlibCompressionAlgorithm()
314 BCompressionAlgorithm()
319 BZlibCompressionAlgorithm::~BZlibCompressionAlgorithm()
325 BZlibCompressionAlgorithm::CreateCompressingInputStream(BDataIO
* input
,
326 const BCompressionParameters
* parameters
, BDataIO
*& _stream
)
328 #ifdef B_ZLIB_COMPRESSION_SUPPORT
329 return Stream
<BAbstractInputStream
, CompressionStrategy
>::Create(
330 input
, parameters
, _stream
);
332 return B_NOT_SUPPORTED
;
338 BZlibCompressionAlgorithm::CreateCompressingOutputStream(BDataIO
* output
,
339 const BCompressionParameters
* parameters
, BDataIO
*& _stream
)
341 #ifdef B_ZLIB_COMPRESSION_SUPPORT
342 return Stream
<BAbstractOutputStream
, CompressionStrategy
>::Create(
343 output
, parameters
, _stream
);
345 return B_NOT_SUPPORTED
;
351 BZlibCompressionAlgorithm::CreateDecompressingInputStream(BDataIO
* input
,
352 const BDecompressionParameters
* parameters
, BDataIO
*& _stream
)
354 return Stream
<BAbstractInputStream
, DecompressionStrategy
>::Create(
355 input
, parameters
, _stream
);
360 BZlibCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO
* output
,
361 const BDecompressionParameters
* parameters
, BDataIO
*& _stream
)
363 return Stream
<BAbstractOutputStream
, DecompressionStrategy
>::Create(
364 output
, parameters
, _stream
);
369 BZlibCompressionAlgorithm::CompressBuffer(const void* input
,
370 size_t inputSize
, void* output
, size_t outputSize
, size_t& _compressedSize
,
371 const BCompressionParameters
* parameters
)
373 #ifdef B_ZLIB_COMPRESSION_SUPPORT
374 const BZlibCompressionParameters
* zlibParameters
375 = dynamic_cast<const BZlibCompressionParameters
*>(parameters
);
376 int compressionLevel
= zlibParameters
!= NULL
377 ? zlibParameters
->CompressionLevel()
378 : B_ZLIB_COMPRESSION_DEFAULT
;
380 uLongf bytesUsed
= outputSize
;
381 int zlibError
= compress2((Bytef
*)output
, &bytesUsed
, (const Bytef
*)input
,
382 (uLong
)inputSize
, compressionLevel
);
383 if (zlibError
!= Z_OK
)
384 return _TranslateZlibError(zlibError
);
386 _compressedSize
= (size_t)bytesUsed
;
389 return B_NOT_SUPPORTED
;
395 BZlibCompressionAlgorithm::DecompressBuffer(const void* input
,
396 size_t inputSize
, void* output
, size_t outputSize
,
397 size_t& _uncompressedSize
, const BDecompressionParameters
* parameters
)
399 uLongf bytesUsed
= outputSize
;
400 int zlibError
= uncompress((Bytef
*)output
, &bytesUsed
, (const Bytef
*)input
,
402 if (zlibError
!= Z_OK
)
403 return _TranslateZlibError(zlibError
);
405 _uncompressedSize
= (size_t)bytesUsed
;
411 BZlibCompressionAlgorithm::_TranslateZlibError(int error
)
418 // a special event (no error), but the caller doesn't seem to handle
430 return B_BUFFER_OVERFLOW
;
431 case Z_VERSION_ERROR
: