Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-stm-filter.c
4 : : * Date: Thu Jun 12 22:13:31 2008
5 : : *
6 : : * GNU PDF Library - Stream Filter
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2008-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 <pdf-stm-filter.h>
29 : : #include <pdf-stm-f-null.h>
30 : : #include <pdf-stm-f-ahex.h>
31 : : #include <pdf-stm-f-rl.h>
32 : : #include <pdf-stm-f-v2.h>
33 : : #include <pdf-stm-f-aesv2.h>
34 : : #include <pdf-stm-f-md5.h>
35 : : #include <pdf-stm-f-lzw.h>
36 : : #include <pdf-stm-f-a85.h>
37 : : #include <pdf-stm-f-pred.h>
38 : :
39 : : /* Build-dependent filters */
40 : :
41 : : #if defined PDF_HAVE_LIBZ
42 : : # include <pdf-stm-f-flate.h>
43 : : #else
44 : : # define pdf_stm_f_flateenc_get NULL
45 : : # define pdf_stm_f_flatedec_get NULL
46 : : #endif /* PDF_HAVE_LIBZ */
47 : :
48 : : #if defined PDF_HAVE_LIBJBIG2DEC
49 : : # include <pdf-stm-f-jbig2.h>
50 : : #else
51 : : # define pdf_stm_f_jbig2dec_get NULL
52 : : #endif /* PDF_HAVE_LIBJBIG2DEC */
53 : :
54 : : #if defined PDF_HAVE_LIBJPEG
55 : : # include <pdf-stm-f-dct.h>
56 : : #else
57 : : # define pdf_stm_f_dctdec_get NULL
58 : : #endif /* PDF_HAVE_LIBJPEG */
59 : :
60 : : static pdf_bool_t pdf_stm_filter_get_input (pdf_stm_filter_t *filter,
61 : : pdf_bool_t finish,
62 : : pdf_bool_t *eof,
63 : : pdf_error_t **error);
64 : :
65 : : /* Filter definition */
66 : : struct stm_filter_s {
67 : : /* Filter name */
68 : : const pdf_char_t *name;
69 : : /* Filter implementation getter */
70 : : const pdf_stm_filter_impl_t *(* get_impl) (void);
71 : : };
72 : :
73 : : /* Same order as pdf_stm_filter_type_e */
74 : : static const struct stm_filter_s filters[PDF_STM_FILTER_LAST] = {
75 : : { "NULL", pdf_stm_f_null_get },
76 : : /* Standard filters */
77 : : { "ASCII-HEX encoder", pdf_stm_f_ahexenc_get },
78 : : { "ASCII-HEX decoder", pdf_stm_f_ahexdec_get },
79 : : { "ASCII-85 encoder", pdf_stm_f_a85enc_get },
80 : : { "ASCII-85 decoder", pdf_stm_f_a85dec_get },
81 : : { "LZW encoder", pdf_stm_f_lzwenc_get },
82 : : { "LZW decoder", pdf_stm_f_lzwdec_get },
83 : : { "FLATE encoder", pdf_stm_f_flateenc_get },
84 : : { "FLATE decoder", pdf_stm_f_flatedec_get },
85 : : { "RunLength encoder", pdf_stm_f_rlenc_get },
86 : : { "RunLength decoder", pdf_stm_f_rldec_get },
87 : : { "CCITT Fax encoder", NULL },
88 : : { "CCITT Fax decoder", NULL },
89 : : { "JBIG2 encoder", NULL },
90 : : { "JBIG2 decoder", pdf_stm_f_jbig2dec_get },
91 : : { "DCT encoder", NULL },
92 : : { "DCT decoder", pdf_stm_f_dctdec_get },
93 : : { "JPX encoder", NULL },
94 : : { "JPX decoder", NULL },
95 : : /* Predictors */
96 : : { "Predictor encoder", pdf_stm_f_predenc_get },
97 : : { "Predictor decoder", pdf_stm_f_preddec_get },
98 : : /* Crypt filters */
99 : : { "AESv2 encoder", pdf_stm_f_aesv2enc_get },
100 : : { "AESv2 decoder", pdf_stm_f_aesv2dec_get },
101 : : { "V2 encoder", pdf_stm_f_v2enc_get },
102 : : { "V2 decoder", pdf_stm_f_v2enc_get },
103 : : /* Hash filters */
104 : : { "MD5 encoder", pdf_stm_f_md5enc_get },
105 : : };
106 : :
107 : : /* Filter data type */
108 : : struct pdf_stm_filter_s
109 : : {
110 : : /* Filter implementation */
111 : : enum pdf_stm_filter_type_e type;
112 : : const pdf_stm_filter_impl_t *impl;
113 : :
114 : : pdf_stm_filter_t *next; /* Next filter in the chain, or NULL */
115 : : pdf_stm_be_t *backend; /* Backend, or NULL */
116 : :
117 : : /* Input and output buffers */
118 : : pdf_buffer_t *in;
119 : : pdf_buffer_t *out;
120 : :
121 : : /* Filter-specific information */
122 : : void *state;
123 : :
124 : : /* Filter status */
125 : : pdf_error_t *error;
126 : : pdf_bool_t really_finish;
127 : : pdf_bool_t eof;
128 : :
129 : : /* Operation mode */
130 : : enum pdf_stm_filter_mode_e mode;
131 : : };
132 : :
133 : : /*
134 : : * Public functions
135 : : */
136 : :
137 : : pdf_bool_t
138 : 0 : pdf_stm_filter_p (enum pdf_stm_filter_type_e type)
139 : : {
140 : 0 : return (filters[type].get_impl != NULL ? PDF_TRUE : PDF_FALSE);
141 : : }
142 : :
143 : : pdf_stm_filter_t *
144 : 1781 : pdf_stm_filter_new (enum pdf_stm_filter_type_e type,
145 : : const pdf_hash_t *params,
146 : : pdf_size_t buffer_size,
147 : : enum pdf_stm_filter_mode_e mode,
148 : : pdf_error_t **error)
149 : : {
150 : : pdf_stm_filter_t *filter;
151 : :
152 : : /* Allocate the filter structure */
153 : 1781 : filter = pdf_alloc (sizeof (struct pdf_stm_filter_s));
154 [ - + ]: 1781 : if (!filter)
155 : : {
156 : 0 : pdf_set_error (error,
157 : : PDF_EDOMAIN_BASE_STM,
158 : : PDF_ENOMEM,
159 : : "not enough memory to create a filter: "
160 : : "couldn't allocate %lu bytes",
161 : : (unsigned long) sizeof (struct pdf_stm_filter_s));
162 : 0 : return NULL;
163 : : }
164 : :
165 : : /* Initialisation */
166 [ - + ]: 1781 : PDF_ASSERT (type >= PDF_STM_FILTER_NULL);
167 [ - + ]: 1781 : PDF_ASSERT (type < PDF_STM_FILTER_LAST);
168 : 1781 : filter->type = type;
169 : :
170 : : /* Ensure filter is supported in current build */
171 [ + - ]: 3562 : filter->impl = (filters[filter->type].get_impl != NULL ?
172 : 1781 : filters[filter->type].get_impl () :
173 : : NULL);
174 [ - + ]: 1781 : if (!filter->impl)
175 : : {
176 : 0 : pdf_set_error (error,
177 : : PDF_EDOMAIN_BASE_STM,
178 : : PDF_EBADDATA,
179 : : "filter type `%s' not supported",
180 : 0 : filters[filter->type].name);
181 : 0 : pdf_stm_filter_destroy (filter);
182 : 0 : return NULL;
183 : : }
184 : :
185 : : /* Data sources */
186 : 1781 : filter->next = NULL;
187 : 1781 : filter->backend = NULL;
188 : :
189 : : /* Operation mode */
190 : 1781 : filter->mode = mode;
191 : :
192 : : /* Input buffer */
193 : 1781 : filter->in = pdf_buffer_new (buffer_size, error);
194 [ - + ]: 1781 : if (!filter->in)
195 : : {
196 : : /* Not enough memory. Retreat. */
197 : 0 : pdf_stm_filter_destroy (filter);
198 : 0 : return NULL;
199 : : }
200 : :
201 : : /* Output buffer */
202 : 1781 : filter->out = NULL;
203 : :
204 : : /* Initialization of the implementation */
205 : 1781 : filter->state = NULL;
206 : 1781 : filter->error = NULL;
207 : 1781 : filter->eof = PDF_FALSE;
208 : 1781 : filter->really_finish = PDF_FALSE;
209 : :
210 : : /* Error initializing the filter implementation? */
211 [ + + ][ - + ]: 1781 : if (filter->impl->init_fn &&
212 : 438 : !filter->impl->init_fn (params,
213 : : &(filter->state),
214 : : error))
215 : : {
216 : : /* Reset implementation before destroying, so that deinit() is not
217 : : * called */
218 : 0 : filter->impl = NULL;
219 : 0 : pdf_stm_filter_destroy (filter);
220 : 0 : return NULL;
221 : : }
222 : :
223 : 1781 : return filter;
224 : : }
225 : :
226 : : void
227 : 1600 : pdf_stm_filter_destroy (pdf_stm_filter_t *filter)
228 : : {
229 [ + - ]: 1600 : if (!filter)
230 : : return;
231 : :
232 [ + - ]: 1600 : if (filter->in)
233 : 1600 : pdf_buffer_destroy (filter->in);
234 : :
235 [ + - ][ + + ]: 1600 : if (filter->impl && filter->impl->deinit_fn)
236 : 438 : filter->impl->deinit_fn (filter->state);
237 : :
238 [ + + ]: 1600 : if (filter->error)
239 : 140 : pdf_error_destroy (filter->error);
240 : :
241 : 1600 : pdf_dealloc (filter);
242 : : }
243 : :
244 : : void
245 : 486 : pdf_stm_filter_set_next (pdf_stm_filter_t *filter,
246 : : pdf_stm_filter_t *next_filter)
247 : : {
248 : 486 : filter->next = next_filter;
249 : 486 : }
250 : :
251 : : void
252 : 989 : pdf_stm_filter_set_be (pdf_stm_filter_t *filter,
253 : : pdf_stm_be_t *be)
254 : : {
255 : 989 : filter->backend = be;
256 : 989 : }
257 : :
258 : : void
259 : 2267 : pdf_stm_filter_set_out (pdf_stm_filter_t *filter,
260 : : pdf_buffer_t *buffer)
261 : : {
262 : 2267 : filter->out = buffer;
263 : 2267 : }
264 : :
265 : : pdf_buffer_t *
266 : 4101 : pdf_stm_filter_get_in (pdf_stm_filter_t *filter)
267 : : {
268 : 4101 : return filter->in;
269 : : }
270 : :
271 : : pdf_stm_filter_t *
272 : 1600 : pdf_stm_filter_get_next (pdf_stm_filter_t *filter)
273 : : {
274 : 1600 : return filter->next;
275 : : }
276 : :
277 : : pdf_stm_filter_t *
278 : 7030 : pdf_stm_filter_get_tail (pdf_stm_filter_t *filter)
279 : : {
280 [ + + ]: 7030 : if (!filter->next)
281 : 3615 : return filter;
282 : :
283 : 7030 : return pdf_stm_filter_get_tail (filter->next);
284 : : }
285 : :
286 : : pdf_bool_t
287 : 3511 : pdf_stm_filter_apply (pdf_stm_filter_t *filter,
288 : : pdf_bool_t finish,
289 : : pdf_bool_t *eof,
290 : : pdf_error_t **error)
291 : : {
292 : : /* If the filter is in an error state, just communicate it to the caller */
293 [ + + ]: 3511 : if (filter->error)
294 : : {
295 : : /* The error is copied, the original is left untouched */
296 : 70 : pdf_propagate_error_dup (error, filter->error);
297 : 70 : return PDF_FALSE;
298 : : }
299 : :
300 : : /* If the filter is in EOF state, just communicate it to the caller */
301 : 3441 : *eof = filter->eof;
302 [ + + ]: 3441 : if (filter->eof)
303 : 254 : return PDF_TRUE;
304 : :
305 [ + + ]: 6293 : while (!pdf_buffer_full_p (filter->out))
306 : : {
307 : 6090 : pdf_error_t *inner_error = NULL;
308 : : enum pdf_stm_filter_apply_status_e filter_status;
309 : : pdf_bool_t input_eof;
310 : :
311 : : /* Generate output */
312 : 6090 : filter_status = filter->impl->apply_fn (filter->state,
313 : : filter->in,
314 : : filter->out,
315 : 6090 : filter->really_finish,
316 : : &(filter->error));
317 : :
318 [ + + ]: 6090 : if (filter_status == PDF_STM_FILTER_APPLY_STATUS_ERROR)
319 : : {
320 : : /* The error is copied, the original is left untouched */
321 : 140 : pdf_propagate_error_dup (error, filter->error);
322 : 140 : return PDF_FALSE;
323 : : }
324 : :
325 [ + + ]: 5950 : if (filter_status == PDF_STM_FILTER_APPLY_STATUS_EOF)
326 : : {
327 : : /* The filter is now in an EOF condition. We should not call
328 : : * this filter anymore without a previous reset */
329 : 188 : *eof = filter->eof = PDF_TRUE;
330 : 188 : return PDF_TRUE;
331 : : }
332 : :
333 [ + - ]: 5762 : if (filter_status == PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT)
334 : : {
335 : : /* The filter needs to generate output and the output buffer
336 : : * is full */
337 : : break;
338 : : }
339 : :
340 : : /* The filter needs more input, try to get the input buffer
341 : : * filled with some data */
342 : 5762 : input_eof = PDF_FALSE;
343 [ - + ]: 5762 : if (!pdf_stm_filter_get_input (filter,
344 : : finish,
345 : : &input_eof,
346 : : &inner_error))
347 : : {
348 : : /* Error getting input, propagate */
349 : 0 : filter->error = inner_error;
350 : 0 : pdf_propagate_error_dup (error, filter->error);
351 : 0 : return PDF_FALSE;
352 : : }
353 : :
354 : : /* EOF when getting input? */
355 [ + + ]: 5762 : if (input_eof)
356 : : {
357 [ + + ]: 5561 : if (!pdf_buffer_eob_p (filter->in))
358 : : {
359 : : /* We got EOF, but data is still available in the input,
360 : : * so go on */
361 : 1308 : continue;
362 : : }
363 : :
364 [ + + ][ + + ]: 4253 : if ((!filter->really_finish) &&
[ + + ][ + + ]
365 : 1611 : ((filter->mode == PDF_STM_FILTER_MODE_WRITE &&
366 : : finish) ||
367 : 1152 : (filter->mode == PDF_STM_FILTER_MODE_READ)))
368 : : {
369 : 1597 : filter->really_finish = PDF_TRUE;
370 : 1597 : continue;
371 : : }
372 : :
373 : : /* Propagate EOF error without storing it */
374 : 2656 : *eof = PDF_TRUE;
375 : 2656 : return PDF_TRUE;
376 : : }
377 : :
378 : : /* Filter got more input, continue */
379 : : }
380 : :
381 : : /* all done */
382 : 3511 : return PDF_TRUE;
383 : : }
384 : :
385 : : /* NOTE: This method is not public and not used anywhere, do we need it? */
386 : : pdf_bool_t
387 : 0 : pdf_stm_filter_reset (pdf_stm_filter_t *filter,
388 : : const pdf_hash_t *params,
389 : : pdf_error_t **error)
390 : : {
391 : 0 : pdf_clear_error (&(filter->error));
392 : 0 : filter->really_finish = PDF_FALSE;
393 : 0 : filter->eof = PDF_FALSE;
394 : :
395 : : /* Deinit before re-init */
396 [ # # ]: 0 : if (filter->impl->deinit_fn)
397 : 0 : filter->impl->deinit_fn (filter->state);
398 : :
399 : : /* Re-init */
400 [ # # ]: 0 : return (filter->impl->init_fn ?
401 : 0 : filter->impl->init_fn (params,
402 : : &(filter->state),
403 : : error) :
404 : : PDF_TRUE);
405 : : }
406 : :
407 : : /*
408 : : * Private functions
409 : : */
410 : :
411 : : static pdf_bool_t
412 : : pdf_stm_filter_get_input (pdf_stm_filter_t *filter,
413 : : pdf_bool_t finish,
414 : : pdf_bool_t *eof,
415 : : pdf_error_t **error)
416 : : {
417 : : /* The input buffer should be empty at this point */
418 : 5762 : pdf_buffer_rewind (filter->in);
419 : :
420 [ + + ]: 5762 : if (filter->next)
421 : 1162 : return pdf_stm_filter_apply (filter->next, finish, eof, error);
422 : :
423 : 4600 : *eof = PDF_FALSE;
424 [ + + ]: 4600 : if (filter->backend)
425 : : {
426 : : pdf_ssize_t read_bytes;
427 : :
428 : 3501 : read_bytes = pdf_stm_be_read (filter->backend,
429 : : filter->in->data,
430 : : filter->in->size,
431 : : error);
432 [ - + ]: 3501 : if (read_bytes < 0)
433 : 0 : return PDF_FALSE;
434 : :
435 : 3501 : filter->in->wp = (pdf_size_t)read_bytes;
436 [ + + ]: 3501 : if (read_bytes == filter->in->size)
437 : 201 : return PDF_TRUE;
438 : : /* else, no more input */
439 : : }
440 : : /* else, no backend */
441 : :
442 : 4399 : *eof = PDF_TRUE;
443 : 4399 : return PDF_TRUE;
444 : : }
445 : :
446 : : /* End of pdf-stm-filter.c */
|