1 #include <qpdf/Pl_Flate.hh>
2 #include <zlib.h>
3 #include <string.h>
4 #include <limits.h>
5 
6 #include <qpdf/QUtil.hh>
7 #include <qpdf/QIntC.hh>
8 
9 int Pl_Flate::compression_level = Z_DEFAULT_COMPRESSION;
10 
Members(size_t out_bufsize,action_e action)11 Pl_Flate::Members::Members(size_t out_bufsize,
12                            action_e action) :
13     out_bufsize(out_bufsize),
14     action(action),
15     initialized(false),
16     zdata(0)
17 {
18     this->outbuf = PointerHolder<unsigned char>(
19         true, new unsigned char[out_bufsize]);
20     // Indirect through zdata to reach the z_stream so we don't have
21     // to include zlib.h in Pl_Flate.hh.  This means people using
22     // shared library versions of qpdf don't have to have zlib
23     // development files available, which particularly helps in a
24     // Windows environment.
25     this->zdata = new z_stream;
26 
27     if (out_bufsize > UINT_MAX)
28     {
29         throw std::runtime_error(
30             "Pl_Flate: zlib doesn't support buffer"
31             " sizes larger than unsigned int");
32     }
33 
34     z_stream& zstream = *(static_cast<z_stream*>(this->zdata));
35     zstream.zalloc = 0;
36     zstream.zfree = 0;
37     zstream.opaque = 0;
38     zstream.next_in = 0;
39     zstream.avail_in = 0;
40     zstream.next_out = this->outbuf.getPointer();
41     zstream.avail_out = QIntC::to_uint(out_bufsize);
42 }
43 
~Members()44 Pl_Flate::Members::~Members()
45 {
46     if (this->initialized)
47     {
48         z_stream& zstream = *(static_cast<z_stream*>(this->zdata));
49         if (action == a_deflate)
50         {
51             deflateEnd(&zstream);
52         }
53         else
54         {
55             inflateEnd(&zstream);
56         }
57     }
58 
59     delete static_cast<z_stream*>(this->zdata);
60     this->zdata = 0;
61 }
62 
Pl_Flate(char const * identifier,Pipeline * next,action_e action,unsigned int out_bufsize_int)63 Pl_Flate::Pl_Flate(char const* identifier, Pipeline* next,
64 		   action_e action, unsigned int out_bufsize_int) :
65     Pipeline(identifier, next),
66     m(new Members(QIntC::to_size(out_bufsize_int), action))
67 {
68 }
69 
~Pl_Flate()70 Pl_Flate::~Pl_Flate()
71 {
72 }
73 
74 void
setWarnCallback(std::function<void (char const *,int)> callback)75 Pl_Flate::setWarnCallback(std::function<void(char const*, int)> callback)
76 {
77     this->m->callback = callback;
78 }
79 
80 void
warn(char const * msg,int code)81 Pl_Flate::warn(char const* msg, int code)
82 {
83     if (this->m->callback != nullptr)
84     {
85         this->m->callback(msg, code);
86     }
87 }
88 
89 void
write(unsigned char * data,size_t len)90 Pl_Flate::write(unsigned char* data, size_t len)
91 {
92     if (this->m->outbuf.getPointer() == 0)
93     {
94 	throw std::logic_error(
95 	    this->identifier +
96 	    ": Pl_Flate: write() called after finish() called");
97     }
98 
99     // Write in chunks in case len is too big to fit in an int.
100     // Assume int is at least 32 bits.
101     static size_t const max_bytes = 1 << 30;
102     size_t bytes_left = len;
103     unsigned char* buf = data;
104     while (bytes_left > 0)
105     {
106 	size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
107         handleData(buf, bytes,
108                    (this->m->action == a_inflate ? Z_SYNC_FLUSH : Z_NO_FLUSH));
109 	bytes_left -= bytes;
110         buf += bytes;
111     }
112 }
113 
114 void
handleData(unsigned char * data,size_t len,int flush)115 Pl_Flate::handleData(unsigned char* data, size_t len, int flush)
116 {
117     if (len > UINT_MAX)
118     {
119         throw std::runtime_error(
120             "Pl_Flate: zlib doesn't support data"
121             " blocks larger than int");
122     }
123     z_stream& zstream = *(static_cast<z_stream*>(this->m->zdata));
124     zstream.next_in = data;
125     zstream.avail_in = QIntC::to_uint(len);
126 
127     if (! this->m->initialized)
128     {
129 	int err = Z_OK;
130 
131         // deflateInit and inflateInit are macros that use old-style
132         // casts.
133 #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
134      defined(__clang__))
135 #       pragma GCC diagnostic push
136 #       pragma GCC diagnostic ignored "-Wold-style-cast"
137 #endif
138 	if (this->m->action == a_deflate)
139 	{
140 	    err = deflateInit(&zstream, compression_level);
141 	}
142 	else
143 	{
144 	    err = inflateInit(&zstream);
145 	}
146 #if ((defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) || \
147      defined(__clang__))
148 #       pragma GCC diagnostic pop
149 #endif
150 
151 	checkError("Init", err);
152 	this->m->initialized = true;
153     }
154 
155     int err = Z_OK;
156 
157     bool done = false;
158     while (! done)
159     {
160 	if (this->m->action == a_deflate)
161 	{
162 	    err = deflate(&zstream, flush);
163 	}
164 	else
165 	{
166 	    err = inflate(&zstream, flush);
167 	}
168         if ((this->m->action == a_inflate) && (err != Z_OK) && zstream.msg &&
169             (strcmp(zstream.msg, "incorrect data check") == 0))
170         {
171             // Other PDF readers ignore this specific error. Combining
172             // this with Z_SYNC_FLUSH enables qpdf to handle some
173             // broken zlib streams without losing data.
174             err = Z_STREAM_END;
175         }
176 	switch (err)
177 	{
178 	  case Z_BUF_ERROR:
179 	    // Probably shouldn't be able to happen, but possible as a
180 	    // boundary condition: if the last call to inflate exactly
181 	    // filled the output buffer, it's possible that the next
182 	    // call to inflate could have nothing to do. There are PDF
183 	    // files in the wild that have this error (including at
184 	    // least one in qpdf's test suite). In some cases, we want
185 	    // to know about this, because it indicates incorrect
186 	    // compression, so call a callback if provided.
187             this->warn(
188                 "input stream is complete but output may still be valid",
189                 err);
190 	    done = true;
191 	    break;
192 
193 	  case Z_STREAM_END:
194 	    done = true;
195 	    // fall through
196 
197 	  case Z_OK:
198 	    {
199 		if ((zstream.avail_in == 0) &&
200 		    (zstream.avail_out > 0))
201 		{
202 		    // There is nothing left to read, and there was
203 		    // sufficient buffer space to write everything we
204 		    // needed, so we're done for now.
205 		    done = true;
206 		}
207 		uLong ready =
208                     QIntC::to_ulong(this->m->out_bufsize - zstream.avail_out);
209 		if (ready > 0)
210 		{
211 		    this->getNext()->write(this->m->outbuf.getPointer(), ready);
212 		    zstream.next_out = this->m->outbuf.getPointer();
213 		    zstream.avail_out = QIntC::to_uint(this->m->out_bufsize);
214 		}
215 	    }
216 	    break;
217 
218 	  default:
219 	    this->checkError("data", err);
220 	    break;
221 	}
222     }
223 }
224 
225 void
finish()226 Pl_Flate::finish()
227 {
228     try
229     {
230         if (this->m->outbuf.getPointer())
231         {
232             if (this->m->initialized)
233             {
234                 z_stream& zstream = *(static_cast<z_stream*>(this->m->zdata));
235                 unsigned char buf[1];
236                 buf[0] = '\0';
237                 handleData(buf, 0, Z_FINISH);
238                 int err = Z_OK;
239                 if (this->m->action == a_deflate)
240                 {
241                     err = deflateEnd(&zstream);
242                 }
243                 else
244                 {
245                     err = inflateEnd(&zstream);
246                 }
247                 this->m->initialized = false;
248                 checkError("End", err);
249             }
250 
251             this->m->outbuf = 0;
252         }
253     }
254     catch (std::exception& e)
255     {
256         try
257         {
258             this->getNext()->finish();
259         }
260         catch (...)
261         {
262             // ignore secondary exception
263         }
264         throw std::runtime_error(e.what());
265     }
266     this->getNext()->finish();
267 }
268 
269 void
setCompressionLevel(int level)270 Pl_Flate::setCompressionLevel(int level)
271 {
272     compression_level = level;
273 }
274 
275 void
checkError(char const * prefix,int error_code)276 Pl_Flate::checkError(char const* prefix, int error_code)
277 {
278     z_stream& zstream = *(static_cast<z_stream*>(this->m->zdata));
279     if (error_code != Z_OK)
280     {
281 	char const* action_str =
282             (this->m->action == a_deflate ? "deflate" : "inflate");
283 	std::string msg =
284 	    this->identifier + ": " + action_str + ": " + prefix + ": ";
285 
286 	if (zstream.msg)
287 	{
288 	    msg += zstream.msg;
289 	}
290 	else
291 	{
292 	    switch (error_code)
293 	    {
294 	      case Z_ERRNO:
295 		msg += "zlib system error";
296 		break;
297 
298 	      case Z_STREAM_ERROR:
299 		msg += "zlib stream error";
300 		break;
301 
302 	      case Z_DATA_ERROR:
303 		msg += "zlib data error";
304 		break;
305 
306 	      case Z_MEM_ERROR:
307 		msg += "zlib memory error";
308 		break;
309 
310 	      case Z_BUF_ERROR:
311 		msg += "zlib buffer error";
312 		break;
313 
314 	      case Z_VERSION_ERROR:
315 		msg += "zlib version error";
316 		break;
317 
318 	      default:
319 		msg += std::string("zlib unknown error (") +
320 		    QUtil::int_to_string(error_code) + ")";
321 		break;
322 	    }
323 	}
324 
325 	throw std::runtime_error(msg);
326     }
327 }
328