1 : /* -*- mode: C -*-
2 : *
3 : * File: pdf-stm-f-ahex.c
4 : * Date: Fri Jul 13 17:08:41 2007
5 : *
6 : * GNU PDF Library - ASCII Hex decoder filter
7 : *
8 : */
9 :
10 : /* Copyright (C) 2007, 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-f-ahex.h>
29 :
30 : static pdf_u32_t pdf_stm_f_ahex_white_p (pdf_u32_t hex);
31 : static pdf_u32_t pdf_stm_f_ahex_hex_p (pdf_u32_t hex);
32 : static pdf_u32_t pdf_stm_f_ahex_hex2int (pdf_u32_t hex);
33 : static pdf_char_t pdf_stm_f_ahex_int2hex (pdf_u32_t n);
34 :
35 : pdf_status_t
36 : pdf_stm_f_ahexenc_init (pdf_hash_t params,
37 : void **state)
38 2 : {
39 : pdf_stm_f_ahexenc_t filter_state;
40 :
41 : /* This filter uses no parameters */
42 : /* Allocate the internal state structure */
43 2 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_ahexenc_s));
44 2 : if (filter_state == NULL)
45 : {
46 0 : return PDF_ERROR;
47 : }
48 :
49 : /* Initialize fields */
50 2 : filter_state->last_nibble = -1;
51 2 : filter_state->written_bytes = 0;
52 :
53 2 : *state = (void *) filter_state;
54 :
55 2 : return PDF_OK;
56 : }
57 :
58 : #define PDF_STM_F_AHEX_LINE_WIDTH 60
59 :
60 : pdf_status_t
61 : pdf_stm_f_ahexenc_apply (pdf_hash_t params,
62 : void *state,
63 : pdf_buffer_t in,
64 : pdf_buffer_t out,
65 : pdf_bool_t finish_p)
66 6 : {
67 : pdf_stm_f_ahexenc_t filter_state;
68 : pdf_char_t first_nibble;
69 : pdf_char_t second_nibble;
70 : pdf_char_t in_char;
71 : pdf_status_t ret;
72 :
73 6 : if (finish_p)
74 : {
75 : /* Assume that there is room in the output buffer to hold the
76 : EOD marker */
77 2 : out->data[out->wp++] = '>';
78 2 : return PDF_EEOF;
79 : }
80 :
81 4 : filter_state = (pdf_stm_f_ahexenc_t) state;
82 :
83 4 : ret = PDF_OK;
84 57 : while (!pdf_buffer_full_p (out))
85 : {
86 53 : if ((filter_state->written_bytes != 0) &&
87 : (filter_state->written_bytes % PDF_STM_F_AHEX_LINE_WIDTH) == 0)
88 : {
89 : /* Write down a newline character */
90 1 : out->data[out->wp] = '\n';
91 1 : out->wp++;
92 1 : filter_state->written_bytes = 0;
93 1 : continue;
94 : }
95 :
96 : /* Write down any pending nibble, if needed, without consuming
97 : any input byte */
98 52 : if (filter_state->last_nibble != -1)
99 : {
100 0 : out->data[out->wp] = filter_state->last_nibble;
101 0 : out->wp++;
102 0 : filter_state->written_bytes++;
103 0 : filter_state->last_nibble = -1;
104 0 : continue;
105 : }
106 :
107 : /* Try to consume an input byte */
108 52 : if (!pdf_buffer_eob_p (in))
109 : {
110 : /* For each byte in the input we should generate two bytes in the
111 : output. */
112 48 : in_char = in->data[in->rp];
113 :
114 : /* Determine the hex digits to write for this input character */
115 48 : if (filter_state->last_nibble != -1)
116 : {
117 0 : first_nibble = (pdf_char_t) filter_state->last_nibble;
118 0 : second_nibble = pdf_stm_f_ahex_int2hex (in_char >> 4);
119 : }
120 : else
121 : {
122 96 : first_nibble = pdf_stm_f_ahex_int2hex (in_char >> 4);
123 96 : second_nibble = pdf_stm_f_ahex_int2hex (in_char);
124 : }
125 48 : in->rp++;
126 :
127 : /* Write the hex digits into the output buffer, if
128 : possible */
129 :
130 : /* First nibble */
131 48 : out->data[out->wp] = first_nibble;
132 48 : out->wp++;
133 48 : filter_state->written_bytes++;
134 :
135 : /* Maybe write the second nibble */
136 48 : if (pdf_buffer_full_p (out))
137 : {
138 0 : filter_state->last_nibble = second_nibble;
139 : }
140 : else
141 : {
142 48 : out->data[out->wp] = second_nibble;
143 48 : out->wp++;
144 48 : filter_state->written_bytes++;
145 : }
146 : }
147 : else
148 : {
149 : /* We need more input */
150 4 : break;
151 : }
152 : }
153 :
154 4 : if (pdf_buffer_full_p (out))
155 : {
156 0 : ret = PDF_ENOUTPUT;
157 : }
158 : else
159 : {
160 4 : ret = PDF_ENINPUT;
161 : }
162 :
163 4 : return ret;
164 : }
165 :
166 : pdf_status_t
167 : pdf_stm_f_ahexenc_dealloc_state (void *state)
168 2 : {
169 : pdf_stm_f_ahexenc_t ahexenc_state;
170 :
171 2 : ahexenc_state = (pdf_stm_f_ahexenc_t) state;
172 2 : pdf_dealloc (ahexenc_state);
173 :
174 2 : return PDF_OK;
175 : }
176 :
177 : pdf_status_t
178 : pdf_stm_f_ahexdec_init (pdf_hash_t params,
179 : void **state)
180 3 : {
181 : pdf_stm_f_ahexdec_t ahexdec_state;
182 : pdf_status_t ret;
183 :
184 : /* This filter uses no parameters */
185 : /* Allocate the internal state structure */
186 3 : ahexdec_state = pdf_alloc (sizeof(struct pdf_stm_f_ahexdec_s));
187 3 : if (ahexdec_state != NULL)
188 : {
189 3 : ahexdec_state->last_nibble = -1;
190 3 : ahexdec_state->written_bytes = 0;
191 :
192 3 : *state = ahexdec_state;
193 3 : ret = PDF_OK;
194 : }
195 : else
196 : {
197 0 : ret = PDF_ERROR;
198 : }
199 :
200 3 : return ret;
201 : }
202 :
203 : pdf_status_t
204 : pdf_stm_f_ahexdec_apply (pdf_hash_t params,
205 : void *state,
206 : pdf_buffer_t in,
207 : pdf_buffer_t out,
208 : pdf_bool_t finish_p)
209 6 : {
210 : pdf_status_t ret;
211 : pdf_stm_f_ahexdec_t filter_state;
212 : pdf_u32_t first_nibble;
213 : pdf_u32_t second_nibble;
214 :
215 6 : ret = PDF_OK;
216 6 : first_nibble = -1;
217 6 : second_nibble = -1;
218 6 : filter_state = (pdf_stm_f_ahexdec_t) state;
219 :
220 33 : while (!pdf_buffer_full_p (out))
221 : {
222 27 : if (pdf_buffer_eob_p (in))
223 : {
224 : /* Need more input */
225 3 : break;
226 : }
227 : else
228 : {
229 : /* Skip white characters */
230 48 : if (pdf_stm_f_ahex_white_p ((pdf_u32_t) in->data[in->rp]))
231 : {
232 4 : in->rp++;
233 4 : continue;
234 : }
235 :
236 : /* Detect the end of the hex data */
237 20 : if (in->data[in->rp] == '>')
238 : {
239 3 : if (filter_state->last_nibble == -1)
240 : {
241 : /* We are done :'D */
242 2 : in->rp++;
243 2 : ret = PDF_EEOF;
244 2 : break;
245 : }
246 : else
247 : {
248 : /* Found an even number of hex digits. We assume that
249 : the second nibble is 0, so generate a byte of data
250 : and finish */
251 2 : out->data[out->wp] =
252 : pdf_stm_f_ahex_hex2int (filter_state->last_nibble) << 4;
253 1 : out->wp++;
254 1 : filter_state->last_nibble = -1;
255 1 : ret = PDF_EEOF;
256 1 : break;
257 : }
258 : }
259 :
260 : /* Detect an invalid character */
261 34 : if (!pdf_stm_f_ahex_hex_p ((pdf_u32_t) in->data[in->rp]))
262 : {
263 0 : ret = PDF_ERROR;
264 0 : break;
265 : }
266 :
267 : /* Process this character. This is the first or the second part
268 : of a mibble. */
269 17 : if (filter_state->last_nibble == -1)
270 : {
271 : /* Get the first nibble */
272 9 : first_nibble = (pdf_u32_t) in->data[in->rp];
273 9 : in->rp++;
274 :
275 9 : filter_state->last_nibble = first_nibble;
276 : }
277 : else
278 : {
279 : /* Get the second nibble */
280 8 : second_nibble = (pdf_u32_t) in->data[in->rp];
281 8 : in->rp++;
282 :
283 : /* Generate one byte of data */
284 8 : first_nibble = filter_state->last_nibble;
285 24 : out->data[out->wp] = (pdf_stm_f_ahex_hex2int (first_nibble) << 4)
286 : + pdf_stm_f_ahex_hex2int (second_nibble);
287 8 : out->wp++;
288 :
289 8 : filter_state->last_nibble = -1;
290 : }
291 : }
292 : }
293 :
294 6 : if (ret == PDF_OK)
295 : {
296 3 : if (pdf_buffer_eob_p (in))
297 : {
298 3 : ret = PDF_ENINPUT;
299 : }
300 : else
301 : {
302 0 : ret = PDF_ENOUTPUT;
303 : }
304 : }
305 :
306 6 : return ret;
307 : }
308 :
309 : pdf_status_t
310 : pdf_stm_f_ahexdec_dealloc_state (void *state)
311 3 : {
312 : pdf_stm_f_ahexenc_t ahexenc_state;
313 :
314 3 : ahexenc_state = (pdf_stm_f_ahexenc_t) state;
315 3 : pdf_dealloc (ahexenc_state);
316 :
317 3 : return PDF_OK;
318 : }
319 :
320 : /* Private functions */
321 :
322 : static pdf_u32_t
323 : pdf_stm_f_ahex_white_p (pdf_u32_t hex)
324 : {
325 24 : return ((hex == '\0') /* Null */
326 : || (hex == '\t') /* Tab */
327 : || (hex == '\n') /* Line feed */
328 : || (hex == '\f') /* Form feed */
329 : || (hex == '\r') /* Carriage return */
330 : || (hex == 32)); /* Space character */
331 : }
332 :
333 : static pdf_u32_t
334 : pdf_stm_f_ahex_hex_p (pdf_u32_t hex)
335 : {
336 17 : return (((hex >= 'a') && (hex <= 'f')) ||
337 : ((hex >= 'A') && (hex <= 'F')) ||
338 : ((hex >= '0') && (hex <= '9')));
339 : }
340 :
341 : static const pdf_char_t to_hex[16] = "0123456789ABCDEF";
342 :
343 : static pdf_char_t
344 : pdf_stm_f_ahex_int2hex (pdf_u32_t hex)
345 : {
346 96 : return to_hex[hex & 0x0f];
347 : }
348 :
349 : static pdf_u32_t
350 : pdf_stm_f_ahex_hex2int (pdf_u32_t hex)
351 : {
352 17 : if ((hex >= 'a') && (hex <= 'f'))
353 : {
354 0 : return (hex - 'a') + 0xA;
355 : }
356 17 : if ((hex >= 'A') && (hex <= 'F'))
357 : {
358 0 : return (hex - 'A') + 0xA;
359 : }
360 17 : if ((hex >= '0') && (hex <= '9'))
361 : {
362 17 : return (hex - '0');
363 : }
364 :
365 0 : return -1;
366 : }
367 :
368 : /* End of pdf_stm_f_ahex.c */
|