| //======================================================================== |
| // |
| // FlateEncoder.cc |
| // |
| // Copyright (C) 2016, William Bader <williambader@hotmail.com> |
| // Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com> |
| // |
| // 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; |
| |
| zlib_stream.zalloc = Z_NULL; |
| zlib_stream.zfree = Z_NULL; |
| zlib_stream.opaque = Z_NULL; |
| |
| 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() { |
| int n; |
| 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) { |
| 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 */ |
| |
| 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 = &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; |
| } |
| |