Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-stm-f-rl.c
4 : : * Date: Sun Jul 15 22:01:18 2007
5 : : *
6 : : * GNU PDF Library - RunLength encoder/decoder
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 <string.h>
29 : : #include <stdio.h>
30 : :
31 : : #include <pdf-alloc.h>
32 : : #include <pdf-stm-f-rl.h>
33 : : #include <pdf-types.h>
34 : : #include <pdf-types-buffer.h>
35 : : #include <pdf-hash.h>
36 : :
37 : : /* Define RL encoder */
38 : 10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_rlenc_get,
39 : : stm_f_rl_init,
40 : : stm_f_rlenc_apply,
41 : : stm_f_rl_deinit);
42 : :
43 : : /* Define RL decoder */
44 : 10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_rldec_get,
45 : : stm_f_rl_init,
46 : : stm_f_rldec_apply,
47 : : stm_f_rl_deinit);
48 : :
49 : : typedef enum
50 : : {
51 : : PDF_STM_F_RL_WRL,
52 : : PDF_STM_F_RL_NONE
53 : : } pdf_stm_f_rl_enc_e;
54 : :
55 : : /* Internal state */
56 : : struct pdf_stm_f_rl_s
57 : : {
58 : : pdf_uchar_t curchar;
59 : : pdf_uchar_t rlchar;
60 : : pdf_uchar_t dec_count;
61 : : pdf_i32_t rl;
62 : : pdf_bool_t run_p;
63 : : pdf_bool_t dec_p;
64 : : pdf_stm_f_rl_enc_e enc_p;
65 : : };
66 : :
67 : : static pdf_bool_t encode_rl_char (struct pdf_stm_f_rl_s *st,
68 : : pdf_buffer_t *out);
69 : :
70 : : static pdf_bool_t decode_rl_char (struct pdf_stm_f_rl_s *st,
71 : : pdf_buffer_t *out);
72 : :
73 : : static int copy_next_bytes (struct pdf_stm_f_rl_s *st,
74 : : pdf_buffer_t *in,
75 : : pdf_buffer_t *out);
76 : :
77 : : /* Common implementation */
78 : :
79 : : static pdf_bool_t
80 : 20 : stm_f_rl_init (const pdf_hash_t *params,
81 : : void **state,
82 : : pdf_error_t **error)
83 : : {
84 : : struct pdf_stm_f_rl_s *filter_state;
85 : :
86 : 20 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_rl_s));
87 [ - + ]: 20 : if (!filter_state)
88 : : {
89 : 0 : pdf_set_error (error,
90 : : PDF_EDOMAIN_BASE_STM,
91 : : PDF_ENOMEM,
92 : : "cannot create RunLength encoder/decoder internal state: "
93 : : "couldn't allocate %lu bytes",
94 : : (unsigned long)sizeof (struct pdf_stm_f_rl_s));
95 : 0 : return PDF_FALSE;
96 : : }
97 : :
98 : : /* Initialize fields */
99 : 20 : filter_state->curchar = 0;
100 : 20 : filter_state->rlchar = 0;
101 : 20 : filter_state->run_p = PDF_FALSE;
102 : 20 : filter_state->rl = -1;
103 : 20 : filter_state->dec_p = PDF_FALSE;;
104 : 20 : filter_state->dec_count = 0;
105 : 20 : filter_state->enc_p = PDF_STM_F_RL_NONE;
106 : :
107 : 20 : *state = (void *) filter_state;
108 : :
109 : 20 : return PDF_TRUE;
110 : : }
111 : :
112 : : static void
113 : 20 : stm_f_rl_deinit (void *state)
114 : : {
115 : 20 : pdf_dealloc (state);
116 : 20 : }
117 : :
118 : : /* Encoder implementation */
119 : :
120 : : static enum pdf_stm_filter_apply_status_e
121 : 30 : stm_f_rlenc_apply (void *state,
122 : : pdf_buffer_t *in,
123 : : pdf_buffer_t *out,
124 : : pdf_bool_t finish,
125 : : pdf_error_t **error)
126 : : {
127 : : struct pdf_stm_f_rl_s *filter_state;
128 : :
129 : 30 : filter_state = (struct pdf_stm_f_rl_s *) state;
130 : :
131 [ + + ]: 580 : while (!pdf_buffer_eob_p (in))
132 : : {
133 : 550 : filter_state->curchar = in->data[in->rp];
134 : :
135 : : /* we're not encoding any character yet */
136 [ + + ]: 550 : if (!filter_state->run_p)
137 : : {
138 : 100 : filter_state->rlchar = filter_state->curchar;
139 : 100 : filter_state->run_p = PDF_TRUE;
140 : 100 : filter_state->rl++;
141 : 100 : in->rp++;
142 : : }
143 : : /* we're encoding some character now */
144 [ + + ][ + - ]: 450 : else if (filter_state->curchar == filter_state->rlchar &&
145 : 360 : filter_state->rl < 127)
146 : : {
147 : 360 : filter_state->rl++;
148 : 360 : in->rp++;
149 : : }
150 : : /*
151 : : * the rl code is too long or the rl char is different,
152 : : * so we write what we encoded so far.
153 : : */
154 : : else
155 : : {
156 [ - + ]: 90 : if (!encode_rl_char (filter_state, out))
157 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
158 : :
159 : 90 : filter_state->rl = -1;
160 : 90 : filter_state->run_p = PDF_FALSE;
161 : : }
162 : : }
163 : :
164 : : /*
165 : : * we may have finished with some history, we save it if needed,
166 : : * then we add the EOD.
167 : : */
168 [ + + ]: 30 : if (finish)
169 : : {
170 [ + - ]: 10 : if (filter_state->run_p)
171 : : {
172 [ - + ]: 10 : if (!encode_rl_char (filter_state, out))
173 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
174 : :
175 : 10 : filter_state->rl = -1;
176 : 10 : filter_state->run_p = PDF_FALSE;
177 : : }
178 : :
179 : : /* Insert EOD marker */
180 [ - + ]: 10 : if (pdf_buffer_full_p (out))
181 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
182 : 10 : out->data[out->wp++] = 128;
183 : 10 : return PDF_STM_FILTER_APPLY_STATUS_EOF;
184 : : }
185 : :
186 : 30 : return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
187 : : }
188 : :
189 : : static enum pdf_stm_filter_apply_status_e
190 : 45 : stm_f_rldec_apply (void *state,
191 : : pdf_buffer_t *in,
192 : : pdf_buffer_t *out,
193 : : pdf_bool_t finish,
194 : : pdf_error_t **error)
195 : : {
196 : : struct pdf_stm_f_rl_s *filter_state;
197 : :
198 : 45 : filter_state = (struct pdf_stm_f_rl_s *) state;
199 : :
200 [ + + ]: 255 : while (!pdf_buffer_eob_p (in))
201 : : {
202 : 210 : filter_state->curchar = in->data[in->rp];
203 : :
204 : : /* we're not decoding any character yet */
205 [ + + ]: 210 : if (!filter_state->run_p)
206 : : {
207 : 110 : filter_state->rlchar = filter_state->curchar;
208 : 110 : filter_state->run_p = PDF_TRUE;
209 : 110 : in->rp++;
210 : : }
211 : : /* copy the following 1 to 128 bytes literally */
212 [ + + ]: 100 : else if (filter_state->rlchar < 128)
213 : : {
214 : : int copied;
215 : :
216 : 20 : copied = copy_next_bytes (filter_state, in, out);
217 [ - + ]: 20 : if (copied < 0)
218 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
219 [ - + ]: 20 : if (copied > 0)
220 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
221 : 20 : filter_state->run_p = PDF_FALSE;
222 : : }
223 : : /* copy the next char 257 - length (2 to 128) times */
224 [ + - ]: 80 : else if (filter_state->rlchar > 128)
225 : : {
226 [ - + ]: 80 : if (!decode_rl_char (filter_state, out))
227 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
228 : 80 : filter_state->run_p = PDF_FALSE;
229 : 80 : in->rp++;
230 : : }
231 : : /* EOD mark */
232 : : else
233 : : {
234 : 0 : filter_state->run_p = PDF_FALSE;
235 : 0 : return PDF_STM_FILTER_APPLY_STATUS_EOF;
236 : : }
237 : : }
238 : :
239 : 45 : return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
240 : : }
241 : :
242 : : /* Helper functions */
243 : :
244 : : static pdf_bool_t
245 : 100 : encode_rl_char (struct pdf_stm_f_rl_s *st,
246 : : pdf_buffer_t *out)
247 : : {
248 [ - + ]: 100 : if (pdf_buffer_full_p (out))
249 : 0 : return PDF_FALSE;
250 : :
251 [ + - - ]: 100 : switch (st->enc_p)
252 : : {
253 : : case PDF_STM_F_RL_NONE:
254 [ + + ]: 100 : out->data[out->wp++] = (st->rl == 0) ? 0 : 256 - st->rl;
255 : 100 : st->enc_p = PDF_STM_F_RL_WRL;
256 : : /* Continue to RL_WRL! */
257 : : case PDF_STM_F_RL_WRL:
258 : 100 : out->data[out->wp++] = st->rlchar;
259 : 100 : st->enc_p = PDF_STM_F_RL_NONE;
260 : : break;
261 : : }
262 : :
263 : 100 : return PDF_TRUE;
264 : : }
265 : :
266 : : static pdf_bool_t
267 : : decode_rl_char (struct pdf_stm_f_rl_s *st,
268 : : pdf_buffer_t *out)
269 : : {
270 [ + - ]: 80 : if (!st->dec_p)
271 : : {
272 : 80 : st->dec_count = 257 - st->rlchar;
273 : 80 : st->dec_p = PDF_TRUE;
274 : : }
275 : :
276 [ + + ]: 520 : while (st->dec_count > 0)
277 : : {
278 [ - + ]: 440 : if (pdf_buffer_full_p (out))
279 : 0 : return PDF_FALSE;
280 : :
281 : 440 : out->data[out->wp++] = st->curchar;
282 : 440 : st->dec_count--;
283 : : }
284 : :
285 : 80 : st->dec_p = PDF_FALSE;
286 : 80 : return PDF_TRUE;
287 : : }
288 : :
289 : : static int
290 : : copy_next_bytes (struct pdf_stm_f_rl_s *st,
291 : : pdf_buffer_t *in,
292 : : pdf_buffer_t *out)
293 : : {
294 [ + - ]: 20 : if (!st->dec_p)
295 : : {
296 [ - + ]: 20 : if (pdf_buffer_full_p (out))
297 : 0 : return -1;
298 : :
299 : 20 : st->dec_count = st->rlchar + 1;
300 : 20 : st->dec_p = PDF_TRUE;
301 : 20 : out->data[out->wp++] = st->curchar;
302 : 20 : in->rp++;
303 : 20 : st->dec_count--;
304 : : }
305 : :
306 [ - + ]: 20 : while (st->dec_count > 0)
307 : : {
308 [ # # ]: 0 : if (pdf_buffer_eob_p (in))
309 : 0 : return 1;
310 : :
311 [ # # ]: 0 : if (pdf_buffer_full_p (out))
312 : 0 : return -1;
313 : :
314 : 0 : out->data[out->wp] = in->data[in->rp];
315 : 0 : out->wp++;
316 : 0 : in->rp++;
317 : 0 : st->dec_count--;
318 : : }
319 : :
320 : 20 : st->dec_p = PDF_FALSE;
321 : 20 : return 0;
322 : : }
323 : :
324 : : /* End of pdf_stm_f_rl.c */
|