1 : /* -*- mode: C -*-
2 : *
3 : * File: pdf-stm-f-a85.c
4 : * Date: Mon Jul 9 22:01:41 2007
5 : *
6 : * GNU PDF Library - ASCII85 stream filter
7 : *
8 : */
9 :
10 : /* Copyright (C) 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 : #include <string.h>
28 :
29 : #include <pdf-types.h>
30 : #include <pdf-stm-f-a85.h>
31 :
32 : #include <ctype.h>
33 :
34 : /*
35 : * static function prototypes
36 : */
37 :
38 : static pdf_status_t
39 : pdf_stm_f_a85enc_wr_tuple (pdf_u32_t tuple, pdf_u8_t tuple_bytes,
40 : void *state, pdf_buffer_t out);
41 :
42 : static pdf_status_t
43 : pdf_stm_f_a85dec_wr_quad (const pdf_char_t * quint, const pdf_size_t outcount,
44 : pdf_buffer_t out, pdf_stm_f_a85_t filter_state);
45 :
46 : static pdf_status_t
47 : pdf_stm_f_a85dec_getnext (pdf_buffer_t in, pdf_char_t * pc);
48 :
49 : static pdf_status_t
50 : pdf_stm_f_a85_write_out (pdf_char_t c, pdf_buffer_t out,
51 : pdf_stm_f_a85_t filter_state);
52 :
53 : static pdf_status_t
54 : pdf_stm_f_a85_flush_outbuff (pdf_buffer_t out, pdf_stm_f_a85_t filter_state);
55 :
56 : /*
57 : * Public functions
58 : */
59 :
60 : pdf_status_t
61 : pdf_stm_f_a85enc_init (pdf_hash_t params, void **state)
62 5 : {
63 :
64 : pdf_stm_f_a85_t filter_state;
65 :
66 5 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_a85_s));
67 5 : if (NULL == filter_state)
68 : {
69 0 : return PDF_ERROR;
70 : }
71 :
72 : /* Initialization */
73 :
74 5 : filter_state->line_length = 0;
75 5 : filter_state->spare_count = 0;
76 5 : filter_state->output_count = 0;
77 5 : filter_state->terminated = PDF_FALSE;
78 :
79 5 : *state = (void *) filter_state;
80 5 : return PDF_OK;
81 : }
82 :
83 : /* pdf_stm_f_a85_write_out helps deal with the possibility of extremely
84 : * small output buffer sizes - like 1 byte for example. Since this
85 : * filter needs to work with 4 to 5 input bytes at a time, and since it
86 : * then produces 1 to 8 output bytes at a time, it is necessary to be
87 : * able to buffer up to 8 output bytes internally, and then wait for
88 : * them to be sent to the output stream.
89 : *
90 : * pdf_stm_f_a85_write_out sends data directly to the output stream if
91 : * there is room, and if no data is already waiting to go out.
92 : * If there is data waiting to go out, then it appends to the end of
93 : * the output buffer.
94 : *
95 : * All writing to the out stream from this filter should take place
96 : * through this function.
97 : *
98 : * it is critical that pdf_stm_a85_flush_outbuff return PDF_OK
99 : * (meaning that it's output buffers are empty) before starting
100 : * to send a new group of output bytes with pdf_stm_f_a85_write_out.
101 : *
102 : */
103 :
104 : static pdf_status_t
105 : pdf_stm_f_a85_write_out (pdf_char_t c, pdf_buffer_t out,
106 : pdf_stm_f_a85_t filter_state)
107 272 : {
108 272 : pdf_status_t retval = PDF_OK;
109 :
110 : #ifdef PDF_A85_FORCE_FAILURE
111 : if('x' == c) { c = 'X'; }
112 : #endif
113 :
114 518 : if (!pdf_buffer_full_p (out) && (0 == filter_state->output_count))
115 : {
116 246 : out->data[out->wp++] = c;
117 246 : retval = PDF_OK;
118 : }
119 : else
120 : {
121 26 : if (filter_state->output_count < A85_OUTPUT_BUFF_LEN)
122 : {
123 26 : filter_state->output_buff[filter_state->output_count++] = c;
124 26 : retval = PDF_OK;
125 : }
126 : else
127 : {
128 0 : retval = PDF_ERROR;
129 : }
130 : }
131 :
132 272 : return retval;
133 : }
134 :
135 : /* pdf_stm_f_a85_flush_outbuff helps deal with the possibility of extremely
136 : * small output buffer sizes - like 1 byte for example. Since this
137 : * filter needs to work with 4 to 5 input bytes at a time, and since it
138 : * then produces 1 to 8 output bytes at a time, it is necessary to be
139 : * able to buffer up to 8 output bytes internally, and then wait for
140 : * them to be sent to the output stream.
141 : *
142 : * Because this output buffer is sized to handle the output data from a single
143 : * input group (up to 8 bytes for the encoding (5 output data bytes, plus a
144 : * newline, plus the terminating sequence)) it is necessary that the output
145 : * buffer be empty before starting to generate another set of output.
146 : *
147 : * pdf_stm_f_a85_flush_outbuff must return PDF_OK before starting to generate
148 : * a new set of output bytes. This ensures that all call to _write_out for
149 : * this set of output bytes will succeed, and no data will be lost.
150 : *
151 : */
152 : static pdf_status_t
153 : pdf_stm_f_a85_flush_outbuff (pdf_buffer_t out, pdf_stm_f_a85_t filter_state)
154 319 : {
155 319 : pdf_status_t retval = PDF_OK;
156 : pdf_size_t i;
157 : pdf_size_t k;
158 :
159 319 : i = 0;
160 :
161 690 : while ((i < filter_state->output_count) && (PDF_OK == retval))
162 : {
163 52 : if (pdf_buffer_full_p (out))
164 : {
165 26 : retval = PDF_ENOUTPUT;
166 : }
167 : else
168 : {
169 26 : out->data[out->wp++] = filter_state->output_buff[i++];
170 : }
171 : }
172 :
173 638 : if ((PDF_ENOUTPUT == retval) || (i == filter_state->output_count))
174 : { /* done flushing (to the extent possible) */
175 : /* shift remaining bytes back to the beginning of buffer */
176 :
177 382 : for (k = 0; (k + i) < filter_state->output_count; k++)
178 : {
179 63 : filter_state->output_buff[k] = filter_state->output_buff[k + i];
180 : }
181 :
182 319 : filter_state->output_count -= i;
183 :
184 : }
185 : else
186 : { /* This should not be reachable */
187 0 : retval = PDF_ERROR;
188 : }
189 :
190 319 : return retval;
191 : }
192 :
193 :
194 :
195 : static pdf_status_t
196 : pdf_stm_f_a85enc_wr_tuple (pdf_u32_t tuple,
197 : pdf_u8_t tuple_bytes, /* always 4 for a full tuple */
198 : void *state,
199 : pdf_buffer_t out)
200 8 : {
201 8 : pdf_status_t retval = PDF_OK;
202 : pdf_stm_f_a85_t filter_state;
203 : pdf_char_t buf[5];
204 : int i;
205 :
206 8 : filter_state = (pdf_stm_f_a85_t) state;
207 :
208 : /* partial tuple doesn't get z handling */
209 8 : if ((0 == tuple) && (4 == tuple_bytes))
210 : {
211 : /* Four 0s in row */
212 :
213 2 : retval = pdf_stm_f_a85_write_out ('z', out, filter_state);
214 : /*
215 : * PDF_ERROR from pdf_stm_f_a85_write_out means full buffer
216 : * This should never happen because buffer should have been
217 : * flushed before starting this set of output data. All
218 : * subsequent calls to _write_out will fail with PDF_ERROR
219 : * also, so it is reasonable to ignore the pass or fail
220 : * status of these invocations within this function. The
221 : * error will be reported back to the caller of this function.
222 : */
223 2 : filter_state->line_length++;
224 :
225 2 : if (filter_state->line_length >= A85_ENC_LINE_LENGTH)
226 : {
227 0 : retval = pdf_stm_f_a85_write_out ('\n', out, filter_state);
228 0 : filter_state->line_length = 0;
229 : }
230 : }
231 : else
232 : {
233 : /* Encode this tuple in base-85 */
234 36 : for (i = 0; i < 5; i++)
235 : {
236 30 : buf[i] = (pdf_char_t) (tuple % 85);
237 30 : tuple = tuple / 85;
238 : }
239 :
240 30 : for (i = tuple_bytes; i >= 0; i--)
241 : {
242 24 : retval = pdf_stm_f_a85_write_out (buf[i] + (pdf_char_t) '!',
243 : out, filter_state);
244 24 : filter_state->line_length++;
245 24 : if (filter_state->line_length >= A85_ENC_LINE_LENGTH)
246 : {
247 0 : retval = pdf_stm_f_a85_write_out ('\n', out, filter_state);
248 :
249 0 : filter_state->line_length = 0;
250 : }
251 : }
252 : }
253 :
254 8 : return retval;
255 : }
256 :
257 : pdf_status_t
258 : pdf_stm_f_a85enc_apply (pdf_hash_t params, void *state, pdf_buffer_t in,
259 : pdf_buffer_t out, pdf_bool_t finish_p)
260 96 : {
261 : pdf_size_t in_size;
262 : pdf_stm_f_a85_t filter_state;
263 :
264 : pdf_u32_t tuple;
265 : pdf_size_t read_bytes;
266 : pdf_size_t pos_in;
267 : int avail;
268 : int i;
269 : pdf_char_t buf[5];
270 : pdf_char_t temp_byte;
271 96 : pdf_status_t retval = PDF_OK;
272 :
273 96 : filter_state = (pdf_stm_f_a85_t) state;
274 :
275 : /*
276 : * ASCII base-85 encoding produces 5 ASCII characters for every 4
277 : * bytes in the input data.
278 : *
279 : * But take care of the EOD marker (~>) and the newlines/whitespace.
280 : *
281 : * Note that 0x00000000 is coded with 'z',
282 : */
283 :
284 : /*
285 : * Make sure that the output_buff is flushed and ready to accept another
286 : * batch of data
287 : */
288 :
289 96 : retval = pdf_stm_f_a85_flush_outbuff (out, filter_state);
290 :
291 96 : if (PDF_OK != retval)
292 : { /* Probably this is PDF_ENOUTPUT - meaning output_buff still has data */
293 18 : return retval;
294 : }
295 :
296 : /* Pull any leftover data from last _apply from state->spare_bytes */
297 :
298 78 : if (filter_state->spare_count)
299 : {
300 39 : avail = in->wp - in->rp;
301 39 : if ((avail + filter_state->spare_count) >= 4)
302 : { /* There is a full tuple available */
303 :
304 5 : tuple = 0;
305 :
306 5 : i = 0;
307 :
308 5 : tuple = tuple | (filter_state->spare_bytes[i++] << 24);
309 5 : filter_state->spare_count--;
310 :
311 5 : if (filter_state->spare_count)
312 : {
313 5 : temp_byte = filter_state->spare_bytes[i++];
314 5 : filter_state->spare_count--;
315 : }
316 : else
317 : {
318 0 : temp_byte = in->data[in->rp++];
319 : }
320 :
321 5 : tuple = tuple | (temp_byte << 16);
322 :
323 5 : if (filter_state->spare_count)
324 : { /* don't bother incrementing i here - not used again */
325 5 : temp_byte = filter_state->spare_bytes[i];
326 5 : filter_state->spare_count--;
327 : }
328 : else
329 : {
330 0 : temp_byte = in->data[in->rp++];
331 : }
332 :
333 5 : tuple = tuple | (temp_byte << 8);
334 :
335 5 : tuple = tuple | in->data[in->rp++];
336 :
337 5 : retval = pdf_stm_f_a85enc_wr_tuple (tuple, 4, filter_state, out);
338 :
339 : } /* End of if there is a full tuple available */
340 : else
341 : {
342 : /* There was no full tuple available - do nothing.
343 : If finish_p is set, then a partial tuple will be written later */
344 34 : retval = PDF_ENINPUT;
345 : }
346 :
347 : } /* end of if spare_count */
348 :
349 78 : retval = pdf_stm_f_a85_flush_outbuff (out, filter_state);
350 :
351 78 : if (PDF_OK != retval)
352 : { /* Probably this is PDF_ENOUTPUT - meaning output_buff still has data */
353 3 : return retval;
354 : }
355 :
356 :
357 : /* Now do all normal tuples */
358 :
359 75 : in_size = in->wp - in->rp;
360 :
361 :
362 75 : if ((PDF_OK == retval) && (in_size >= 4))
363 : {
364 :
365 0 : for (pos_in = 0; (pos_in < in_size) && (PDF_OK == retval); pos_in += 4)
366 : {
367 0 : tuple = 0;
368 0 : avail = in_size - pos_in;
369 :
370 0 : if (avail >= 4)
371 : {
372 0 : tuple = tuple | (in->data[in->rp] << 24);
373 0 : tuple = tuple | (in->data[in->rp + 1] << 16);
374 0 : tuple = tuple | (in->data[in->rp + 2] << 8);
375 0 : tuple = tuple | in->data[in->rp + 3];
376 :
377 0 : in->rp += 4;
378 :
379 0 : retval = pdf_stm_f_a85enc_wr_tuple (tuple, 4, filter_state, out);
380 :
381 0 : retval = pdf_stm_f_a85_flush_outbuff (out, filter_state);
382 :
383 : } /* end of whole tuple available */
384 :
385 : } /* end for loop */
386 :
387 0 : if (PDF_OK == retval)
388 : { /* Loop terminated by PDF_ENINPUT */
389 0 : retval = PDF_ENINPUT;
390 : }
391 :
392 : } /* End if retval == PDF_OK && whole tuple available */
393 75 : else if ((PDF_OK == retval) && (in_size < 4))
394 : {
395 75 : retval = PDF_ENINPUT;
396 : }
397 : /* Now if finish_p do a partial tuple if there are leftover bytes */
398 :
399 75 : if (finish_p && (PDF_ENINPUT == retval))
400 : {
401 :
402 : /* If the length of the binary data to be encoded is not a multiple of 4
403 : bytes, the last, partial group of 4 is used to produce a last, partial
404 : group of 5 output characters. Given n (1, 2 or 3) bytes of binary
405 : data, the encoder first appends 4 - n zero bytes to make a complete
406 : group of 4. It then encodes this group in the usual way, but without
407 : applying the special z case. Finally, it writes only the first n + 1
408 : characters of the resulting group of 5. */
409 :
410 20 : in_size = filter_state->spare_count + (in->wp - in->rp);
411 :
412 20 : if (in_size)
413 : {
414 :
415 9 : for (i = 0; i < (4 - in_size); i++)
416 : {
417 6 : buf[i] = 0;
418 : }
419 :
420 3 : read_bytes = 0;
421 :
422 9 : for (i = (4 - in_size); i < 4; i++)
423 : {
424 :
425 6 : avail = in->wp - in->rp;
426 :
427 6 : if (filter_state->spare_count || avail)
428 : {
429 6 : if (filter_state->spare_count)
430 : {
431 6 : buf[i] = filter_state->spare_bytes[read_bytes++];
432 6 : filter_state->spare_count--;
433 : }
434 : else
435 : {
436 0 : buf[i] = in->data[in->rp++];
437 : }
438 : }
439 : else
440 : {
441 0 : buf[i] = 0;
442 : }
443 :
444 : }
445 :
446 3 : tuple = 0;
447 3 : tuple = tuple | buf[0] << 24;
448 3 : tuple = tuple | buf[1] << 16;
449 3 : tuple = tuple | buf[2] << 8;
450 3 : tuple = tuple | buf[3];
451 :
452 3 : retval =
453 : pdf_stm_f_a85enc_wr_tuple (tuple, in_size, filter_state, out);
454 :
455 :
456 : } /* end of if (in_size) */
457 : else
458 : {
459 : /* There was no partial tuple to write out. Do Nothing. */
460 : }
461 :
462 20 : if (!filter_state->terminated)
463 : {
464 : /* Insert the EOD marker */
465 5 : retval = pdf_stm_f_a85_write_out ('~', out, filter_state);
466 5 : retval = pdf_stm_f_a85_write_out ('>', out, filter_state);
467 :
468 5 : filter_state->terminated = PDF_TRUE;
469 : }
470 :
471 : }
472 55 : else if (PDF_ENINPUT == retval)
473 : { /* finish_p not set, so save partial tuple (if present) for next call */
474 55 : avail = in->wp - in->rp;
475 131 : while (avail)
476 : {
477 21 : if (filter_state->spare_count >= A85_SPARE_BYTES_LEN)
478 : {
479 0 : retval = PDF_ERROR;
480 : }
481 : else
482 : {
483 21 : filter_state->spare_bytes[filter_state->spare_count++] =
484 : in->data[in->rp++];
485 : }
486 21 : avail--;
487 : }
488 : }
489 :
490 :
491 75 : if (finish_p && (PDF_OK == retval))
492 : {
493 5 : retval = pdf_stm_f_a85_flush_outbuff (out, filter_state);
494 :
495 5 : if (PDF_OK == retval)
496 : { /* We have completed this filter job: */
497 0 : retval = PDF_EEOF;
498 : }
499 : }
500 :
501 75 : return retval;
502 :
503 : }
504 :
505 : pdf_status_t
506 : pdf_stm_f_a85enc_dealloc_state (void *state)
507 5 : {
508 : pdf_stm_f_a85_t a85_state;
509 5 : a85_state = (pdf_stm_f_a85_t) state;
510 5 : pdf_dealloc (a85_state);
511 :
512 5 : return PDF_OK;
513 : }
514 :
515 : /* Do not Pass this function a 'z' quint. */
516 : /* Make certain that there is room in the output buffer before calling */
517 : static pdf_status_t
518 : pdf_stm_f_a85dec_wr_quad (const pdf_char_t * quint, const pdf_size_t outcount,
519 : pdf_buffer_t out, pdf_stm_f_a85_t filter_state)
520 57 : {
521 57 : pdf_status_t retval = PDF_OK;
522 : pdf_u32_t quad;
523 : int i;
524 : pdf_char_t outbytes[4];
525 :
526 57 : if ((outcount < 1) || (outcount > 4))
527 : {
528 0 : retval = PDF_ERROR;
529 0 : return retval;
530 : }
531 :
532 : /* Error check on quint contents */
533 :
534 57 : if (quint[0] > 82)
535 : { /* 83 * 85^4 is greater than 2^32 all by itself. */
536 1 : retval = PDF_ERROR;
537 : }
538 :
539 57 : if ((quint[1] > 84) || (quint[2] > 84) ||
540 : (quint[3] > 84) || (quint[4] > 84))
541 : { /* any character here greater than 84 is an error */
542 6 : retval = PDF_ERROR;
543 : }
544 :
545 : /* Begin Conversion to quad. */
546 57 : quad = (pdf_u32_t) quint[0] * 85u;
547 57 : quad = (quad + (pdf_u32_t) quint[1]) * 85u;
548 57 : quad = (quad + (pdf_u32_t) quint[2]) * 85u;
549 :
550 : /* Now we could be adding up to too big a number */
551 : /* Go in smaller steps and check for potential overflow: */
552 57 : quad = (quad + (pdf_u32_t) quint[3]);
553 :
554 57 : if (quad > (pdf_u32_t) ((pdf_u32_t) UINT32_MAX / (pdf_u32_t) 85u))
555 : { /* This would overflow, so it's an error. Bail */
556 5 : retval = PDF_ERROR;
557 : }
558 : else
559 : {
560 52 : quad = quad * 85u; /* Complete the incorporation of quint[3] */
561 :
562 52 : if (((pdf_u32_t) (UINT32_MAX - quad)) >= (pdf_u32_t) quint[4])
563 : {
564 50 : quad += quint[4];
565 : }
566 : else
567 : {
568 2 : retval = PDF_ERROR;
569 : }
570 : }
571 :
572 57 : if (PDF_OK == retval)
573 : {
574 220 : for (i = 0; i < 4; i++)
575 : {
576 176 : outbytes[3 - i] = quad % 256;
577 176 : quad = quad / 256;
578 : }
579 :
580 200 : for (i = (4 - outcount); i < 4; i++)
581 : {
582 156 : retval = pdf_stm_f_a85_write_out (outbytes[i], out, filter_state);
583 : }
584 : }
585 :
586 57 : return retval;
587 : }
588 :
589 :
590 : pdf_status_t
591 : pdf_stm_f_a85dec_init (pdf_hash_t params, void **state)
592 30 : {
593 :
594 : pdf_stm_f_a85_t filter_state;
595 :
596 30 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_a85_s));
597 30 : if (NULL == filter_state)
598 : {
599 0 : return PDF_ERROR;
600 : }
601 :
602 : /* Initialization */
603 :
604 30 : filter_state->line_length = 0;
605 30 : filter_state->spare_count = 0;
606 30 : filter_state->output_count = 0;
607 :
608 :
609 30 : *state = (void *) filter_state;
610 30 : return PDF_OK;
611 : }
612 :
613 : /* Get the next non-whitespace character */
614 : static pdf_status_t
615 : pdf_stm_f_a85dec_getnext (pdf_buffer_t in, pdf_char_t * pc)
616 : {
617 : /* Get the next non-whitespace character */
618 386 : int done = PDF_FALSE;
619 386 : pdf_status_t retval = PDF_OK;
620 : pdf_char_t c;
621 :
622 795 : while (!done)
623 : {
624 409 : if (in->wp > in->rp)
625 : {
626 342 : c = in->data[in->rp++];
627 342 : if (!isspace (c))
628 : { /* Found a non-whitespace character. We're done. */
629 319 : done = PDF_TRUE;
630 319 : retval = PDF_OK;
631 319 : *pc = c;
632 : }
633 : }
634 : else
635 : { /* ran out of input data. We're done. */
636 67 : retval = PDF_ENINPUT;
637 67 : done = PDF_TRUE;
638 : }
639 : }
640 :
641 386 : return retval;
642 : }
643 :
644 : #define A85_INVALID_TERM_IDX 255
645 :
646 : pdf_status_t
647 : pdf_stm_f_a85dec_apply (pdf_hash_t params, void *state, pdf_buffer_t in,
648 : pdf_buffer_t out, pdf_bool_t finish_p)
649 76 : {
650 : pdf_stm_f_a85_t filter_state;
651 : pdf_char_t quint[5];
652 : pdf_char_t tr_quint[5];
653 : pdf_size_t q_idx;
654 : int i;
655 : int done;
656 : int oldone; /* Outer Loop Done */
657 : pdf_size_t term_idx;
658 76 : pdf_status_t retval = PDF_OK;
659 : int k;
660 :
661 76 : filter_state = (pdf_stm_f_a85_t) state;
662 :
663 : /* Fill the output buffer with the contents of the input buffer, but
664 : note that the second may be bigger than the former */
665 :
666 : /* Only process the next bit of input if the output buffer is empty */
667 76 : retval = pdf_stm_f_a85_flush_outbuff (out, filter_state);
668 76 : if (PDF_OK != retval)
669 : {
670 0 : return retval;
671 : }
672 :
673 :
674 76 : oldone = PDF_FALSE;
675 :
676 292 : while (!oldone)
677 : {
678 :
679 140 : q_idx = 0;
680 140 : term_idx = A85_INVALID_TERM_IDX;
681 :
682 : /* First pull any leftover bytes from last _apply(...) and prepend here */
683 140 : if (filter_state->spare_count)
684 : {
685 : /* First pull the spare_bytes into the quint */
686 25 : for (i = 0; i < filter_state->spare_count; i++)
687 : {
688 16 : quint[q_idx] = filter_state->spare_bytes[i];
689 16 : if ('~' == quint[q_idx])
690 : {
691 7 : term_idx = q_idx;
692 : }
693 16 : q_idx++;
694 : }
695 9 : filter_state->spare_count = 0;
696 : }
697 :
698 : /* Now attempt to fill up the rest of the quint from the input stream */
699 140 : done = PDF_FALSE;
700 526 : for (i = q_idx; ((i < 5) && !done); i++)
701 : {
702 772 : retval = pdf_stm_f_a85dec_getnext (in, &(quint[q_idx]));
703 386 : if (PDF_ENINPUT == retval)
704 : { /* Ran out of input before filling quint */
705 67 : done = PDF_TRUE;
706 : }
707 : else
708 : {
709 319 : if ('~' == quint[q_idx])
710 : {
711 17 : term_idx = q_idx;
712 : }
713 :
714 319 : if ((0 == q_idx) && ('z' == quint[0]))
715 : {
716 20 : done = PDF_TRUE;
717 : }
718 :
719 319 : q_idx++;
720 : }
721 : }
722 :
723 :
724 140 : if (A85_INVALID_TERM_IDX == term_idx)
725 : { /* Normal Processing */
726 116 : if (5 != q_idx)
727 : {
728 88 : if ((1 == q_idx) && ('z' == quint[0]) && (PDF_OK == retval))
729 : { /* special case 'z' encodes value 0x00000000 */
730 20 : retval = pdf_stm_f_a85_write_out (0, out, filter_state);
731 20 : retval = pdf_stm_f_a85_write_out (0, out, filter_state);
732 20 : retval = pdf_stm_f_a85_write_out (0, out, filter_state);
733 20 : retval = pdf_stm_f_a85_write_out (0, out, filter_state);
734 :
735 20 : q_idx = 0;
736 : }
737 48 : else if (PDF_ENINPUT == retval)
738 : { /* Not full dataset. Save this data for later */
739 52 : for (i = 0; i < q_idx; i++)
740 : {
741 4 : filter_state->spare_bytes[i] = quint[i];
742 : }
743 48 : filter_state->spare_count = q_idx;
744 48 : q_idx = 0; /* Clear this so that the output loop is skipped.*/
745 48 : oldone = PDF_TRUE;
746 : }
747 0 : else if (finish_p)
748 : { /* finish specified, but valid term. sequence not present */
749 0 : retval = PDF_ERROR;
750 0 : oldone = PDF_TRUE;
751 : }
752 : else
753 : { /* some other error than PDF_ENINPUT */
754 : /* Let this other error pass through. */
755 0 : oldone = PDF_TRUE;
756 : }
757 : }
758 48 : else if ((5 == q_idx) && (PDF_OK == retval))
759 : { /* 5 good output bytes present */
760 : /* remove the offset from each byte */
761 288 : for (i = 0; i < 5; i++)
762 : {
763 240 : tr_quint[i] = quint[i] - '!';
764 :
765 : }
766 :
767 48 : retval = pdf_stm_f_a85dec_wr_quad (tr_quint, 4, out,
768 : filter_state);
769 :
770 48 : if (PDF_OK != retval)
771 : {
772 : /* Something wrong in writing out data. Save for next call */
773 78 : for (i = 0; i < q_idx; i++)
774 : {
775 65 : filter_state->spare_bytes[i] = quint[i];
776 : }
777 13 : filter_state->spare_count = q_idx;
778 13 : oldone = PDF_TRUE;
779 : }
780 :
781 : }
782 : }
783 : else
784 : { /* Start of termination pattern detected. */
785 :
786 24 : if (1 == term_idx)
787 : {
788 : /* There is a single byte to process before term sequence */
789 : /* This is an error */
790 1 : retval = PDF_ERROR;
791 1 : oldone = PDF_TRUE;
792 : }
793 23 : else if (term_idx > 1)
794 : {
795 : /* Prepare quint for handoff to wr_quad */
796 29 : for (i = 0; i < (5 - term_idx); i++)
797 : { /* Pad with zeroes */
798 20 : tr_quint[i] = 0;
799 : }
800 :
801 34 : for (i = 0; i < term_idx; i++)
802 : { /* Pull in data bytes */
803 25 : tr_quint[(5 - term_idx) + i] = quint[i] - '!';
804 : }
805 :
806 9 : retval = pdf_stm_f_a85dec_wr_quad (tr_quint, (term_idx - 1), out,
807 : filter_state);
808 :
809 : /* Now put remaining parts of the term. seq. at beg. of quint */
810 9 : k = 0;
811 25 : for (i = term_idx; i < q_idx; i++)
812 : {
813 16 : quint[k++] = quint[i];
814 : }
815 9 : q_idx = k;
816 :
817 : }
818 : else
819 : {
820 : /* 0 == term_idx - only term sequence - no quad output */
821 : }
822 :
823 : /* Now check to see if we have valid finishing conditions: */
824 24 : if ((PDF_ENINPUT == retval) && (2 == q_idx)
825 : && ('~' == quint[0]) && ('>' == quint[1]))
826 : {
827 14 : if (finish_p)
828 : {
829 : /* All we have is term code, and finish is requested. fini */
830 7 : retval = PDF_EEOF;
831 7 : oldone = PDF_TRUE;
832 : }
833 : else
834 : { /* finish_p not set. save the bytes for later */
835 21 : for (i = 0; i < q_idx; i++)
836 : {
837 14 : filter_state->spare_bytes[i] = quint[i];
838 : }
839 7 : filter_state->spare_count = q_idx;
840 7 : oldone = PDF_TRUE;
841 : }
842 : }
843 : }
844 :
845 140 : if (!oldone && PDF_OK == retval)
846 : {
847 64 : retval = pdf_stm_f_a85_flush_outbuff (out, filter_state);
848 :
849 64 : if (PDF_OK != retval)
850 : {
851 0 : oldone = PDF_TRUE;
852 : }
853 : }
854 :
855 : }
856 76 : return retval;
857 : }
858 :
859 : pdf_status_t
860 : pdf_stm_f_a85dec_dealloc_state (void *state)
861 30 : {
862 : pdf_stm_f_a85_t a85_state;
863 30 : a85_state = (pdf_stm_f_a85_t) state;
864 30 : pdf_dealloc (a85_state);
865 :
866 30 : return PDF_OK;
867 : }
868 :
869 : /* End of pdf_stm_f_a85.c */
|