HaikuDepot: notify work status from main window
[haiku.git] / src / kits / support / ZlibCompressionAlgorithm.cpp
blobf49a781a25bcba8fae939bf68845d015581516b3
1 /*
2 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <ZlibCompressionAlgorithm.h>
9 #include <errno.h>
10 #include <string.h>
12 #include <algorithm>
13 #include <new>
15 #include <zlib.h>
17 #include <DataIO.h>
20 // build compression support only for userland
21 #if !defined(_KERNEL_MODE) && !defined(_BOOT_MODE)
22 # define B_ZLIB_COMPRESSION_SUPPORT 1
23 #endif
26 static const size_t kMinBufferSize = 1024;
27 static const size_t kMaxBufferSize = 1024 * 1024;
28 static const size_t kDefaultBufferSize = 4 * 1024;
31 static size_t
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(
44 int compressionLevel)
46 BCompressionParameters(),
47 fCompressionLevel(compressionLevel),
48 fBufferSize(kDefaultBufferSize),
49 fGzipFormat(false)
54 BZlibCompressionParameters::~BZlibCompressionParameters()
59 int32
60 BZlibCompressionParameters::CompressionLevel() const
62 return fCompressionLevel;
66 void
67 BZlibCompressionParameters::SetCompressionLevel(int32 level)
69 fCompressionLevel = level;
73 size_t
74 BZlibCompressionParameters::BufferSize() const
76 return fBufferSize;
80 void
81 BZlibCompressionParameters::SetBufferSize(size_t size)
83 fBufferSize = sanitize_buffer_size(size);
87 bool
88 BZlibCompressionParameters::IsGzipFormat() const
90 return fGzipFormat;
94 void
95 BZlibCompressionParameters::SetGzipFormat(bool gzipFormat)
97 fGzipFormat = gzipFormat;
101 // #pragma mark - BZlibDecompressionParameters
104 BZlibDecompressionParameters::BZlibDecompressionParameters()
106 BDecompressionParameters(),
107 fBufferSize(kDefaultBufferSize)
112 BZlibDecompressionParameters::~BZlibDecompressionParameters()
117 size_t
118 BZlibDecompressionParameters::BufferSize() const
120 return fBufferSize;
124 void
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,
153 Z_DEFLATED,
154 MAX_WBITS + (gzipFormat ? 16 : 0),
155 MAX_MEM_LEVEL,
156 Z_DEFAULT_STRATEGY);
159 static void Uninit(z_stream& stream)
161 deflateEnd(&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)
191 inflateEnd(&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 {
206 Stream(BDataIO* io)
208 BaseClass(io),
209 fStreamInitialized(false)
213 ~Stream()
215 if (fStreamInitialized) {
216 if (Strategy::kNeedsFinalFlush)
217 this->Flush();
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);
226 if (error != B_OK)
227 return error;
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;
236 return B_OK;
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,
257 BDataIO*& _stream)
259 const typename Strategy::Parameters* parameters
260 #ifdef _BOOT_MODE
261 = static_cast<const typename Strategy::Parameters*>(_parameters);
262 #else
263 = dynamic_cast<const typename Strategy::Parameters*>(_parameters);
264 #endif
265 Stream* stream = new(std::nothrow) Stream(io);
266 if (stream == NULL)
267 return B_NO_MEMORY;
269 status_t error = stream->Init(parameters);
270 if (error != B_OK) {
271 delete stream;
272 return error;
275 _stream = stream;
276 return B_OK;
279 private:
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)
293 return B_BAD_DATA;
294 } else
295 return _TranslateZlibError(zlibError);
298 bytesConsumed = inputSize - (size_t)fStream.avail_in;
299 bytesProduced = outputSize - (size_t)fStream.avail_out;
300 return B_OK;
303 private:
304 z_stream fStream;
305 bool fStreamInitialized;
309 // #pragma mark - BZlibCompressionAlgorithm
312 BZlibCompressionAlgorithm::BZlibCompressionAlgorithm()
314 BCompressionAlgorithm()
319 BZlibCompressionAlgorithm::~BZlibCompressionAlgorithm()
324 status_t
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);
331 #else
332 return B_NOT_SUPPORTED;
333 #endif
337 status_t
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);
344 #else
345 return B_NOT_SUPPORTED;
346 #endif
350 status_t
351 BZlibCompressionAlgorithm::CreateDecompressingInputStream(BDataIO* input,
352 const BDecompressionParameters* parameters, BDataIO*& _stream)
354 return Stream<BAbstractInputStream, DecompressionStrategy>::Create(
355 input, parameters, _stream);
359 status_t
360 BZlibCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
361 const BDecompressionParameters* parameters, BDataIO*& _stream)
363 return Stream<BAbstractOutputStream, DecompressionStrategy>::Create(
364 output, parameters, _stream);
368 status_t
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;
387 return B_OK;
388 #else
389 return B_NOT_SUPPORTED;
390 #endif
394 status_t
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,
401 (uLong)inputSize);
402 if (zlibError != Z_OK)
403 return _TranslateZlibError(zlibError);
405 _uncompressedSize = (size_t)bytesUsed;
406 return B_OK;
410 /*static*/ status_t
411 BZlibCompressionAlgorithm::_TranslateZlibError(int error)
413 switch (error) {
414 case Z_OK:
415 return B_OK;
416 case Z_STREAM_END:
417 case Z_NEED_DICT:
418 // a special event (no error), but the caller doesn't seem to handle
419 // it
420 return B_ERROR;
421 case Z_ERRNO:
422 return errno;
423 case Z_STREAM_ERROR:
424 return B_BAD_VALUE;
425 case Z_DATA_ERROR:
426 return B_BAD_DATA;
427 case Z_MEM_ERROR:
428 return B_NO_MEMORY;
429 case Z_BUF_ERROR:
430 return B_BUFFER_OVERFLOW;
431 case Z_VERSION_ERROR:
432 return B_BAD_VALUE;
433 default:
434 return B_ERROR;