2 * Copyright 2017, Jérôme Duval.
3 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
8 #include <ZstdCompressionAlgorithm.h>
18 #include <zstd_errors.h>
24 // build compression support only for userland
25 #if defined(ZSTD_ENABLED) && !defined(_KERNEL_MODE) && !defined(_BOOT_MODE)
26 # define B_ZSTD_COMPRESSION_SUPPORT 1
30 static const size_t kMinBufferSize
= 1024;
31 static const size_t kMaxBufferSize
= 1024 * 1024;
32 static const size_t kDefaultBufferSize
= 4 * 1024;
36 sanitize_buffer_size(size_t size
)
38 if (size
< kMinBufferSize
)
39 return kMinBufferSize
;
40 return std::min(size
, kMaxBufferSize
);
44 // #pragma mark - BZstdCompressionParameters
47 BZstdCompressionParameters::BZstdCompressionParameters(
50 BCompressionParameters(),
51 fCompressionLevel(compressionLevel
),
52 fBufferSize(kDefaultBufferSize
)
57 BZstdCompressionParameters::~BZstdCompressionParameters()
63 BZstdCompressionParameters::CompressionLevel() const
65 return fCompressionLevel
;
70 BZstdCompressionParameters::SetCompressionLevel(int32 level
)
72 fCompressionLevel
= level
;
77 BZstdCompressionParameters::BufferSize() const
84 BZstdCompressionParameters::SetBufferSize(size_t size
)
86 fBufferSize
= sanitize_buffer_size(size
);
90 // #pragma mark - BZstdDecompressionParameters
93 BZstdDecompressionParameters::BZstdDecompressionParameters()
95 BDecompressionParameters(),
96 fBufferSize(kDefaultBufferSize
)
101 BZstdDecompressionParameters::~BZstdDecompressionParameters()
107 BZstdDecompressionParameters::BufferSize() const
114 BZstdDecompressionParameters::SetBufferSize(size_t size
)
116 fBufferSize
= sanitize_buffer_size(size
);
120 // #pragma mark - CompressionStrategy
123 #ifdef B_ZSTD_COMPRESSION_SUPPORT
126 struct BZstdCompressionAlgorithm::CompressionStrategy
{
127 typedef BZstdCompressionParameters Parameters
;
129 static const bool kNeedsFinalFlush
= true;
131 static size_t Init(ZSTD_CStream
**stream
,
132 const BZstdCompressionParameters
* parameters
)
134 int32 compressionLevel
= B_ZSTD_COMPRESSION_DEFAULT
;
135 if (parameters
!= NULL
) {
136 compressionLevel
= parameters
->CompressionLevel();
139 *stream
= ZSTD_createCStream();
140 return ZSTD_initCStream(*stream
, compressionLevel
);
143 static void Uninit(ZSTD_CStream
*stream
)
145 ZSTD_freeCStream(stream
);
148 static size_t Process(ZSTD_CStream
*stream
, ZSTD_inBuffer
*input
,
149 ZSTD_outBuffer
*output
, bool flush
)
152 return ZSTD_flushStream(stream
, output
);
154 return ZSTD_compressStream(stream
, output
, input
);
159 #endif // B_ZSTD_COMPRESSION_SUPPORT
162 // #pragma mark - DecompressionStrategy
168 struct BZstdCompressionAlgorithm::DecompressionStrategy
{
169 typedef BZstdDecompressionParameters Parameters
;
171 static const bool kNeedsFinalFlush
= false;
173 static size_t Init(ZSTD_DStream
**stream
,
174 const BZstdDecompressionParameters
* /*parameters*/)
176 *stream
= ZSTD_createDStream();
177 return ZSTD_initDStream(*stream
);
180 static void Uninit(ZSTD_DStream
*stream
)
182 ZSTD_freeDStream(stream
);
185 static size_t Process(ZSTD_DStream
*stream
, ZSTD_inBuffer
*input
,
186 ZSTD_outBuffer
*output
, bool flush
)
188 return ZSTD_decompressStream(stream
, output
, input
);
194 // #pragma mark - Stream
197 template<typename BaseClass
, typename Strategy
, typename StreamType
>
198 struct BZstdCompressionAlgorithm::Stream
: BaseClass
{
202 fStreamInitialized(false)
208 if (fStreamInitialized
) {
209 if (Strategy::kNeedsFinalFlush
)
211 Strategy::Uninit(fStream
);
215 status_t
Init(const typename
Strategy::Parameters
* parameters
)
217 status_t error
= this->BaseClass::Init(
218 parameters
!= NULL
? parameters
->BufferSize() : kDefaultBufferSize
);
222 size_t zstdError
= Strategy::Init(&fStream
, parameters
);
223 if (ZSTD_getErrorCode(zstdError
) != ZSTD_error_no_error
)
224 return _TranslateZstdError(zstdError
);
226 fStreamInitialized
= true;
230 virtual status_t
ProcessData(const void* input
, size_t inputSize
,
231 void* output
, size_t outputSize
, size_t& bytesConsumed
,
232 size_t& bytesProduced
)
234 return _ProcessData(input
, inputSize
, output
, outputSize
,
235 bytesConsumed
, bytesProduced
, false);
238 virtual status_t
FlushPendingData(void* output
, size_t outputSize
,
239 size_t& bytesProduced
)
241 size_t bytesConsumed
;
242 return _ProcessData(NULL
, 0, output
, outputSize
,
243 bytesConsumed
, bytesProduced
, true);
246 template<typename BaseParameters
>
247 static status_t
Create(BDataIO
* io
, BaseParameters
* _parameters
,
250 const typename
Strategy::Parameters
* parameters
252 = static_cast<const typename
Strategy::Parameters
*>(_parameters
);
254 = dynamic_cast<const typename
Strategy::Parameters
*>(_parameters
);
256 Stream
* stream
= new(std::nothrow
) Stream(io
);
260 status_t error
= stream
->Init(parameters
);
271 status_t
_ProcessData(const void* input
, size_t inputSize
,
272 void* output
, size_t outputSize
, size_t& bytesConsumed
,
273 size_t& bytesProduced
, bool flush
)
275 inBuffer
.src
= input
;
277 inBuffer
.size
= inputSize
;
278 outBuffer
.dst
= output
;
280 outBuffer
.size
= outputSize
;
282 size_t zstdError
= Strategy::Process(fStream
, &inBuffer
, &outBuffer
, flush
);
283 if (ZSTD_getErrorCode(zstdError
) != ZSTD_error_no_error
)
284 return _TranslateZstdError(zstdError
);
286 bytesConsumed
= inBuffer
.pos
;
287 bytesProduced
= outBuffer
.pos
;
292 bool fStreamInitialized
;
294 ZSTD_inBuffer inBuffer
;
295 ZSTD_outBuffer outBuffer
;
299 #endif // ZSTD_ENABLED
302 // #pragma mark - BZstdCompressionAlgorithm
305 BZstdCompressionAlgorithm::BZstdCompressionAlgorithm()
307 BCompressionAlgorithm()
312 BZstdCompressionAlgorithm::~BZstdCompressionAlgorithm()
318 BZstdCompressionAlgorithm::CreateCompressingInputStream(BDataIO
* input
,
319 const BCompressionParameters
* parameters
, BDataIO
*& _stream
)
321 #ifdef B_ZSTD_COMPRESSION_SUPPORT
322 return Stream
<BAbstractInputStream
, CompressionStrategy
, ZSTD_CStream
>::Create(
323 input
, parameters
, _stream
);
325 return B_NOT_SUPPORTED
;
331 BZstdCompressionAlgorithm::CreateCompressingOutputStream(BDataIO
* output
,
332 const BCompressionParameters
* parameters
, BDataIO
*& _stream
)
334 #ifdef B_ZSTD_COMPRESSION_SUPPORT
335 return Stream
<BAbstractOutputStream
, CompressionStrategy
, ZSTD_CStream
>::Create(
336 output
, parameters
, _stream
);
338 return B_NOT_SUPPORTED
;
344 BZstdCompressionAlgorithm::CreateDecompressingInputStream(BDataIO
* input
,
345 const BDecompressionParameters
* parameters
, BDataIO
*& _stream
)
348 return Stream
<BAbstractInputStream
, DecompressionStrategy
, ZSTD_DStream
>::Create(
349 input
, parameters
, _stream
);
351 return B_NOT_SUPPORTED
;
357 BZstdCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO
* output
,
358 const BDecompressionParameters
* parameters
, BDataIO
*& _stream
)
361 return Stream
<BAbstractOutputStream
, DecompressionStrategy
, ZSTD_DStream
>::Create(
362 output
, parameters
, _stream
);
364 return B_NOT_SUPPORTED
;
370 BZstdCompressionAlgorithm::CompressBuffer(const void* input
,
371 size_t inputSize
, void* output
, size_t outputSize
, size_t& _compressedSize
,
372 const BCompressionParameters
* parameters
)
374 #ifdef B_ZSTD_COMPRESSION_SUPPORT
375 const BZstdCompressionParameters
* zstdParameters
376 = dynamic_cast<const BZstdCompressionParameters
*>(parameters
);
377 int compressionLevel
= zstdParameters
!= NULL
378 ? zstdParameters
->CompressionLevel()
379 : B_ZSTD_COMPRESSION_DEFAULT
;
381 size_t zstdError
= ZSTD_compress(output
, outputSize
, input
,
382 inputSize
, compressionLevel
);
383 if (ZSTD_isError(zstdError
))
384 return _TranslateZstdError(zstdError
);
386 _compressedSize
= zstdError
;
389 return B_NOT_SUPPORTED
;
395 BZstdCompressionAlgorithm::DecompressBuffer(const void* input
,
396 size_t inputSize
, void* output
, size_t outputSize
,
397 size_t& _uncompressedSize
, const BDecompressionParameters
* parameters
)
400 size_t zstdError
= ZSTD_decompress(output
, outputSize
, input
,
402 if (ZSTD_isError(zstdError
))
403 return _TranslateZstdError(zstdError
);
405 _uncompressedSize
= zstdError
;
408 return B_NOT_SUPPORTED
;
414 BZstdCompressionAlgorithm::_TranslateZstdError(size_t error
)
417 switch (ZSTD_getErrorCode(error
)) {
418 case ZSTD_error_no_error
:
420 case ZSTD_error_seekableIO
:
422 case ZSTD_error_corruption_detected
:
423 case ZSTD_error_checksum_wrong
:
425 case ZSTD_error_version_unsupported
:
431 return B_NOT_SUPPORTED
;