Branch data Line data Source code
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-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-types.h>
29 : : #include <pdf-types-buffer.h>
30 : : #include <pdf-hash.h>
31 : : #include <pdf-stm-f-ahex.h>
32 : :
33 : : /* Define AHEX encoder */
34 : 10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_ahexenc_get,
35 : : stm_f_ahex_init,
36 : : stm_f_ahexenc_apply,
37 : : stm_f_ahex_deinit);
38 : :
39 : : /* Define AHEX decoder */
40 : 30 : PDF_STM_FILTER_DEFINE (pdf_stm_f_ahexdec_get,
41 : : stm_f_ahex_init,
42 : : stm_f_ahexdec_apply,
43 : : stm_f_ahex_deinit);
44 : :
45 : : #define PDF_STM_F_AHEX_LINE_WIDTH 60
46 : :
47 : : /* Internal state, same for encoder and decoder */
48 : : struct pdf_stm_f_ahex_s
49 : : {
50 : : pdf_i32_t last_nibble;
51 : : pdf_size_t written_bytes;
52 : : };
53 : :
54 : : static pdf_u32_t pdf_stm_f_ahex_white_p (pdf_u32_t hex);
55 : :
56 : : static pdf_u32_t pdf_stm_f_ahex_hex_p (pdf_u32_t hex);
57 : :
58 : : static pdf_u32_t pdf_stm_f_ahex_hex2int (pdf_u32_t hex);
59 : :
60 : : static pdf_uchar_t pdf_stm_f_ahex_int2hex (pdf_u32_t n);
61 : :
62 : : /* Common implementation */
63 : :
64 : : static pdf_bool_t
65 : 40 : stm_f_ahex_init (const pdf_hash_t *params,
66 : : void **state,
67 : : pdf_error_t **error)
68 : : {
69 : : struct pdf_stm_f_ahex_s *filter_state;
70 : :
71 : : /* This filter uses no parameters */
72 : : /* Allocate the internal state structure */
73 : 40 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_ahex_s));
74 [ - + ]: 40 : if (!filter_state)
75 : : {
76 : 0 : pdf_set_error (error,
77 : : PDF_EDOMAIN_BASE_STM,
78 : : PDF_ENOMEM,
79 : : "cannot create ASCII-Hex encoder/decoder internal state: "
80 : : "couldn't allocate %lu bytes",
81 : : (unsigned long)sizeof (struct pdf_stm_f_ahex_s));
82 : 0 : return PDF_FALSE;
83 : : }
84 : :
85 : : /* Initialize fields */
86 : 40 : filter_state->last_nibble = -1;
87 : 40 : filter_state->written_bytes = 0;
88 : :
89 : 40 : *state = (void *)filter_state;
90 : :
91 : 40 : return PDF_TRUE;
92 : : }
93 : :
94 : : static void
95 : 40 : stm_f_ahex_deinit (void *state)
96 : : {
97 : 40 : pdf_dealloc (state);
98 : 40 : }
99 : :
100 : : /* Encoder implementation */
101 : :
102 : : static enum pdf_stm_filter_apply_status_e
103 : 30 : stm_f_ahexenc_apply (void *state,
104 : : pdf_buffer_t *in,
105 : : pdf_buffer_t *out,
106 : : pdf_bool_t finish,
107 : : pdf_error_t **error)
108 : : {
109 : : struct pdf_stm_f_ahex_s *filter_state;
110 : : pdf_uchar_t first_nibble;
111 : : pdf_uchar_t second_nibble;
112 : : pdf_uchar_t in_char;
113 : :
114 [ + + ]: 30 : if (finish)
115 : : {
116 [ - + ]: 10 : if (pdf_buffer_full_p (out))
117 : 0 : return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
118 : 10 : out->data[out->wp++] = '>';
119 : 10 : return PDF_STM_FILTER_APPLY_STATUS_EOF;
120 : : }
121 : :
122 : 20 : filter_state = (struct pdf_stm_f_ahex_s *) state;
123 : :
124 [ + - ]: 50 : while (!pdf_buffer_full_p (out))
125 : : {
126 [ + + ][ - + ]: 50 : if ((filter_state->written_bytes != 0) &&
127 : 30 : (filter_state->written_bytes % PDF_STM_F_AHEX_LINE_WIDTH) == 0)
128 : : {
129 : : /* Write down a newline character */
130 : 0 : out->data[out->wp] = '\n';
131 : 0 : out->wp++;
132 : 0 : filter_state->written_bytes = 0;
133 : 0 : continue;
134 : : }
135 : :
136 : : /* Write down any pending nibble, if needed, without consuming
137 : : any input byte */
138 [ - + ]: 50 : if (filter_state->last_nibble != -1)
139 : : {
140 : 0 : out->data[out->wp] = filter_state->last_nibble;
141 : 0 : out->wp++;
142 : 0 : filter_state->written_bytes++;
143 : 0 : filter_state->last_nibble = -1;
144 : 0 : continue;
145 : : }
146 : :
147 : : /* Try to consume an input byte */
148 [ + + ]: 50 : if (!pdf_buffer_eob_p (in))
149 : : {
150 : : /* For each byte in the input we should generate two bytes in the
151 : : output. */
152 : 30 : in_char = in->data[in->rp];
153 : :
154 : : /* Determine the hex digits to write for this input character */
155 [ - + ]: 30 : if (filter_state->last_nibble != -1)
156 : : {
157 : 0 : first_nibble = (pdf_uchar_t) filter_state->last_nibble;
158 : 0 : second_nibble = pdf_stm_f_ahex_int2hex (in_char >> 4);
159 : : }
160 : : else
161 : : {
162 : 60 : first_nibble = pdf_stm_f_ahex_int2hex (in_char >> 4);
163 : 30 : second_nibble = pdf_stm_f_ahex_int2hex (in_char);
164 : : }
165 : 30 : in->rp++;
166 : :
167 : : /* Write the hex digits into the output buffer, if
168 : : possible */
169 : :
170 : : /* First nibble */
171 : 30 : out->data[out->wp] = first_nibble;
172 : 30 : out->wp++;
173 : 30 : filter_state->written_bytes++;
174 : :
175 : : /* Maybe write the second nibble */
176 [ - + ]: 30 : if (pdf_buffer_full_p (out))
177 : : {
178 : 0 : filter_state->last_nibble = second_nibble;
179 : : }
180 : : else
181 : : {
182 : 30 : out->data[out->wp] = second_nibble;
183 : 30 : out->wp++;
184 : 30 : filter_state->written_bytes++;
185 : : }
186 : : }
187 : : else
188 : : {
189 : : /* We need more input */
190 : : break;
191 : : }
192 : : }
193 : :
194 [ - + ]: 30 : return (pdf_buffer_full_p (out) ?
195 : : PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT :
196 : : PDF_STM_FILTER_APPLY_STATUS_NO_INPUT);
197 : : }
198 : :
199 : : static enum pdf_stm_filter_apply_status_e
200 : 60 : stm_f_ahexdec_apply (void *state,
201 : : pdf_buffer_t *in,
202 : : pdf_buffer_t *out,
203 : : pdf_bool_t finish,
204 : : pdf_error_t **error)
205 : : {
206 : : struct pdf_stm_f_ahex_s *filter_state;
207 : :
208 : 60 : filter_state = (struct pdf_stm_f_ahex_s *) state;
209 : :
210 [ + - ]: 270 : while (!pdf_buffer_full_p (out))
211 : : {
212 [ + + ]: 270 : if (pdf_buffer_eob_p (in))
213 : : {
214 : : /* Need more input */
215 : : break;
216 : : }
217 : :
218 : : /* Skip white characters */
219 [ + + ]: 240 : if (pdf_stm_f_ahex_white_p ((pdf_u32_t) in->data[in->rp]))
220 : : {
221 : 40 : in->rp++;
222 : 40 : continue;
223 : : }
224 : :
225 : : /* Detect the end of the hex data */
226 [ + + ]: 200 : if (in->data[in->rp] == '>')
227 : : {
228 [ + + ]: 30 : if (filter_state->last_nibble == -1)
229 : : {
230 : : /* We are done :'D */
231 : 20 : in->rp++;
232 : : }
233 : : else
234 : : {
235 : : /* Found an even number of hex digits. We assume that
236 : : the second nibble is 0, so generate a byte of data
237 : : and finish */
238 : 30 : out->data[out->wp] =
239 : 10 : pdf_stm_f_ahex_hex2int (filter_state->last_nibble) << 4;
240 : 10 : out->wp++;
241 : 10 : filter_state->last_nibble = -1;
242 : : }
243 : :
244 : 30 : return PDF_STM_FILTER_APPLY_STATUS_EOF;
245 : : }
246 : :
247 : : /* Detect an invalid character */
248 [ - + ]: 170 : if (!pdf_stm_f_ahex_hex_p ((pdf_u32_t) in->data[in->rp]))
249 : : {
250 : 0 : pdf_set_error (error,
251 : : PDF_EDOMAIN_BASE_STM,
252 : : PDF_ERROR,
253 : : "Invalid character found in ASCII-Hex decoder: %u",
254 : 0 : (pdf_u32_t) in->data[in->rp]);
255 : 0 : return PDF_STM_FILTER_APPLY_STATUS_ERROR;
256 : : }
257 : :
258 : : /* Process this character. This is the first or the second part
259 : : of a mibble. */
260 [ + + ]: 170 : if (filter_state->last_nibble == -1)
261 : : {
262 : : pdf_u32_t first_nibble;
263 : :
264 : : /* Get the first nibble */
265 : 90 : first_nibble = (pdf_u32_t) in->data[in->rp];
266 : 90 : in->rp++;
267 : :
268 : 90 : filter_state->last_nibble = first_nibble;
269 : : }
270 : : else
271 : : {
272 : : pdf_u32_t first_nibble;
273 : : pdf_u32_t second_nibble;
274 : :
275 : : /* Get the second nibble */
276 : 80 : second_nibble = (pdf_u32_t) in->data[in->rp];
277 : 80 : in->rp++;
278 : :
279 : : /* Generate one byte of data */
280 : 80 : first_nibble = filter_state->last_nibble;
281 : 240 : out->data[out->wp] = ((pdf_stm_f_ahex_hex2int (first_nibble) << 4)
282 : : + pdf_stm_f_ahex_hex2int (second_nibble));
283 : 80 : out->wp++;
284 : :
285 : 80 : filter_state->last_nibble = -1;
286 : : }
287 : : }
288 : :
289 [ + - ]: 60 : return (pdf_buffer_eob_p (in) ?
290 : : PDF_STM_FILTER_APPLY_STATUS_NO_INPUT :
291 : : PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT);
292 : : }
293 : :
294 : : /* Helper functions */
295 : :
296 : : static pdf_u32_t
297 : : pdf_stm_f_ahex_white_p (pdf_u32_t hex)
298 : : {
299 [ + - ][ + + ]: 240 : return ((hex == '\0') /* Null */
[ + + ]
300 : 240 : || (hex == '\t') /* Tab */
301 : 480 : || (hex == '\n') /* Line feed */
302 : 240 : || (hex == '\f') /* Form feed */
303 : 220 : || (hex == '\r') /* Carriage return */
304 : 220 : || (hex == 32)); /* Space character */
305 : : }
306 : :
307 : : static pdf_u32_t
308 : : pdf_stm_f_ahex_hex_p (pdf_u32_t hex)
309 : : {
310 [ + - ][ + - ]: 170 : return (((hex >= 'a') && (hex <= 'f')) ||
311 : 170 : ((hex >= 'A') && (hex <= 'F')) ||
312 : 170 : ((hex >= '0') && (hex <= '9')));
313 : : }
314 : :
315 : : static const pdf_uchar_t to_hex[16] = "0123456789ABCDEF";
316 : :
317 : : static pdf_uchar_t
318 : : pdf_stm_f_ahex_int2hex (pdf_u32_t hex)
319 : : {
320 : 60 : return to_hex[hex & 0x0f];
321 : : }
322 : :
323 : : static pdf_u32_t
324 : : pdf_stm_f_ahex_hex2int (pdf_u32_t hex)
325 : : {
326 [ - + ][ - + ]: 170 : if ((hex >= 'a') && (hex <= 'f'))
[ - + ]
327 : 0 : return (hex - 'a') + 0xA;
328 : :
329 [ - + ][ - + ]: 170 : if ((hex >= 'A') && (hex <= 'F'))
[ - + ]
330 : 0 : return (hex - 'A') + 0xA;
331 : :
332 [ + - ][ + - ]: 170 : if ((hex >= '0') && (hex <= '9'))
[ + - ]
333 : 170 : return (hex - '0');
334 : :
335 : 0 : return -1;
336 : : }
337 : :
338 : : /* End of pdf_stm_f_ahex.c */
|