Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-stm-f-flate.c
4 : : * Date: Tue Jul 10 23:44:00 2007
5 : : *
6 : : * GNU PDF Library - FlateDecode stream filter
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2007-2011 Free Software Foundation, Inc. */
11 : :
12 : : /* This program is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU General Public License as published by
14 : : * the Free Software Foundation, either version 3 of the License, or
15 : : * (at your option) any later version.
16 : : *
17 : : * This program is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU General Public License for more details.
21 : : *
22 : : * You should have received a copy of the GNU General Public License
23 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : : */
25 : :
26 : : #include <config.h>
27 : :
28 : : #include <stdio.h>
29 : : #include <string.h>
30 : :
31 : : #include <zlib.h>
32 : :
33 : : #include <pdf-alloc.h>
34 : : #include <pdf-hash.h>
35 : : #include <pdf-stm-f-flate.h>
36 : : #include <pdf-types.h>
37 : : #include <pdf-types-buffer.h>
38 : : #include <pdf-hash.h>
39 : :
40 : : /* Define FLATE encoder */
41 : 10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_flateenc_get,
42 : : stm_f_flateenc_init,
43 : : stm_f_flateenc_apply,
44 : : stm_f_flateenc_deinit);
45 : :
46 : : /* Define FLATE decoder */
47 : 10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_flatedec_get,
48 : : stm_f_flatedec_init,
49 : : stm_f_flatedec_apply,
50 : : stm_f_flatedec_deinit);
51 : :
52 : : #define PDF_STM_F_FLATE_CHUNK 16384
53 : :
54 : : struct pdf_stm_f_flate_s
55 : : {
56 : : z_stream stream;
57 : : int zret;
58 : : pdf_size_t incnt;
59 : : pdf_size_t outcnt;
60 : : pdf_size_t to_write;
61 : : pdf_bool_t writing;
62 : : pdf_char_t inbuf[PDF_STM_F_FLATE_CHUNK];
63 : : pdf_char_t outbuf[PDF_STM_F_FLATE_CHUNK];
64 : : };
65 : :
66 : : /* Common implementation */
67 : :
68 : : static pdf_bool_t
69 : 20 : stm_f_flate_init (void **state,
70 : : pdf_error_t **error)
71 : : {
72 : : struct pdf_stm_f_flate_s *filter_state;
73 : :
74 : : /* Allocate the internal state structure */
75 : 20 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_flate_s));
76 [ - + ]: 20 : if (!filter_state)
77 : : {
78 : 0 : pdf_set_error (error,
79 : : PDF_EDOMAIN_BASE_STM,
80 : : PDF_ENOMEM,
81 : : "cannot create FLATE encoder/decoder internal state: "
82 : : "couldn't allocate %lu bytes",
83 : : (unsigned long)sizeof (struct pdf_stm_f_flate_s));
84 : 0 : return PDF_FALSE;
85 : : }
86 : :
87 : : /* Initialize common fields */
88 : 20 : filter_state->stream.zalloc = Z_NULL;
89 : 20 : filter_state->stream.zfree = Z_NULL;
90 : 20 : filter_state->stream.opaque = Z_NULL;
91 : 20 : filter_state->stream.next_in = Z_NULL;
92 : 20 : filter_state->stream.avail_in = 0;
93 : 20 : filter_state->writing = PDF_FALSE;
94 : 20 : filter_state->to_write = 0;
95 : 20 : filter_state->incnt = 0;
96 : 20 : filter_state->outcnt = 0;
97 : 20 : filter_state->zret = Z_OK;
98 : :
99 : 20 : *state = filter_state;
100 : :
101 : 20 : return PDF_TRUE;
102 : : }
103 : :
104 : : static void
105 : : stm_f_flate_deinit (void *state)
106 : : {
107 : 20 : pdf_dealloc (state);
108 : : }
109 : :
110 : : static void
111 : : set_error_from_zlib_ret (pdf_error_t **error,
112 : : int zlib_ret)
113 : : {
114 : : const pdf_char_t *errmsg;
115 : :
116 [ # # # # : 0 : switch (zlib_ret)
# ][ # # #
# # ]
117 : : {
118 : : case Z_STREAM_ERROR:
119 : 0 : errmsg = "zlib error detected: invalid compression level";
120 : : break;
121 : : case Z_NEED_DICT:
122 : 0 : errmsg = "zlib error detected: need dictionary";
123 : : break;
124 : : case Z_DATA_ERROR:
125 : 0 : errmsg = "zlib error detected: invalid or incomplete deflate data";
126 : : break;
127 : : case Z_MEM_ERROR:
128 : 0 : errmsg = "zlib error detected: out of memory";
129 : : break;
130 : : default:
131 : 0 : errmsg = "zlib error detected";
132 : : break;
133 : : }
134 : :
135 : 0 : pdf_set_error (error,
136 : : PDF_EDOMAIN_BASE_STM,
137 : : PDF_ERROR,
138 : : errmsg);
139 : : }
140 : :
141 : : /* Encoder implementation */
142 : :
143 : : static pdf_bool_t
144 : 10 : stm_f_flateenc_init (const pdf_hash_t *params,
145 : : void **state,
146 : : pdf_error_t **error)
147 : : {
148 : : struct pdf_stm_f_flate_s *filter_state;
149 : :
150 : : /* Initialize common stuff */
151 [ - + ]: 10 : if (!stm_f_flate_init (state, error))
152 : 0 : return PDF_FALSE;
153 : :
154 : 10 : filter_state = *state;
155 [ - + ]: 10 : if (deflateInit (&(filter_state->stream),
156 : : Z_DEFAULT_COMPRESSION) != Z_OK)
157 : : {
158 : 0 : pdf_set_error (error,
159 : : PDF_EDOMAIN_BASE_STM,
160 : : PDF_ERROR,
161 : : "cannot create FLATE encoder internal state: "
162 : : "couldn't initialize deflate");
163 : : stm_f_flate_deinit (filter_state);
164 : 0 : return PDF_FALSE;
165 : : }
166 : :
167 : 10 : return PDF_TRUE;
168 : : }
169 : :
170 : : static void
171 : 10 : stm_f_flateenc_deinit (void *state)
172 : : {
173 : 10 : struct pdf_stm_f_flate_s *filter_state = state;
174 : :
175 : 10 : deflateEnd (&(filter_state->stream));
176 : : stm_f_flate_deinit (state);
177 : 10 : }
178 : :
179 : : static enum pdf_stm_filter_apply_status_e
180 : 10 : deflate_inbuf (struct pdf_stm_f_flate_s *st,
181 : : pdf_buffer_t *out,
182 : : pdf_bool_t finish,
183 : : pdf_error_t **error)
184 : : {
185 [ + - ]: 10 : if (st->writing)
186 : : {
187 : : /*
188 : : * Not nice, but keeps the writing process code clear.
189 : : * Notice that the labeled code is inside a while loop,
190 : : * so I feel that avoiding this goto won't bring us better code.
191 : : */
192 : : goto writing;
193 : : }
194 : :
195 : 10 : st->stream.avail_in = st->incnt;
196 : 10 : st->stream.next_in = (Bytef *) st->inbuf;
197 : : do {
198 : 10 : st->stream.avail_out = PDF_STM_F_FLATE_CHUNK;
199 : 10 : st->stream.next_out = (Bytef *) st->outbuf;
200 : 10 : st->outcnt = 0;
201 : :
202 [ + - ]: 10 : st->zret = deflate (&(st->stream),
203 : : (finish ? Z_FINISH : Z_NO_FLUSH));
204 [ - + ]: 10 : if (st->zret == Z_STREAM_ERROR)
205 : : {
206 : 0 : set_error_from_zlib_ret (error, st->zret);
207 : 0 : return PDF_STM_FILTER_APPLY_STATUS_ERROR;
208 : : }
209 : :
210 : 10 : st->to_write = PDF_STM_F_FLATE_CHUNK - st->stream.avail_out;
211 : :
212 : : writing:
213 : :
214 [ + + ][ + - ]: 420 : while (st->outcnt < st->to_write &&
215 : : !pdf_buffer_full_p (out))
216 : : {
217 : 410 : out->data[out->wp++] = st->outbuf[st->outcnt];
218 : 410 : st->outcnt++;
219 : : }
220 : :
221 [ - + ]: 10 : if (pdf_buffer_full_p (out))
222 : : {
223 : 0 : st->writing = PDF_TRUE;
224 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
225 : : }
226 [ - + ]: 10 : } while (st->stream.avail_out == 0);
227 : :
228 : 10 : st->writing = PDF_FALSE;
229 : :
230 [ + - ]: 10 : if (finish)
231 : : {
232 : 10 : return PDF_STM_FILTER_APPLY_STATUS_EOF;
233 : : }
234 : : else
235 : : {
236 : : /* the input CHUNK now is empty */
237 : 0 : st->incnt = 0;
238 : : /* ask for the input we couldn't read */
239 : 10 : return PDF_STM_FILTER_APPLY_STATUS_OK;
240 : : }
241 : : }
242 : :
243 : : static enum pdf_stm_filter_apply_status_e
244 : : read_and_deflate (struct pdf_stm_f_flate_s *st,
245 : : pdf_buffer_t *in,
246 : : pdf_buffer_t *out,
247 : : pdf_bool_t finish,
248 : : pdf_error_t **error)
249 : : {
250 : : /* Fill the input CHUNK */
251 [ + - ]: 30 : if (!st->writing)
252 : : {
253 [ + - ][ + + ]: 10620 : while (st->incnt < PDF_STM_F_FLATE_CHUNK &&
254 : : !pdf_buffer_eob_p (in))
255 : : {
256 : 10590 : st->inbuf[st->incnt] = in->data[in->rp];
257 : 10590 : st->incnt++;
258 : 10590 : in->rp++;
259 : : }
260 : :
261 : : /* If more data may come and the input CHUNK has space, ask for it. */
262 [ + + ][ + - ]: 30 : if (!finish &&
263 : 20 : st->incnt < PDF_STM_F_FLATE_CHUNK)
264 : : {
265 : 20 : return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
266 : : }
267 : : }
268 : :
269 : : /*
270 : : * Now we have the input CHUNK full or finish_p is set,
271 : : * we deflate and write to out.
272 : : */
273 : 10 : return deflate_inbuf (st, out, finish, error);
274 : : }
275 : :
276 : : static enum pdf_stm_filter_apply_status_e
277 : 30 : stm_f_flateenc_apply (void *state,
278 : : pdf_buffer_t *in,
279 : : pdf_buffer_t *out,
280 : : pdf_bool_t finish,
281 : : pdf_error_t **error)
282 : : {
283 : 30 : struct pdf_stm_f_flate_s *st = state;
284 : : enum pdf_stm_filter_apply_status_e ret;
285 : :
286 : : do
287 : : {
288 : 60 : ret = read_and_deflate (st, in, out, finish, error);
289 : : }
290 [ - + ]: 30 : while (ret == PDF_STM_FILTER_APPLY_STATUS_OK);
291 : :
292 : 30 : return ret;
293 : : }
294 : :
295 : : /* Decoder implementation */
296 : :
297 : : static pdf_bool_t
298 : 10 : stm_f_flatedec_init (const pdf_hash_t *params,
299 : : void **state,
300 : : pdf_error_t **error)
301 : : {
302 : : struct pdf_stm_f_flate_s *filter_state;
303 : :
304 : : /* Initialize common stuff */
305 [ - + ]: 10 : if (!stm_f_flate_init (state, error))
306 : 0 : return PDF_FALSE;
307 : :
308 : 10 : filter_state = *state;
309 : :
310 [ - + ]: 10 : if (inflateInit (&(filter_state->stream)) != Z_OK)
311 : : {
312 : 0 : pdf_set_error (error,
313 : : PDF_EDOMAIN_BASE_STM,
314 : : PDF_ERROR,
315 : : "cannot create FLATE decoder internal state: "
316 : : "couldn't initialize inflate");
317 : : stm_f_flate_deinit (filter_state);
318 : 0 : return PDF_FALSE;
319 : : }
320 : :
321 : 10 : return PDF_TRUE;
322 : : }
323 : :
324 : : static void
325 : 10 : stm_f_flatedec_deinit (void *state)
326 : : {
327 : 10 : struct pdf_stm_f_flate_s *filter_state = state;
328 : :
329 : 10 : inflateEnd (&filter_state->stream);
330 : : stm_f_flate_deinit (state);
331 : 10 : }
332 : :
333 : : static enum pdf_stm_filter_apply_status_e
334 : 20 : read_and_inflate (struct pdf_stm_f_flate_s *st,
335 : : pdf_buffer_t *in,
336 : : pdf_buffer_t *out,
337 : : pdf_error_t **error)
338 : : {
339 : : /* Fill the input CHUNK */
340 [ + - ]: 20 : if (!st->writing)
341 : : {
342 [ + - ][ + + ]: 430 : while (st->incnt < PDF_STM_F_FLATE_CHUNK &&
343 : : !pdf_buffer_eob_p (in))
344 : : {
345 : 410 : st->inbuf[st->incnt] = in->data[in->rp];
346 : 410 : st->incnt++;
347 : 410 : in->rp++;
348 : : }
349 : : }
350 : : else
351 : : {
352 : : /*
353 : : * Not nice, but keeps the writing process code clear.
354 : : * Notice that the labeled code is inside a while loop,
355 : : * so I feel that avoiding this goto won't bring us better code.
356 : : */
357 : : goto writing;
358 : : }
359 : :
360 [ + + ]: 20 : if (st->incnt == 0)
361 : 10 : return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
362 : :
363 : : /* we inflate and write to out */
364 : 10 : st->stream.avail_in = st->incnt;
365 : 10 : st->stream.next_in = (Bytef *) st->inbuf;
366 : : do {
367 : 10 : st->stream.avail_out = PDF_STM_F_FLATE_CHUNK;
368 : 10 : st->stream.next_out = (Bytef *) st->outbuf;
369 : 10 : st->outcnt = 0;
370 : :
371 : 10 : st->zret = inflate (&(st->stream),
372 : : Z_NO_FLUSH);
373 [ + - + - ]: 10 : if (st->zret == Z_STREAM_ERROR ||
[ - + ]
374 : 10 : st->zret == Z_NEED_DICT ||
375 : 10 : st->zret == Z_DATA_ERROR ||
376 : 10 : st->zret == Z_MEM_ERROR)
377 : : {
378 : 0 : set_error_from_zlib_ret (error, st->zret);
379 : 0 : return PDF_STM_FILTER_APPLY_STATUS_ERROR;
380 : : }
381 : :
382 : 10 : st->to_write = PDF_STM_F_FLATE_CHUNK - st->stream.avail_out;
383 : :
384 : : writing:
385 : :
386 [ + + ][ + - ]: 10600 : while (st->outcnt < st->to_write &&
387 : : !pdf_buffer_full_p (out))
388 : : {
389 : 10590 : out->data[out->wp] = st->outbuf[st->outcnt];
390 : 10590 : out->wp++;
391 : 10590 : st->outcnt++;
392 : : }
393 : :
394 [ - + ]: 10 : if (pdf_buffer_full_p (out))
395 : : {
396 : 0 : st->writing = PDF_TRUE;
397 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
398 : : }
399 [ - + ]: 10 : } while (st->stream.avail_out == 0);
400 : :
401 [ + - ]: 10 : if (st->zret == Z_STREAM_END)
402 : 10 : return PDF_STM_FILTER_APPLY_STATUS_EOF;
403 : :
404 : : /* the input CHUNK now is empty, if needed, ask for input */
405 : 0 : st->writing = PDF_FALSE;
406 : 0 : st->incnt = 0;
407 [ # # ]: 0 : if (pdf_buffer_eob_p (in))
408 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
409 : :
410 : : /* ask for the input we couldn't read */
411 : 20 : return PDF_STM_FILTER_APPLY_STATUS_OK;
412 : : }
413 : :
414 : : static enum pdf_stm_filter_apply_status_e
415 : 20 : stm_f_flatedec_apply (void *state,
416 : : pdf_buffer_t *in,
417 : : pdf_buffer_t *out,
418 : : pdf_bool_t finish,
419 : : pdf_error_t **error)
420 : : {
421 : 20 : struct pdf_stm_f_flate_s *st = state;
422 : : enum pdf_stm_filter_apply_status_e ret;
423 : :
424 : : do
425 : : {
426 : 20 : ret = read_and_inflate (st, in, out, error);
427 : : }
428 [ - + ]: 20 : while (ret == PDF_STM_FILTER_APPLY_STATUS_OK);
429 : :
430 : 20 : return ret;
431 : : }
432 : :
433 : : /* End of pdf_stm_f_flate.c */
|