HaikuDepot: notify work status from main window
[haiku.git] / src / kits / support / ZstdCompressionAlgorithm.cpp
blobd6e0337f9906c63c6689704e6fa205687aba0ad9
1 /*
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.
5 */
8 #include <ZstdCompressionAlgorithm.h>
10 #include <errno.h>
11 #include <string.h>
13 #include <algorithm>
14 #include <new>
16 #ifdef ZSTD_ENABLED
17 #include <zstd.h>
18 #include <zstd_errors.h>
19 #endif
21 #include <DataIO.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
27 #endif
30 static const size_t kMinBufferSize = 1024;
31 static const size_t kMaxBufferSize = 1024 * 1024;
32 static const size_t kDefaultBufferSize = 4 * 1024;
35 static size_t
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(
48 int compressionLevel)
50 BCompressionParameters(),
51 fCompressionLevel(compressionLevel),
52 fBufferSize(kDefaultBufferSize)
57 BZstdCompressionParameters::~BZstdCompressionParameters()
62 int32
63 BZstdCompressionParameters::CompressionLevel() const
65 return fCompressionLevel;
69 void
70 BZstdCompressionParameters::SetCompressionLevel(int32 level)
72 fCompressionLevel = level;
76 size_t
77 BZstdCompressionParameters::BufferSize() const
79 return fBufferSize;
83 void
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()
106 size_t
107 BZstdDecompressionParameters::BufferSize() const
109 return fBufferSize;
113 void
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)
151 if (flush)
152 return ZSTD_flushStream(stream, output);
153 else
154 return ZSTD_compressStream(stream, output, input);
159 #endif // B_ZSTD_COMPRESSION_SUPPORT
162 // #pragma mark - DecompressionStrategy
165 #ifdef ZSTD_ENABLED
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 {
199 Stream(BDataIO* io)
201 BaseClass(io),
202 fStreamInitialized(false)
206 ~Stream()
208 if (fStreamInitialized) {
209 if (Strategy::kNeedsFinalFlush)
210 this->Flush();
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);
219 if (error != B_OK)
220 return error;
222 size_t zstdError = Strategy::Init(&fStream, parameters);
223 if (ZSTD_getErrorCode(zstdError) != ZSTD_error_no_error)
224 return _TranslateZstdError(zstdError);
226 fStreamInitialized = true;
227 return B_OK;
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,
248 BDataIO*& _stream)
250 const typename Strategy::Parameters* parameters
251 #ifdef _BOOT_MODE
252 = static_cast<const typename Strategy::Parameters*>(_parameters);
253 #else
254 = dynamic_cast<const typename Strategy::Parameters*>(_parameters);
255 #endif
256 Stream* stream = new(std::nothrow) Stream(io);
257 if (stream == NULL)
258 return B_NO_MEMORY;
260 status_t error = stream->Init(parameters);
261 if (error != B_OK) {
262 delete stream;
263 return error;
266 _stream = stream;
267 return B_OK;
270 private:
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;
276 inBuffer.pos = 0;
277 inBuffer.size = inputSize;
278 outBuffer.dst = output;
279 outBuffer.pos = 0;
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;
288 return B_OK;
291 private:
292 bool fStreamInitialized;
293 StreamType *fStream;
294 ZSTD_inBuffer inBuffer;
295 ZSTD_outBuffer outBuffer;
299 #endif // ZSTD_ENABLED
302 // #pragma mark - BZstdCompressionAlgorithm
305 BZstdCompressionAlgorithm::BZstdCompressionAlgorithm()
307 BCompressionAlgorithm()
312 BZstdCompressionAlgorithm::~BZstdCompressionAlgorithm()
317 status_t
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);
324 #else
325 return B_NOT_SUPPORTED;
326 #endif
330 status_t
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);
337 #else
338 return B_NOT_SUPPORTED;
339 #endif
343 status_t
344 BZstdCompressionAlgorithm::CreateDecompressingInputStream(BDataIO* input,
345 const BDecompressionParameters* parameters, BDataIO*& _stream)
347 #ifdef ZSTD_ENABLED
348 return Stream<BAbstractInputStream, DecompressionStrategy, ZSTD_DStream>::Create(
349 input, parameters, _stream);
350 #else
351 return B_NOT_SUPPORTED;
352 #endif
356 status_t
357 BZstdCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
358 const BDecompressionParameters* parameters, BDataIO*& _stream)
360 #ifdef ZSTD_ENABLED
361 return Stream<BAbstractOutputStream, DecompressionStrategy, ZSTD_DStream>::Create(
362 output, parameters, _stream);
363 #else
364 return B_NOT_SUPPORTED;
365 #endif
369 status_t
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;
387 return B_OK;
388 #else
389 return B_NOT_SUPPORTED;
390 #endif
394 status_t
395 BZstdCompressionAlgorithm::DecompressBuffer(const void* input,
396 size_t inputSize, void* output, size_t outputSize,
397 size_t& _uncompressedSize, const BDecompressionParameters* parameters)
399 #ifdef ZSTD_ENABLED
400 size_t zstdError = ZSTD_decompress(output, outputSize, input,
401 inputSize);
402 if (ZSTD_isError(zstdError))
403 return _TranslateZstdError(zstdError);
405 _uncompressedSize = zstdError;
406 return B_OK;
407 #else
408 return B_NOT_SUPPORTED;
409 #endif
413 /*static*/ status_t
414 BZstdCompressionAlgorithm::_TranslateZstdError(size_t error)
416 #ifdef ZSTD_ENABLED
417 switch (ZSTD_getErrorCode(error)) {
418 case ZSTD_error_no_error:
419 return B_OK;
420 case ZSTD_error_seekableIO:
421 return B_BAD_VALUE;
422 case ZSTD_error_corruption_detected:
423 case ZSTD_error_checksum_wrong:
424 return B_BAD_DATA;
425 case ZSTD_error_version_unsupported:
426 return B_BAD_VALUE;
427 default:
428 return B_ERROR;
430 #else
431 return B_NOT_SUPPORTED;
432 #endif