1 | //======================================================================== |
2 | // |
3 | // FlateEncoder.cc |
4 | // |
5 | // Copyright (C) 2016, William Bader <williambader@hotmail.com> |
6 | // Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com> |
7 | // Copyright (C) 2021 Even Rouault <even.rouault@spatialys.com> |
8 | // Copyright (C) 2022 Albert Astals Cid <aacid@kde.org> |
9 | // |
10 | // This file is under the GPLv2 or later license |
11 | // |
12 | //======================================================================== |
13 | |
14 | #include <config.h> |
15 | |
16 | #include "FlateEncoder.h" |
17 | |
18 | //------------------------------------------------------------------------ |
19 | // FlateEncoder |
20 | //------------------------------------------------------------------------ |
21 | |
22 | FlateEncoder::FlateEncoder(Stream *strA) : FilterStream(strA) |
23 | { |
24 | int zlib_status; |
25 | |
26 | outBufPtr = outBufEnd = outBuf; |
27 | inBufEof = outBufEof = false; |
28 | |
29 | // We used to assign Z_NULL to the 3 following members of zlib_stream, |
30 | // but as Z_NULL is a #define to 0, using it triggers the |
31 | // -Wzero-as-null-pointer-constant warning. |
32 | // For safety, check that the Z_NULL definition is equivalent to |
33 | // 0 / null pointer. |
34 | static_assert(static_cast<int>(Z_NULL) == 0); |
35 | zlib_stream.zalloc = nullptr; |
36 | zlib_stream.zfree = nullptr; |
37 | zlib_stream.opaque = nullptr; |
38 | |
39 | zlib_status = deflateInit(&zlib_stream, Z_DEFAULT_COMPRESSION); |
40 | |
41 | if (zlib_status != Z_OK) { |
42 | inBufEof = outBufEof = true; |
43 | error(category: errInternal, pos: -1, msg: "Internal: deflateInit() failed in FlateEncoder::FlateEncoder()" ); |
44 | } |
45 | |
46 | zlib_stream.next_out = outBufEnd; |
47 | zlib_stream.avail_out = 1; /* anything but 0 to trigger a read */ |
48 | } |
49 | |
50 | FlateEncoder::~FlateEncoder() |
51 | { |
52 | deflateEnd(strm: &zlib_stream); |
53 | if (str->isEncoder()) { |
54 | delete str; |
55 | } |
56 | } |
57 | |
58 | void FlateEncoder::reset() |
59 | { |
60 | int zlib_status; |
61 | |
62 | str->reset(); |
63 | |
64 | outBufPtr = outBufEnd = outBuf; |
65 | inBufEof = outBufEof = false; |
66 | |
67 | deflateEnd(strm: &zlib_stream); |
68 | |
69 | zlib_status = deflateInit(&zlib_stream, Z_DEFAULT_COMPRESSION); |
70 | |
71 | if (zlib_status != Z_OK) { |
72 | inBufEof = outBufEof = true; |
73 | error(category: errInternal, pos: -1, msg: "Internal: deflateInit() failed in FlateEncoder::reset()" ); |
74 | } |
75 | |
76 | zlib_stream.next_out = outBufEnd; |
77 | zlib_stream.avail_out = 1; /* anything but 0 to trigger a read */ |
78 | } |
79 | |
80 | bool FlateEncoder::fillBuf() |
81 | { |
82 | unsigned int starting_avail_out; |
83 | int zlib_status; |
84 | |
85 | /* If the output is done, don't try to read more. */ |
86 | |
87 | if (outBufEof) { |
88 | return false; |
89 | } |
90 | |
91 | /* The output buffer should be empty. */ |
92 | /* If it is not empty, push any processed data to the start. */ |
93 | |
94 | if (outBufPtr > outBuf && outBufPtr < outBufEnd) { |
95 | const ptrdiff_t n = outBufEnd - outBufPtr; |
96 | memmove(dest: outBuf, src: outBufPtr, n: n); |
97 | outBufEnd = &outBuf[n]; |
98 | } else { |
99 | outBufEnd = outBuf; |
100 | } |
101 | outBufPtr = outBuf; |
102 | |
103 | /* Keep feeding zlib until we get output. */ |
104 | /* zlib might consume a few input buffers */ |
105 | /* before it starts producing output. */ |
106 | |
107 | do { |
108 | |
109 | /* avail_out > 0 means that zlib has depleted its input */ |
110 | /* and needs a new chunk of input in order to generate */ |
111 | /* more output. */ |
112 | |
113 | if (zlib_stream.avail_out != 0) { |
114 | |
115 | /* Fill the input buffer */ |
116 | |
117 | const int n = (inBufEof ? 0 : str->doGetChars(nChars: inBufSize, buffer: inBuf)); |
118 | |
119 | if (n == 0) { |
120 | inBufEof = true; |
121 | } |
122 | |
123 | zlib_stream.next_in = inBuf; |
124 | zlib_stream.avail_in = n; |
125 | } |
126 | |
127 | /* Ask zlib for output. */ |
128 | |
129 | zlib_stream.next_out = outBufEnd; |
130 | starting_avail_out = static_cast<unsigned int>(&outBuf[outBufSize] - outBufEnd); |
131 | zlib_stream.avail_out = starting_avail_out; |
132 | |
133 | zlib_status = deflate(strm: &zlib_stream, flush: (inBufEof ? Z_FINISH : Z_NO_FLUSH)); |
134 | |
135 | if (zlib_status == Z_STREAM_ERROR || zlib_stream.avail_out > starting_avail_out) { |
136 | /* Unrecoverable error */ |
137 | inBufEof = outBufEof = true; |
138 | error(category: errInternal, pos: -1, msg: "Internal: deflate() failed in FlateEncoder::fillBuf()" ); |
139 | return false; |
140 | } |
141 | |
142 | } while (zlib_stream.avail_out == outBufSize && !inBufEof); |
143 | |
144 | outBufEnd = &outBuf[outBufSize] - zlib_stream.avail_out; |
145 | |
146 | if (inBufEof && zlib_stream.avail_out != 0) { |
147 | outBufEof = true; |
148 | } |
149 | |
150 | return outBufPtr < outBufEnd; |
151 | } |
152 | |