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, 2009 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 :
30 : /* Forward references */
31 : static pdf_size_t pdf_stm_filter_get_input (pdf_stm_filter_t filter,
32 : pdf_bool_t finish_p);
33 :
34 :
35 : /*
36 : * Public functions
37 : */
38 :
39 : pdf_status_t
40 : pdf_stm_filter_new (enum pdf_stm_filter_type_e type,
41 : pdf_hash_t params,
42 : pdf_size_t buffer_size,
43 : enum pdf_stm_filter_mode_e mode,
44 : pdf_stm_filter_t *filter)
45 859 : {
46 859 : pdf_status_t init_ret = PDF_ERROR;
47 : pdf_stm_filter_t new;
48 :
49 : /* Allocate the filter structure */
50 859 : new = (pdf_stm_filter_t)
51 : pdf_alloc (sizeof(struct pdf_stm_filter_s));
52 :
53 859 : if (new)
54 : {
55 : /* Initialisation */
56 859 : new->type = type;
57 :
58 : /* Data sources */
59 859 : new->next = NULL;
60 859 : new->backend = NULL;
61 :
62 : /* Operation mode */
63 859 : new->mode = mode;
64 :
65 : /* Input buffer */
66 859 : new->in = pdf_buffer_new (buffer_size);
67 859 : if (!new->in)
68 : {
69 : /* Not enough memory. Retreat. */
70 0 : pdf_dealloc (new);
71 0 : goto exit;
72 : }
73 :
74 : /* Output buffer */
75 859 : new->out = NULL;
76 :
77 : /* Install the appropriate implementation */
78 859 : switch (new->type)
79 : {
80 : case PDF_STM_FILTER_NULL:
81 : {
82 806 : new->impl.init_fn = pdf_stm_f_null_init;
83 806 : new->impl.apply_fn = pdf_stm_f_null_apply;
84 806 : new->impl.dealloc_state_fn = pdf_stm_f_null_dealloc_state;
85 806 : break;
86 : }
87 : case PDF_STM_FILTER_AHEX_ENC:
88 : {
89 2 : new->impl.init_fn = pdf_stm_f_ahexenc_init;
90 2 : new->impl.apply_fn = pdf_stm_f_ahexenc_apply;
91 2 : new->impl.dealloc_state_fn = pdf_stm_f_ahexenc_dealloc_state;
92 2 : break;
93 : }
94 : case PDF_STM_FILTER_AHEX_DEC:
95 : {
96 3 : new->impl.init_fn = pdf_stm_f_ahexdec_init;
97 3 : new->impl.apply_fn = pdf_stm_f_ahexdec_apply;
98 3 : new->impl.dealloc_state_fn = pdf_stm_f_ahexdec_dealloc_state;
99 3 : break;
100 : }
101 : case PDF_STM_FILTER_RL_ENC:
102 : {
103 1 : new->impl.init_fn = pdf_stm_f_rlenc_init;
104 1 : new->impl.apply_fn = pdf_stm_f_rlenc_apply;
105 1 : new->impl.dealloc_state_fn = pdf_stm_f_rlenc_dealloc_state;
106 1 : break;
107 : }
108 : case PDF_STM_FILTER_RL_DEC:
109 : {
110 1 : new->impl.init_fn = pdf_stm_f_rldec_init;
111 1 : new->impl.apply_fn = pdf_stm_f_rldec_apply;
112 1 : new->impl.dealloc_state_fn = pdf_stm_f_rldec_dealloc_state;
113 1 : break;
114 : }
115 : #if defined PDF_HAVE_LIBZ
116 : case PDF_STM_FILTER_FLATE_ENC:
117 : {
118 1 : new->impl.init_fn = pdf_stm_f_flateenc_init;
119 1 : new->impl.apply_fn = pdf_stm_f_flateenc_apply;
120 1 : new->impl.dealloc_state_fn = pdf_stm_f_flateenc_dealloc_state;
121 1 : break;
122 : }
123 : case PDF_STM_FILTER_FLATE_DEC:
124 : {
125 1 : new->impl.init_fn = pdf_stm_f_flatedec_init;
126 1 : new->impl.apply_fn = pdf_stm_f_flatedec_apply;
127 1 : new->impl.dealloc_state_fn = pdf_stm_f_flatedec_dealloc_state;
128 1 : break;
129 : }
130 : #endif /* PDF_HAVE_LIBZ */
131 : case PDF_STM_FILTER_V2_ENC:
132 : {
133 2 : new->impl.init_fn = pdf_stm_f_v2enc_init;
134 2 : new->impl.apply_fn = pdf_stm_f_v2enc_apply;
135 2 : new->impl.dealloc_state_fn = pdf_stm_f_v2enc_dealloc_state;
136 2 : break;
137 : }
138 : case PDF_STM_FILTER_V2_DEC:
139 : {
140 1 : new->impl.init_fn = pdf_stm_f_v2dec_init;
141 1 : new->impl.apply_fn = pdf_stm_f_v2dec_apply;
142 1 : new->impl.dealloc_state_fn = pdf_stm_f_v2dec_dealloc_state;
143 1 : break;
144 : }
145 : case PDF_STM_FILTER_AESV2_ENC:
146 : {
147 2 : new->impl.init_fn = pdf_stm_f_aesv2enc_init;
148 2 : new->impl.apply_fn = pdf_stm_f_aesv2enc_apply;
149 2 : new->impl.dealloc_state_fn = pdf_stm_f_aesv2enc_dealloc_state;
150 2 : break;
151 : }
152 : case PDF_STM_FILTER_AESV2_DEC:
153 : {
154 1 : new->impl.init_fn = pdf_stm_f_aesv2dec_init;
155 1 : new->impl.apply_fn = pdf_stm_f_aesv2dec_apply;
156 1 : new->impl.dealloc_state_fn = pdf_stm_f_aesv2dec_dealloc_state;
157 1 : break;
158 : }
159 : case PDF_STM_FILTER_MD5_ENC:
160 : {
161 1 : new->impl.init_fn = pdf_stm_f_md5enc_init;
162 1 : new->impl.apply_fn = pdf_stm_f_md5enc_apply;
163 1 : new->impl.dealloc_state_fn = pdf_stm_f_md5enc_dealloc_state;
164 1 : break;
165 : }
166 : case PDF_STM_FILTER_LZW_ENC:
167 : {
168 1 : new->impl.init_fn = pdf_stm_f_lzwenc_init;
169 1 : new->impl.apply_fn = pdf_stm_f_lzwenc_apply;
170 1 : new->impl.dealloc_state_fn = pdf_stm_f_lzwenc_dealloc_state;
171 1 : break;
172 : }
173 : case PDF_STM_FILTER_LZW_DEC:
174 : {
175 1 : new->impl.init_fn = pdf_stm_f_lzwdec_init;
176 1 : new->impl.apply_fn = pdf_stm_f_lzwdec_apply;
177 1 : new->impl.dealloc_state_fn = pdf_stm_f_lzwdec_dealloc_state;
178 1 : break;
179 : }
180 : case PDF_STM_FILTER_A85_ENC:
181 : {
182 5 : new->impl.init_fn = pdf_stm_f_a85enc_init;
183 5 : new->impl.apply_fn = pdf_stm_f_a85enc_apply;
184 5 : new->impl.dealloc_state_fn = pdf_stm_f_a85enc_dealloc_state;
185 5 : break;
186 : }
187 : case PDF_STM_FILTER_A85_DEC:
188 : {
189 30 : new->impl.init_fn = pdf_stm_f_a85dec_init;
190 30 : new->impl.apply_fn = pdf_stm_f_a85dec_apply;
191 30 : new->impl.dealloc_state_fn = pdf_stm_f_a85dec_dealloc_state;
192 30 : break;
193 : }
194 : #if defined PDF_HAVE_LIBJBIG2DEC
195 : case PDF_STM_FILTER_JBIG2_DEC:
196 : {
197 0 : new->impl.init_fn = pdf_stm_f_jbig2dec_init;
198 0 : new->impl.apply_fn = pdf_stm_f_jbig2dec_apply;
199 0 : new->impl.dealloc_state_fn = pdf_stm_f_jbig2dec_dealloc_state;
200 : break;
201 : }
202 : #endif /* PDF_HAVE_LIBJBIG2DEC */
203 : #if defined PDF_HAVE_LIBJPEG
204 : case PDF_STM_FILTER_DCT_DEC:
205 : {
206 : new->impl.init_fn = pdf_stm_f_dctdec_init;
207 : new->impl.apply_fn = pdf_stm_f_dctdec_apply;
208 : new->impl.dealloc_state_fn = pdf_stm_f_dctdec_dealloc_state;
209 : break;
210 : }
211 : #endif /* PDF_HAVE_LIBJPEG */
212 : default:
213 : {
214 : /* Shall not be reached, but makes the compiler happy */
215 : break;
216 : }
217 : }
218 :
219 : /* Initialization of the implementation */
220 859 : new->params = params;
221 859 : new->state = NULL;
222 859 : new->status = PDF_OK;
223 859 : new->really_finish_p = PDF_FALSE;
224 :
225 859 : init_ret = new->impl.init_fn (new->params,
226 : &(new->state));
227 859 : if (init_ret != PDF_OK)
228 : {
229 : /* Error initializing the filter implementation */
230 1 : pdf_buffer_destroy (new->in);
231 1 : pdf_dealloc (new);
232 1 : new = NULL;
233 : }
234 :
235 859 : *filter = new;
236 : }
237 :
238 859 : exit:
239 :
240 859 : return init_ret;
241 : }
242 :
243 : pdf_status_t
244 : pdf_stm_filter_destroy (pdf_stm_filter_t filter)
245 673 : {
246 673 : pdf_buffer_destroy (filter->in);
247 673 : filter->impl.dealloc_state_fn (filter->state);
248 673 : pdf_dealloc (filter);
249 :
250 : /* Note that the memory used by the output buffer and by the params
251 : hash is NOT managed by the filter */
252 :
253 673 : return PDF_OK;
254 : }
255 :
256 : inline pdf_status_t
257 : pdf_stm_filter_set_next (pdf_stm_filter_t filter,
258 : pdf_stm_filter_t next_filter)
259 56 : {
260 56 : filter->next = next_filter;
261 56 : return PDF_OK;
262 : }
263 :
264 : inline pdf_status_t
265 : pdf_stm_filter_set_be (pdf_stm_filter_t filter,
266 : pdf_stm_be_t be)
267 762 : {
268 762 : filter->backend = be;
269 762 : return PDF_OK;
270 : }
271 :
272 : inline pdf_status_t
273 : pdf_stm_filter_set_out (pdf_stm_filter_t filter,
274 : pdf_buffer_t buffer)
275 914 : {
276 914 : filter->out = buffer;
277 914 : return PDF_OK;
278 : }
279 :
280 : inline pdf_buffer_t
281 : pdf_stm_filter_get_in (pdf_stm_filter_t filter)
282 1289 : {
283 1289 : return filter->in;
284 : }
285 :
286 : pdf_status_t
287 : pdf_stm_filter_apply (pdf_stm_filter_t filter,
288 : pdf_bool_t finish_p)
289 6062 : {
290 : pdf_status_t ret;
291 : pdf_status_t apply_ret;
292 : pdf_status_t ret_in;
293 :
294 : /* If the filter is in an error state or it is in an eof state, just
295 : communicate it to the caller */
296 6062 : if (filter->status != PDF_OK)
297 : {
298 14 : return filter->status;
299 : }
300 :
301 6048 : ret = PDF_OK;
302 14928 : while (!pdf_buffer_full_p (filter->out))
303 : {
304 : /* Generate output */
305 8659 : apply_ret = filter->impl.apply_fn (filter->params,
306 : filter->state,
307 : filter->in,
308 : filter->out,
309 : filter->really_finish_p);
310 :
311 8659 : if (apply_ret == PDF_ERROR)
312 : {
313 : /* The filter is now in an error condition. We should not
314 : call this filter anymore without a previous reset */
315 14 : filter->status = PDF_ERROR;
316 14 : ret = filter->status;
317 14 : break;
318 : }
319 8645 : if (apply_ret == PDF_EEOF)
320 : {
321 : /* The filter is now in an EOF condition. We should not call
322 : this filter anymore without a previous reset */
323 20 : filter->status = PDF_EEOF;
324 20 : ret = filter->status;
325 20 : break;
326 : }
327 8625 : if (apply_ret == PDF_ENINPUT)
328 : {
329 : /* The filter needs more input, try to get the input buffer
330 : filled with some data */
331 14876 : ret_in = pdf_stm_filter_get_input (filter, finish_p);
332 7438 : if (ret_in == PDF_ERROR)
333 : {
334 0 : filter->status = PDF_ERROR;
335 0 : ret = filter->status;
336 0 : break;
337 : }
338 7438 : else if ((ret_in == PDF_EEOF)
339 : && (pdf_buffer_eob_p (filter->in)))
340 : {
341 6100 : if (((filter->mode == PDF_STM_FILTER_MODE_WRITE)
342 : && ((finish_p) && (!filter->really_finish_p))) ||
343 : ((filter->mode == PDF_STM_FILTER_MODE_READ)
344 : && (!filter->really_finish_p)))
345 : {
346 747 : filter->really_finish_p = PDF_TRUE;
347 : }
348 : else
349 : {
350 4606 : ret = PDF_EEOF;
351 4606 : break;
352 : }
353 : }
354 : }
355 4019 : if (apply_ret == PDF_ENOUTPUT)
356 : {
357 : /* The filter needs to generate output and the output buffer
358 : is full */
359 1187 : filter->status = PDF_OK;
360 1187 : break;
361 : }
362 : }
363 :
364 6048 : return ret;
365 : }
366 :
367 : pdf_status_t
368 : pdf_stm_filter_reset (pdf_stm_filter_t filter)
369 0 : {
370 0 : filter->status = PDF_OK;
371 0 : filter->really_finish_p = PDF_FALSE;
372 0 : return filter->impl.init_fn (filter->params,
373 : &(filter->state));
374 : }
375 :
376 : pdf_stm_filter_t
377 : pdf_stm_filter_get_tail (pdf_stm_filter_t filter)
378 2425 : {
379 2425 : if (filter->next == NULL)
380 : {
381 1233 : return filter;
382 : }
383 : else
384 : {
385 1192 : return pdf_stm_filter_get_tail (filter->next);
386 : }
387 : }
388 :
389 : /*
390 : * Private functions
391 : */
392 :
393 : static pdf_size_t
394 : pdf_stm_filter_get_input (pdf_stm_filter_t filter,
395 : pdf_bool_t finish_p)
396 : {
397 : pdf_status_t ret;
398 : pdf_size_t read_bytes;
399 :
400 : /* The input buffer should be empty at this point */
401 7438 : pdf_buffer_rewind (filter->in);
402 :
403 7438 : ret = PDF_OK;
404 7438 : if (filter->next != NULL)
405 : {
406 2479 : ret = pdf_stm_filter_apply (filter->next, finish_p);
407 : }
408 4959 : else if (filter->backend != NULL)
409 : {
410 2536 : read_bytes = pdf_stm_be_read (filter->backend,
411 : filter->in->data,
412 : filter->in->size);
413 2536 : filter->in->wp = read_bytes;
414 2536 : if (read_bytes < filter->in->size)
415 : {
416 2277 : ret = PDF_EEOF;
417 : }
418 : }
419 : else
420 : {
421 : /* No backend */
422 2423 : ret = PDF_EEOF;
423 : }
424 :
425 7438 : return ret;
426 : }
427 :
428 : /* End of pdf-stm-filter.c */
|