| //======================================================================== |
| // |
| // FlateEncoder.cc |
| // |
| // Copyright (C) 2016, William Bader <williambader@hotmail.com> |
| // Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com> |
| // Copyright (C) 2021 Even Rouault <even.rouault@spatialys.com> |
| // Copyright (C) 2022 Albert Astals Cid <aacid@kde.org> |
| // |
| // This file is under the GPLv2 or later license |
| // |
| //======================================================================== |
| |
| #include <config.h> |
| |
| #include "FlateEncoder.h" |
| |
| //------------------------------------------------------------------------ |
| // FlateEncoder |
| //------------------------------------------------------------------------ |
| |
| FlateEncoder::FlateEncoder(Stream *strA) : FilterStream(strA) |
| { |
| int zlib_status; |
| |
| outBufPtr = outBufEnd = outBuf; |
| inBufEof = outBufEof = false; |
| |
| // We used to assign Z_NULL to the 3 following members of zlib_stream, |
| // but as Z_NULL is a #define to 0, using it triggers the |
| // -Wzero-as-null-pointer-constant warning. |
| // For safety, check that the Z_NULL definition is equivalent to |
| // 0 / null pointer. |
| static_assert(static_cast<int>(Z_NULL) == 0); |
| zlib_stream.zalloc = nullptr; |
| zlib_stream.zfree = nullptr; |
| zlib_stream.opaque = nullptr; |
| |
| zlib_status = deflateInit(&zlib_stream, Z_DEFAULT_COMPRESSION); |
| |
| if (zlib_status != Z_OK) { |
| inBufEof = outBufEof = true; |
| error(errInternal, -1, "Internal: deflateInit() failed in FlateEncoder::FlateEncoder()"); |
| } |
| |
| zlib_stream.next_out = outBufEnd; |
| zlib_stream.avail_out = 1; /* anything but 0 to trigger a read */ |
| } |
| |
| FlateEncoder::~FlateEncoder() |
| { |
| deflateEnd(&zlib_stream); |
| if (str->isEncoder()) { |
| delete str; |
| } |
| } |
| |
| void FlateEncoder::reset() |
| { |
| int zlib_status; |
| |
| str->reset(); |
| |
| outBufPtr = outBufEnd = outBuf; |
| inBufEof = outBufEof = false; |
| |
| deflateEnd(&zlib_stream); |
| |
| zlib_status = deflateInit(&zlib_stream, Z_DEFAULT_COMPRESSION); |
| |
| if (zlib_status != Z_OK) { |
| inBufEof = outBufEof = true; |
| error(errInternal, -1, "Internal: deflateInit() failed in FlateEncoder::reset()"); |
| } |
| |
| zlib_stream.next_out = outBufEnd; |
| zlib_stream.avail_out = 1; /* anything but 0 to trigger a read */ |
| } |
| |
| bool FlateEncoder::fillBuf() |
| { |
| unsigned int starting_avail_out; |
| int zlib_status; |
| |
| /* If the output is done, don't try to read more. */ |
| |
| if (outBufEof) { |
| return false; |
| } |
| |
| /* The output buffer should be empty. */ |
| /* If it is not empty, push any processed data to the start. */ |
| |
| if (outBufPtr > outBuf && outBufPtr < outBufEnd) { |
| const ptrdiff_t n = outBufEnd - outBufPtr; |
| memmove(outBuf, outBufPtr, n); |
| outBufEnd = &outBuf[n]; |
| } else { |
| outBufEnd = outBuf; |
| } |
| outBufPtr = outBuf; |
| |
| /* Keep feeding zlib until we get output. */ |
| /* zlib might consume a few input buffers */ |
| /* before it starts producing output. */ |
| |
| do { |
| |
| /* avail_out > 0 means that zlib has depleted its input */ |
| /* and needs a new chunk of input in order to generate */ |
| /* more output. */ |
| |
| if (zlib_stream.avail_out != 0) { |
| |
| /* Fill the input buffer */ |
| |
| const int n = (inBufEof ? 0 : str->doGetChars(inBufSize, inBuf)); |
| |
| if (n == 0) { |
| inBufEof = true; |
| } |
| |
| zlib_stream.next_in = inBuf; |
| zlib_stream.avail_in = n; |
| } |
| |
| /* Ask zlib for output. */ |
| |
| zlib_stream.next_out = outBufEnd; |
| starting_avail_out = static_cast<unsigned int>(&outBuf[outBufSize] - outBufEnd); |
| zlib_stream.avail_out = starting_avail_out; |
| |
| zlib_status = deflate(&zlib_stream, (inBufEof ? Z_FINISH : Z_NO_FLUSH)); |
| |
| if (zlib_status == Z_STREAM_ERROR || zlib_stream.avail_out > starting_avail_out) { |
| /* Unrecoverable error */ |
| inBufEof = outBufEof = true; |
| error(errInternal, -1, "Internal: deflate() failed in FlateEncoder::fillBuf()"); |
| return false; |
| } |
| |
| } while (zlib_stream.avail_out == outBufSize && !inBufEof); |
| |
| outBufEnd = &outBuf[outBufSize] - zlib_stream.avail_out; |
| |
| if (inBufEof && zlib_stream.avail_out != 0) { |
| outBufEof = true; |
| } |
| |
| return outBufPtr < outBufEnd; |
| } |