Sun, 21 Dec 2003 23:52:11 +0000
fix svn:keywords property
1 /*
2 * tumble: build a PDF file from image files
3 *
4 * PDF routines
5 * $Id: pdf_prim.c,v 1.13 2003/03/19 23:44:53 eric Exp $
6 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. Note that permission is
11 * not granted to redistribute this program under the terms of any
12 * other version of the General Public License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
22 */
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "bitblt.h"
33 #include "pdf.h"
34 #include "pdf_util.h"
35 #include "pdf_prim.h"
36 #include "pdf_private.h"
39 struct pdf_array_elem
40 {
41 struct pdf_array_elem *next;
42 struct pdf_obj *val;
43 };
46 struct pdf_array
47 {
48 struct pdf_array_elem *first;
49 struct pdf_array_elem *last;
50 };
53 struct pdf_dict_entry
54 {
55 struct pdf_dict_entry *next;
56 char *key;
57 struct pdf_obj *val;
58 };
61 struct pdf_dict
62 {
63 struct pdf_dict_entry *first;
64 };
67 struct pdf_stream
68 {
69 struct pdf_obj *stream_dict;
70 struct pdf_obj *length;
71 pdf_stream_write_callback callback;
72 void *app_data; /* arg to pass to callback */
73 struct pdf_obj *filters; /* name or array of names */
74 struct pdf_obj *decode_parms;
75 };
78 struct pdf_obj
79 {
80 /* these fields only apply to indirectly referenced objects */
81 struct pdf_obj *prev;
82 struct pdf_obj *next;
83 unsigned long obj_num;
84 unsigned long obj_gen;
85 long int file_offset;
87 /* these fields apply to all objects */
88 unsigned long ref_count;
89 pdf_obj_type type;
90 union {
91 bool boolean;
92 char *name;
93 char *string;
94 long integer;
95 double real;
96 struct pdf_obj *ind_ref;
97 struct pdf_dict dict;
98 struct pdf_array array;
99 struct pdf_stream stream;
100 } val;
101 };
104 struct pdf_obj *ref (struct pdf_obj *obj)
105 {
106 obj->ref_count++;
107 return (obj);
108 }
111 void unref (struct pdf_obj *obj)
112 {
113 if ((--obj->ref_count) == 0)
114 {
115 /* $$$ free the object */
116 }
117 }
120 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
121 {
122 pdf_assert (ind_obj->type == PT_IND_REF);
123 return (ind_obj->val.ind_ref);
124 }
127 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
128 {
129 struct pdf_dict_entry *entry;
131 if (dict_obj->type == PT_IND_REF)
132 dict_obj = pdf_deref_ind_obj (dict_obj);
134 pdf_assert (dict_obj->type == PT_DICTIONARY);
136 /* replacing existing entry? */
137 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
138 if (strcmp (entry->key, key) == 0)
139 {
140 unref (entry->val);
141 entry->val = ref (val);
142 return;
143 }
145 /* new entry */
146 entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
148 entry->next = dict_obj->val.dict.first;
149 dict_obj->val.dict.first = entry;
151 entry->key = pdf_strdup (key);
152 entry->val = ref (val);
153 }
156 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
157 {
158 struct pdf_dict_entry *entry;
160 if (dict_obj->type == PT_IND_REF)
161 dict_obj = pdf_deref_ind_obj (dict_obj);
163 pdf_assert (dict_obj->type == PT_DICTIONARY);
165 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
166 if (strcmp (entry->key, key) == 0)
167 return (entry->val);
169 return (NULL);
170 }
173 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
174 {
175 struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
177 if (array_obj->type == PT_IND_REF)
178 array_obj = pdf_deref_ind_obj (array_obj);
180 pdf_assert (array_obj->type == PT_ARRAY);
182 elem->val = ref (val);
184 if (! array_obj->val.array.first)
185 array_obj->val.array.first = elem;
186 else
187 array_obj->val.array.last->next = elem;
189 array_obj->val.array.last = elem;
190 }
193 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
194 {
195 struct pdf_array_elem *elem;
197 if (array_obj->type == PT_IND_REF)
198 array_obj = pdf_deref_ind_obj (array_obj);
200 pdf_assert (array_obj->type == PT_ARRAY);
202 for (elem = array_obj->val.array.first; elem; elem = elem->next)
203 if (pdf_compare_obj (val, elem->val) == 0)
204 return;
206 elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
208 elem->val = ref (val);
210 if (! array_obj->val.array.first)
211 array_obj->val.array.first = elem;
212 else
213 array_obj->val.array.last->next = elem;
215 array_obj->val.array.last = elem;
216 }
219 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
220 {
221 struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
222 obj->type = type;
223 return (obj);
224 }
227 struct pdf_obj *pdf_new_bool (bool val)
228 {
229 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
230 obj->val.boolean = val;
231 return (obj);
232 }
235 struct pdf_obj *pdf_new_name (char *name)
236 {
237 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
238 obj->val.name = pdf_strdup (name);
239 return (obj);
240 }
243 struct pdf_obj *pdf_new_string (char *str)
244 {
245 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
246 obj->val.string = pdf_strdup (str);
247 return (obj);
248 }
251 struct pdf_obj *pdf_new_integer (long val)
252 {
253 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
254 obj->val.integer = val;
255 return (obj);
256 }
259 struct pdf_obj *pdf_new_real (double val)
260 {
261 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
262 obj->val.real = val;
263 return (obj);
264 }
267 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
268 struct pdf_obj *stream_dict,
269 pdf_stream_write_callback callback,
270 void *app_data)
271 {
272 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
274 obj->val.stream.stream_dict = stream_dict;
275 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
276 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
278 obj->val.stream.callback = callback;
279 obj->val.stream.app_data = app_data;
280 return (obj);
281 }
284 /* $$$ currently limited to one filter per stream */
285 void pdf_stream_add_filter (struct pdf_obj *stream,
286 char *filter_name,
287 struct pdf_obj *decode_parms)
288 {
289 if (stream->type == PT_IND_REF)
290 stream = pdf_deref_ind_obj (stream);
292 pdf_assert (stream->type == PT_STREAM);
294 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
295 if (decode_parms)
296 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
297 }
300 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
301 {
302 struct pdf_obj *ind_obj;
304 pdf_assert (obj->type != PT_IND_REF);
306 ind_obj = pdf_new_obj (PT_IND_REF);
308 ind_obj->type = PT_IND_REF;
309 ind_obj->val.ind_ref = obj;
311 /* is there already an indirect reference to this object? */
312 if (! obj->obj_num)
313 {
314 /* no, assign object number/generation and add to linked list */
315 if (! pdf_file->first_ind_obj)
316 {
317 obj->obj_num = 1;
318 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
319 }
320 else
321 {
322 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
323 pdf_file->last_ind_obj->next = obj;
324 obj->prev = pdf_file->last_ind_obj;
325 pdf_file->last_ind_obj = obj;
326 }
327 }
329 return (ind_obj);
330 }
333 long pdf_get_integer (struct pdf_obj *obj)
334 {
335 if (obj->type == PT_IND_REF)
336 obj = pdf_deref_ind_obj (obj);
338 pdf_assert (obj->type == PT_INTEGER);
340 return (obj->val.integer);
341 }
343 void pdf_set_integer (struct pdf_obj *obj, long val)
344 {
345 if (obj->type == PT_IND_REF)
346 obj = pdf_deref_ind_obj (obj);
348 pdf_assert (obj->type == PT_INTEGER);
350 obj->val.integer = val;
351 }
354 double pdf_get_real (struct pdf_obj *obj)
355 {
356 if (obj->type == PT_IND_REF)
357 obj = pdf_deref_ind_obj (obj);
359 pdf_assert (obj->type == PT_REAL);
361 return (obj->val.real);
362 }
364 void pdf_set_real (struct pdf_obj *obj, double val)
365 {
366 if (obj->type == PT_IND_REF)
367 obj = pdf_deref_ind_obj (obj);
369 pdf_assert (obj->type == PT_REAL);
371 obj->val.real = val;
372 }
375 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
376 {
377 if (o1->type == PT_IND_REF)
378 o1 = pdf_deref_ind_obj (o1);
380 if (o2->type == PT_IND_REF)
381 o2 = pdf_deref_ind_obj (o2);
383 pdf_assert (o1->type == o2->type);
385 switch (o1->type)
386 {
387 case PT_INTEGER:
388 if (o1->val.integer < o2->val.integer)
389 return (-1);
390 if (o1->val.integer > o2->val.integer)
391 return (1);
392 return (0);
393 case PT_REAL:
394 if (o1->val.real < o2->val.real)
395 return (-1);
396 if (o1->val.real > o2->val.real)
397 return (1);
398 return (0);
399 case PT_STRING:
400 return (strcmp (o1->val.string, o2->val.string));
401 case PT_NAME:
402 return (strcmp (o1->val.name, o2->val.name));
403 default:
404 pdf_fatal ("invalid object type for comparison\n");
405 }
406 }
409 static int name_char_needs_quoting (char c)
410 {
411 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
412 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
413 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
414 (c == '%'));
415 }
418 void pdf_write_name (pdf_file_handle pdf_file, char *s)
419 {
420 fprintf (pdf_file->f, "/");
421 while (*s)
422 if (name_char_needs_quoting (*s))
423 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
424 else
425 fprintf (pdf_file->f, "%c", *(s++));
426 fprintf (pdf_file->f, " ");
427 }
430 static int string_char_needs_quoting (char c)
431 {
432 return ((c < ' ') || (c > '~') || (c == '\\') ||
433 (c == '(') || (c == ')'));
434 }
437 void pdf_write_string (pdf_file_handle pdf_file, char *s)
438 {
439 fprintf (pdf_file->f, "(");
440 while (*s)
441 if (string_char_needs_quoting (*s))
442 fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
443 else
444 fprintf (pdf_file->f, "%c", *(s++));
445 fprintf (pdf_file->f, ") ");
446 }
449 void pdf_write_real (pdf_file_handle pdf_file, double num)
450 {
451 /* $$$ not actually good enough, precision needs to be variable,
452 and no exponent is allowed */
453 fprintf (pdf_file->f, "%0f ", num);
454 }
457 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
458 {
459 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
460 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
461 }
464 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
465 {
466 struct pdf_array_elem *elem;
468 pdf_assert (array_obj->type == PT_ARRAY);
470 fprintf (pdf_file->f, "[ ");
471 for (elem = array_obj->val.array.first; elem; elem = elem->next)
472 {
473 pdf_write_obj (pdf_file, elem->val);
474 fprintf (pdf_file->f, " ");
475 }
476 fprintf (pdf_file->f, "] ");
477 }
480 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
481 {
482 struct pdf_dict_entry *entry;
484 pdf_assert (dict_obj->type == PT_DICTIONARY);
486 fprintf (pdf_file->f, "<<\r\n");
487 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
488 {
489 pdf_write_name (pdf_file, entry->key);
490 fprintf (pdf_file->f, " ");
491 pdf_write_obj (pdf_file, entry->val);
492 fprintf (pdf_file->f, "\r\n");
493 }
494 fprintf (pdf_file->f, ">>\r\n");
495 }
498 void pdf_stream_write_data (pdf_file_handle pdf_file,
499 struct pdf_obj *stream,
500 char *data,
501 unsigned long len)
502 {
503 while (len)
504 {
505 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
506 data += l2;
507 len -= l2;
508 if (ferror (pdf_file->f))
509 pdf_fatal ("error writing stream data\n");
510 }
511 }
514 void pdf_stream_printf (pdf_file_handle pdf_file,
515 struct pdf_obj *stream,
516 char *fmt, ...)
517 {
518 va_list ap;
520 va_start (ap, fmt);
521 vfprintf (pdf_file->f, fmt, ap);
522 va_end (ap);
523 }
526 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
527 {
528 unsigned long begin_pos, end_pos;
530 pdf_assert (stream->type == PT_STREAM);
532 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
533 fprintf (pdf_file->f, "stream\r\n");
534 begin_pos = ftell (pdf_file->f);
535 stream->val.stream.callback (pdf_file,
536 stream,
537 stream->val.stream.app_data);
538 end_pos = ftell (pdf_file->f);
540 fprintf (pdf_file->f, "\r\nendstream\r\n");
542 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
543 }
546 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
547 {
548 switch (obj->type)
549 {
550 case PT_NULL:
551 fprintf (pdf_file->f, "null ");
552 break;
553 case PT_BOOL:
554 if (obj->val.boolean)
555 fprintf (pdf_file->f, "true ");
556 else
557 fprintf (pdf_file->f, "false ");
558 break;
559 case PT_NAME:
560 pdf_write_name (pdf_file, obj->val.name);
561 break;
562 case PT_STRING:
563 pdf_write_string (pdf_file, obj->val.string);
564 break;
565 case PT_INTEGER:
566 fprintf (pdf_file->f, "%ld ", obj->val.integer);
567 break;
568 case PT_REAL:
569 pdf_write_real (pdf_file, obj->val.real);
570 break;
571 case PT_IND_REF:
572 pdf_write_ind_ref (pdf_file, obj);
573 break;
574 case PT_DICTIONARY:
575 pdf_write_dict (pdf_file, obj);
576 break;
577 case PT_ARRAY:
578 pdf_write_array (pdf_file, obj);
579 break;
580 case PT_STREAM:
581 pdf_write_stream (pdf_file, obj);
582 break;
583 default:
584 pdf_fatal ("bad object type\n");
585 }
586 }
589 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
590 {
591 struct pdf_obj *obj;
593 if (ind_obj->type == PT_IND_REF)
594 obj = pdf_deref_ind_obj (ind_obj);
595 else
596 obj = ind_obj;
598 obj->file_offset = ftell (pdf_file->f);
599 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
600 pdf_write_obj (pdf_file, obj);
601 fprintf (pdf_file->f, "endobj\r\n");
602 }
605 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
606 {
607 struct pdf_obj *ind_obj;
608 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
609 if (! ind_obj->file_offset)
610 pdf_write_ind_obj (pdf_file, ind_obj);
611 }
614 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
615 {
616 struct pdf_obj *ind_obj;
617 pdf_file->xref_offset = ftell (pdf_file->f);
618 fprintf (pdf_file->f, "xref\r\n");
619 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
620 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
621 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
622 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
623 return (pdf_file->last_ind_obj->obj_num + 1);
624 }
627 /* this isn't really a PDF primitive data type */
628 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
629 {
630 char XObject_name [4] = "Im ";
632 XObject_name [2] = ++pdf_page->last_XObject_name;
634 if (! pdf_page->XObject_dict)
635 {
636 pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
637 pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
638 }
640 pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
642 return (pdf_page->last_XObject_name);
643 }