Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-token.c
4 : : * Date: Sat Jul 7 03:04:30 2007
5 : : *
6 : : * GNU PDF Library - PDF token objects
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 <math.h>
30 : :
31 : : #include <pdf-token.h>
32 : : #include <pdf-alloc.h>
33 : :
34 : : /* According to the PDF reference, a PDF name object is an atomic
35 : : symbol uniquely defined by a sequence of non-null characters. It has
36 : : no internal structure.
37 : :
38 : : In the practice, PDF uses name objects in order to store
39 : : information (such as font names). In that situation, it is
40 : : recommended to code such information in UTF-8. Due to this
41 : : stupidity we should store the entire byte sequence that conform the
42 : : name.
43 : :
44 : : A pdf_token_buffer_s structure is used to store a name's value. */
45 : :
46 : : /* A PDF string is a sequence of bytes, in the range of 0-255. In
47 : : particular it may contain NULL characters (code 0 in the ASCII
48 : : CCS).
49 : :
50 : : Corollary: NEVER NEVER NEVER EVER use a PDF string as an input
51 : : expecting null-terminated strings. You have been warned.
52 : :
53 : : A pdf_token_buffer_s structure is used to store a string's value. */
54 : :
55 : : /* pdf_token_buffer_s is an internal structure used for tokens with an
56 : : * associated byte array. 'data' may or may not be null-terminated,
57 : : * but size never includes the trailing null. */
58 : : struct pdf_token_buffer_s
59 : : {
60 : : pdf_char_t *data;
61 : : pdf_size_t size;
62 : : };
63 : :
64 : : /* A `pdf_token_s' structure stores a PDF object. The object may be of
65 : : any type (including NULL). */
66 : :
67 : : struct pdf_token_s
68 : : {
69 : : enum pdf_token_type_e type;
70 : :
71 : : union
72 : : {
73 : : struct pdf_token_buffer_s buffer;
74 : : pdf_i32_t integer;
75 : : pdf_real_t real;
76 : :
77 : : } value;
78 : : };
79 : :
80 : : /* Private functions */
81 : :
82 : : static pdf_token_t *
83 : 2750 : token_new (enum pdf_token_type_e type,
84 : : pdf_error_t **error)
85 : : {
86 : : pdf_token_t *token;
87 : :
88 : 2750 : token = (pdf_token_t *) pdf_alloc (sizeof (struct pdf_token_s));
89 [ - + ]: 2750 : if (!token)
90 : : {
91 : 0 : pdf_set_error (error,
92 : : PDF_EDOMAIN_BASE_TOKENISER,
93 : : PDF_ENOMEM,
94 : : "cannot create new token: "
95 : : "couldn't allocate '%lu' bytes",
96 : : (unsigned long)sizeof (struct pdf_token_s));
97 : 0 : return NULL;
98 : : }
99 : :
100 : 2750 : token->type = type;
101 : 2750 : return token;
102 : : }
103 : :
104 : : void
105 : 2022 : pdf_token_destroy (pdf_token_t *token)
106 : : {
107 [ - + ]: 2022 : PDF_ASSERT_POINTER_RETURN (token);
108 [ - + ]: 2022 : PDF_ASSERT_RETURN (token->type >= PDF_TOKEN_INTEGER &&
109 : : token->type <= PDF_TOKEN_PROC_END);
110 : :
111 [ + + ]: 2022 : switch (token->type)
112 : : {
113 : : case PDF_TOKEN_STRING: /* fall through */
114 : : case PDF_TOKEN_NAME: /* fall through */
115 : : case PDF_TOKEN_KEYWORD: /* fall through */
116 : : case PDF_TOKEN_COMMENT:
117 : : {
118 [ + - ]: 1387 : if (token->value.buffer.data)
119 : 1387 : pdf_dealloc (token->value.buffer.data);
120 : : break;
121 : : }
122 : : default:
123 : : {
124 : : /* NOP */
125 : : break;
126 : : }
127 : : }
128 : :
129 : 2022 : pdf_dealloc (token);
130 : : }
131 : :
132 : : static pdf_token_t *
133 : 2093 : token_buffer_new (enum pdf_token_type_e type,
134 : : const pdf_char_t *value,
135 : : pdf_size_t size,
136 : : pdf_bool_t nullterm,
137 : : pdf_error_t **error)
138 : : {
139 : : pdf_token_t *token;
140 : :
141 : 2093 : token = token_new (type, error);
142 [ - + ]: 2093 : if (!token)
143 : 0 : return NULL;
144 : :
145 : 2093 : token->value.buffer.data = pdf_alloc (size + 1);
146 [ - + ]: 2093 : if (!token->value.buffer.data)
147 : : {
148 : 0 : pdf_set_error (error,
149 : : PDF_EDOMAIN_BASE_TOKENISER,
150 : : PDF_ENOMEM,
151 : : "cannot create token buffer: "
152 : : "couldn't allocate '%lu' bytes",
153 : : (unsigned long)sizeof (struct pdf_token_s));
154 : 0 : pdf_token_destroy (token);
155 : 0 : return NULL;
156 : : }
157 : :
158 : 2093 : token->value.buffer.size = size;
159 : 2093 : memcpy (token->value.buffer.data, value, size);
160 : :
161 : : /* If the value isn't null terminated, append a non-null character
162 : : * to catch bugs. */
163 [ + + ]: 2093 : token->value.buffer.data[size] = nullterm ? '\0' : 'X';
164 : :
165 : 2093 : return token;
166 : : }
167 : :
168 : :
169 : : /* General functions */
170 : :
171 : : enum pdf_token_type_e
172 : 1278 : pdf_token_get_type (const pdf_token_t *token)
173 : : {
174 [ - + ]: 1278 : PDF_ASSERT_POINTER_RETURN_VAL (token, PDF_TOKEN_UNKNOWN);
175 [ - + ]: 1278 : PDF_ASSERT_RETURN_VAL ((token->type >= PDF_TOKEN_INTEGER &&
176 : : token->type <= PDF_TOKEN_PROC_END),
177 : : PDF_TOKEN_UNKNOWN);
178 : :
179 : 1278 : return token->type;
180 : : }
181 : :
182 : : pdf_bool_t
183 : 364 : pdf_token_equal_p (const pdf_token_t *token1,
184 : : const pdf_token_t *token2)
185 : : {
186 [ - + ]: 364 : PDF_ASSERT_POINTER_RETURN_VAL (token1, PDF_FALSE);
187 [ - + ]: 364 : PDF_ASSERT_POINTER_RETURN_VAL (token2, PDF_FALSE);
188 [ - + ]: 364 : PDF_ASSERT_RETURN_VAL ((token1->type >= PDF_TOKEN_INTEGER &&
189 : : token1->type <= PDF_TOKEN_PROC_END),
190 : : PDF_FALSE);
191 [ - + ]: 364 : PDF_ASSERT_RETURN_VAL ((token2->type >= PDF_TOKEN_INTEGER &&
192 : : token2->type <= PDF_TOKEN_PROC_END),
193 : : PDF_FALSE);
194 : :
195 [ - + ]: 364 : if (token1->type != token2->type)
196 : 0 : return PDF_FALSE;
197 : :
198 [ + + + + : 364 : switch (token1->type)
- ]
199 : : {
200 : : case PDF_TOKEN_DICT_START: /* fall through */
201 : : case PDF_TOKEN_DICT_END: /* fall through */
202 : : case PDF_TOKEN_ARRAY_START: /* fall through */
203 : : case PDF_TOKEN_ARRAY_END: /* fall through */
204 : : case PDF_TOKEN_PROC_START: /* fall through */
205 : : case PDF_TOKEN_PROC_END:
206 : 6 : return PDF_TRUE;
207 : :
208 : : case PDF_TOKEN_INTEGER:
209 : 3 : return (token1->value.integer == token2->value.integer ?
210 : : PDF_TRUE : PDF_FALSE);
211 : :
212 : : case PDF_TOKEN_REAL:
213 : 2 : return (token1->value.real == token2->value.real ?
214 : : PDF_TRUE : PDF_FALSE);
215 : :
216 : : case PDF_TOKEN_COMMENT: /* fall through */
217 : : case PDF_TOKEN_STRING: /* fall through */
218 : : case PDF_TOKEN_NAME: /* fall through */
219 : : case PDF_TOKEN_KEYWORD:
220 : : {
221 [ + - ][ + - ]: 353 : return ((token1->value.buffer.size == token2->value.buffer.size &&
222 : 353 : memcmp (token1->value.buffer.data,
223 : 353 : token2->value.buffer.data,
224 : 706 : token1->value.buffer.size) == 0) ?
225 : : PDF_TRUE : PDF_FALSE);
226 : : }
227 : :
228 : : default:
229 : : /* shouldn't happen */
230 : 0 : PDF_ASSERT_TRACE_NOT_REACHED ();
231 : 364 : return PDF_FALSE;
232 : : }
233 : : }
234 : :
235 : : pdf_token_t *
236 : 0 : pdf_token_dup (const pdf_token_t *token,
237 : : pdf_error_t **error)
238 : : {
239 [ # # ]: 0 : PDF_ASSERT_POINTER_RETURN_VAL (token, NULL);
240 [ # # ]: 0 : PDF_ASSERT_RETURN_VAL ((token->type >= PDF_TOKEN_INTEGER &&
241 : : token->type <= PDF_TOKEN_PROC_END),
242 : : NULL);
243 : :
244 [ # # # # # : 0 : switch (token->type)
# # # ]
245 : : {
246 : : case PDF_TOKEN_DICT_START: /* fall through */
247 : : case PDF_TOKEN_DICT_END: /* fall through */
248 : : case PDF_TOKEN_ARRAY_START: /* fall through */
249 : : case PDF_TOKEN_ARRAY_END: /* fall through */
250 : : case PDF_TOKEN_PROC_START: /* fall through */
251 : : case PDF_TOKEN_PROC_END:
252 : 0 : return pdf_token_valueless_new (token->type, error);
253 : :
254 : : case PDF_TOKEN_INTEGER:
255 : 0 : return pdf_token_integer_new (token->value.integer, error);
256 : :
257 : : case PDF_TOKEN_REAL:
258 : 0 : return pdf_token_real_new (token->value.real, error);
259 : :
260 : : case PDF_TOKEN_STRING:
261 : 0 : return pdf_token_string_new (token->value.buffer.data,
262 : : token->value.buffer.size,
263 : : error);
264 : : case PDF_TOKEN_NAME:
265 : 0 : return pdf_token_name_new (token->value.buffer.data,
266 : : token->value.buffer.size,
267 : : error);
268 : : case PDF_TOKEN_KEYWORD:
269 : 0 : return pdf_token_keyword_new (token->value.buffer.data,
270 : : token->value.buffer.size,
271 : : error);
272 : : case PDF_TOKEN_COMMENT:
273 : 0 : return pdf_token_comment_new (token->value.buffer.data,
274 : : token->value.buffer.size,
275 : : error);
276 : : default:
277 : : /* shouldn't happen */
278 : 0 : PDF_ASSERT_TRACE_NOT_REACHED ();
279 : 0 : return NULL;
280 : : }
281 : : }
282 : :
283 : : pdf_token_t *
284 : 451 : pdf_token_valueless_new (enum pdf_token_type_e type,
285 : : pdf_error_t **error)
286 : : {
287 [ - + ]: 451 : PDF_ASSERT_RETURN_VAL ((type >= PDF_TOKEN_INTEGER &&
288 : : type <= PDF_TOKEN_PROC_END),
289 : : NULL);
290 : :
291 [ + - ]: 451 : switch (type)
292 : : {
293 : : case PDF_TOKEN_DICT_START: /* fall through */
294 : : case PDF_TOKEN_DICT_END: /* fall through */
295 : : case PDF_TOKEN_ARRAY_START: /* fall through */
296 : : case PDF_TOKEN_ARRAY_END: /* fall through */
297 : : case PDF_TOKEN_PROC_START: /* fall through */
298 : : case PDF_TOKEN_PROC_END:
299 : 451 : return token_new (type, error);
300 : : default:
301 : 451 : return NULL;
302 : : }
303 : : }
304 : :
305 : : /** integers *****/
306 : :
307 : : pdf_token_t *
308 : 184 : pdf_token_integer_new (pdf_i32_t value,
309 : : pdf_error_t **error)
310 : : {
311 : : pdf_token_t *token;
312 : :
313 : 184 : token = token_new (PDF_TOKEN_INTEGER, error);
314 [ + - ]: 184 : if (token)
315 : 184 : token->value.integer = value;
316 : :
317 : 184 : return token;
318 : : }
319 : :
320 : : pdf_i32_t
321 : 172 : pdf_token_get_integer_value (const pdf_token_t *token)
322 : : {
323 [ - + ]: 172 : PDF_ASSERT_POINTER_RETURN_VAL (token, 0);
324 [ - + ]: 172 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_INTEGER, 0);
325 : :
326 : 172 : return token->value.integer;
327 : : }
328 : :
329 : : /** reals *****/
330 : :
331 : : pdf_token_t *
332 : 22 : pdf_token_real_new (pdf_real_t value,
333 : : pdf_error_t **error)
334 : : {
335 : : pdf_token_t *token;
336 : :
337 [ - + ]: 22 : if (isnan (value))
338 : : {
339 : 0 : pdf_set_error (error,
340 : : PDF_EDOMAIN_BASE_TOKENISER,
341 : : PDF_EBADDATA,
342 : : "cannot create real token from NaN value");
343 : 0 : return NULL;
344 : : }
345 : :
346 [ - + ]: 22 : if (isinf (value))
347 : : {
348 : 0 : pdf_set_error (error,
349 : : PDF_EDOMAIN_BASE_TOKENISER,
350 : : PDF_EBADDATA,
351 : : "cannot create real token from infinite value");
352 : 0 : return NULL;
353 : : }
354 : :
355 : 22 : token = token_new (PDF_TOKEN_REAL, error);
356 [ + - ]: 22 : if (token)
357 : 22 : token->value.real = value;
358 : :
359 : 22 : return token;
360 : : }
361 : :
362 : : pdf_real_t
363 : 14 : pdf_token_get_real_value (const pdf_token_t *token)
364 : : {
365 [ - + ]: 14 : PDF_ASSERT_POINTER_RETURN_VAL (token, 0.0);
366 [ - + ]: 14 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_REAL, 0.0);
367 : :
368 : 14 : return token->value.real;
369 : : }
370 : :
371 : : /** names *****/
372 : :
373 : : pdf_token_t *
374 : 1395 : pdf_token_name_new (const pdf_char_t *value,
375 : : pdf_size_t size,
376 : : pdf_error_t **error)
377 : : {
378 : : pdf_size_t i;
379 : :
380 [ - + ]: 1395 : PDF_ASSERT_POINTER_RETURN_VAL (value, NULL);
381 : :
382 [ + + ]: 2945 : for (i = 0; i < size; ++i)
383 : : {
384 : : /* names can't include NUL bytes */
385 [ - + ]: 1550 : if (value[i] == '\0')
386 : : {
387 : 0 : pdf_set_error (error,
388 : : PDF_EDOMAIN_BASE_TOKENISER,
389 : : PDF_EBADDATA,
390 : : "cannot create name token: "
391 : : "names cannot include NUL bytes");
392 : 0 : return NULL;
393 : : }
394 : : }
395 : :
396 : 1395 : return token_buffer_new (PDF_TOKEN_NAME,
397 : : value,
398 : : size,
399 : : PDF_TRUE,
400 : : error);
401 : : }
402 : :
403 : : pdf_size_t
404 : 11 : pdf_token_get_name_size (const pdf_token_t *token)
405 : : {
406 [ - + ]: 11 : PDF_ASSERT_POINTER_RETURN_VAL (token, 0);
407 [ - + ]: 11 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_NAME, 0);
408 : :
409 : 11 : return token->value.buffer.size;
410 : : }
411 : :
412 : : const pdf_char_t *
413 : 27 : pdf_token_get_name_data (const pdf_token_t *token)
414 : : {
415 [ - + ]: 27 : PDF_ASSERT_POINTER_RETURN_VAL (token, NULL);
416 [ - + ]: 27 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_NAME, NULL);
417 : :
418 : 27 : return token->value.buffer.data;
419 : : }
420 : :
421 : : /** strings *****/
422 : :
423 : : pdf_token_t *
424 : 53 : pdf_token_string_new (const pdf_char_t *value,
425 : : pdf_size_t size,
426 : : pdf_error_t **error)
427 : : {
428 [ - + ]: 53 : PDF_ASSERT_POINTER_RETURN_VAL (value, NULL);
429 : :
430 : 53 : return token_buffer_new (PDF_TOKEN_STRING,
431 : : value,
432 : : size,
433 : : PDF_FALSE,
434 : : error);
435 : : }
436 : :
437 : : pdf_size_t
438 : 17 : pdf_token_get_string_size (const pdf_token_t *token)
439 : : {
440 [ - + ]: 17 : PDF_ASSERT_POINTER_RETURN_VAL (token, 0);
441 [ - + ]: 17 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_STRING, 0);
442 : :
443 : 17 : return token->value.buffer.size;
444 : : }
445 : :
446 : : const pdf_char_t *
447 : 16 : pdf_token_get_string_data (const pdf_token_t *token)
448 : : {
449 [ - + ]: 16 : PDF_ASSERT_POINTER_RETURN_VAL (token, NULL);
450 [ - + ]: 16 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_STRING, NULL);
451 : :
452 : 16 : return token->value.buffer.data;
453 : : }
454 : :
455 : : /** comments *****/
456 : :
457 : : pdf_token_t *
458 : 0 : pdf_token_comment_new (const pdf_char_t *value,
459 : : pdf_size_t size,
460 : : pdf_error_t **error)
461 : : {
462 : : pdf_size_t i;
463 : :
464 [ # # ]: 0 : PDF_ASSERT_POINTER_RETURN_VAL (value, NULL);
465 : :
466 [ # # ]: 0 : for (i = 0; i < size; ++i)
467 : : {
468 : : /* comments can't span multiple lines */
469 [ # # ]: 0 : if (pdf_is_eol_char (value[i]))
470 : : {
471 : 0 : pdf_set_error (error,
472 : : PDF_EDOMAIN_BASE_TOKENISER,
473 : : PDF_EBADDATA,
474 : : "cannot create comment token: "
475 : : "comments cannot span multiple lines");
476 : 0 : return NULL;
477 : : }
478 : : }
479 : :
480 : 0 : return token_buffer_new (PDF_TOKEN_COMMENT,
481 : : value,
482 : : size,
483 : : PDF_FALSE,
484 : : error);
485 : : }
486 : :
487 : : pdf_size_t
488 : 0 : pdf_token_get_comment_size (const pdf_token_t *token)
489 : : {
490 [ # # ]: 0 : PDF_ASSERT_POINTER_RETURN_VAL (token, 0);
491 [ # # ]: 0 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_COMMENT, 0);
492 : :
493 : 0 : return token->value.buffer.size;
494 : : }
495 : :
496 : : const pdf_char_t *
497 : 0 : pdf_token_get_comment_data (const pdf_token_t *token)
498 : : {
499 [ # # ]: 0 : PDF_ASSERT_POINTER_RETURN_VAL (token, NULL);
500 [ # # ]: 0 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_COMMENT, NULL);
501 : :
502 : 0 : return token->value.buffer.data;
503 : : }
504 : :
505 : : /** keywords *****/
506 : :
507 : : pdf_token_t *
508 : 645 : pdf_token_keyword_new (const pdf_char_t *value,
509 : : pdf_size_t size,
510 : : pdf_error_t **error)
511 : : {
512 : : pdf_size_t i;
513 : :
514 [ - + ]: 645 : PDF_ASSERT_POINTER_RETURN_VAL (value, NULL);
515 : :
516 [ + + ]: 2878 : for (i = 0; i < size; ++i)
517 : : {
518 : : /* keywords can only include regular characters */
519 [ + - ][ + - ]: 2233 : if (!pdf_is_regular_char (value[i]))
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ - + ]
520 : : {
521 : 0 : pdf_set_error (error,
522 : : PDF_EDOMAIN_BASE_TOKENISER,
523 : : PDF_EBADDATA,
524 : : "cannot create keyword token: "
525 : : "keywords can only include regular characters");
526 : 0 : return NULL;
527 : : }
528 : : }
529 : :
530 : 645 : return token_buffer_new (PDF_TOKEN_KEYWORD,
531 : : value,
532 : : size,
533 : : PDF_TRUE,
534 : : error);
535 : : }
536 : :
537 : : pdf_size_t
538 : 637 : pdf_token_get_keyword_size (const pdf_token_t *token)
539 : : {
540 [ - + ]: 637 : PDF_ASSERT_POINTER_RETURN_VAL (token, 0);
541 [ - + ]: 637 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_KEYWORD, 0);
542 : :
543 : 637 : return token->value.buffer.size;
544 : : }
545 : :
546 : : const pdf_char_t *
547 : 637 : pdf_token_get_keyword_data (const pdf_token_t *token)
548 : : {
549 [ - + ]: 637 : PDF_ASSERT_POINTER_RETURN_VAL (token, NULL);
550 [ - + ]: 637 : PDF_ASSERT_RETURN_VAL (token->type == PDF_TOKEN_KEYWORD, NULL);
551 : :
552 : 637 : return token->value.buffer.data;
553 : : }
554 : :
555 : : /* End of pdf-token.c */
|