//======================================================================== // // FlateEncoder.cc // // Copyright (C) 2016, William Bader // Copyright (C) 2017 Adrian Johnson // Copyright (C) 2021 Even Rouault // Copyright (C) 2022 Albert Astals Cid // // This file is under the GPLv2 or later license // //======================================================================== #include #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(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(&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; }