Mon, 14 Dec 2009 16:00:58 +0000
add hgignore file
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 struct {
94 char *content;
95 int length;
96 } string;
97 long integer;
98 double real;
99 struct pdf_obj *ind_ref;
100 struct pdf_dict dict;
101 struct pdf_array array;
102 struct pdf_stream stream;
103 } val;
104 };
107 struct pdf_obj *ref (struct pdf_obj *obj)
108 {
109 obj->ref_count++;
110 return (obj);
111 }
114 void unref (struct pdf_obj *obj)
115 {
116 if ((--obj->ref_count) == 0)
117 {
118 /* $$$ free the object */
119 }
120 }
123 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
124 {
125 pdf_assert (ind_obj->type == PT_IND_REF);
126 return (ind_obj->val.ind_ref);
127 }
130 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
131 {
132 struct pdf_dict_entry *entry;
134 if (dict_obj->type == PT_IND_REF)
135 dict_obj = pdf_deref_ind_obj (dict_obj);
137 pdf_assert (dict_obj->type == PT_DICTIONARY);
139 /* replacing existing entry? */
140 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
141 if (strcmp (entry->key, key) == 0)
142 {
143 unref (entry->val);
144 entry->val = ref (val);
145 return;
146 }
148 /* new entry */
149 entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
151 entry->next = dict_obj->val.dict.first;
152 dict_obj->val.dict.first = entry;
154 entry->key = pdf_strdup (key);
155 entry->val = ref (val);
156 }
159 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
160 {
161 struct pdf_dict_entry *entry;
163 if (dict_obj->type == PT_IND_REF)
164 dict_obj = pdf_deref_ind_obj (dict_obj);
166 pdf_assert (dict_obj->type == PT_DICTIONARY);
168 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
169 if (strcmp (entry->key, key) == 0)
170 return (entry->val);
172 return (NULL);
173 }
176 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
177 {
178 struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
180 if (array_obj->type == PT_IND_REF)
181 array_obj = pdf_deref_ind_obj (array_obj);
183 pdf_assert (array_obj->type == PT_ARRAY);
185 elem->val = ref (val);
187 if (! array_obj->val.array.first)
188 array_obj->val.array.first = elem;
189 else
190 array_obj->val.array.last->next = elem;
192 array_obj->val.array.last = elem;
193 }
196 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
197 {
198 struct pdf_array_elem *elem;
200 if (array_obj->type == PT_IND_REF)
201 array_obj = pdf_deref_ind_obj (array_obj);
203 pdf_assert (array_obj->type == PT_ARRAY);
205 for (elem = array_obj->val.array.first; elem; elem = elem->next)
206 if (pdf_compare_obj (val, elem->val) == 0)
207 return;
209 elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
211 elem->val = ref (val);
213 if (! array_obj->val.array.first)
214 array_obj->val.array.first = elem;
215 else
216 array_obj->val.array.last->next = elem;
218 array_obj->val.array.last = elem;
219 }
222 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
223 {
224 struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
225 obj->type = type;
226 return (obj);
227 }
230 struct pdf_obj *pdf_new_bool (bool val)
231 {
232 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
233 obj->val.boolean = val;
234 return (obj);
235 }
238 struct pdf_obj *pdf_new_name (char *name)
239 {
240 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
241 obj->val.name = pdf_strdup (name);
242 return (obj);
243 }
246 struct pdf_obj *pdf_new_string (char *str)
247 {
248 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
249 obj->val.string.content = pdf_strdup (str);
250 obj->val.string.length = strlen(str);
251 return (obj);
252 }
255 struct pdf_obj *pdf_new_string_n (char *str, int n)
256 {
257 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
258 obj->val.string.length = n;
259 obj->val.string.content = pdf_calloc (1,n);
260 memcpy(obj->val.string.content, str, n);
261 return (obj);
262 }
265 struct pdf_obj *pdf_new_integer (long val)
266 {
267 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
268 obj->val.integer = val;
269 return (obj);
270 }
273 struct pdf_obj *pdf_new_real (double val)
274 {
275 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
276 obj->val.real = val;
277 return (obj);
278 }
281 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
282 struct pdf_obj *stream_dict,
283 pdf_stream_write_callback callback,
284 void *app_data)
285 {
286 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
288 obj->val.stream.stream_dict = stream_dict;
289 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
290 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
292 obj->val.stream.callback = callback;
293 obj->val.stream.app_data = app_data;
294 return (obj);
295 }
298 /* $$$ currently limited to one filter per stream */
299 void pdf_stream_add_filter (struct pdf_obj *stream,
300 char *filter_name,
301 struct pdf_obj *decode_parms)
302 {
303 if (stream->type == PT_IND_REF)
304 stream = pdf_deref_ind_obj (stream);
306 pdf_assert (stream->type == PT_STREAM);
308 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
309 if (decode_parms)
310 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
311 }
314 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
315 {
316 struct pdf_obj *ind_obj;
318 pdf_assert (obj->type != PT_IND_REF);
320 ind_obj = pdf_new_obj (PT_IND_REF);
322 ind_obj->type = PT_IND_REF;
323 ind_obj->val.ind_ref = obj;
325 /* is there already an indirect reference to this object? */
326 if (! obj->obj_num)
327 {
328 /* no, assign object number/generation and add to linked list */
329 if (! pdf_file->first_ind_obj)
330 {
331 obj->obj_num = 1;
332 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
333 }
334 else
335 {
336 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
337 pdf_file->last_ind_obj->next = obj;
338 obj->prev = pdf_file->last_ind_obj;
339 pdf_file->last_ind_obj = obj;
340 }
341 }
343 return (ind_obj);
344 }
347 long pdf_get_integer (struct pdf_obj *obj)
348 {
349 if (obj->type == PT_IND_REF)
350 obj = pdf_deref_ind_obj (obj);
352 pdf_assert (obj->type == PT_INTEGER);
354 return (obj->val.integer);
355 }
357 void pdf_set_integer (struct pdf_obj *obj, long val)
358 {
359 if (obj->type == PT_IND_REF)
360 obj = pdf_deref_ind_obj (obj);
362 pdf_assert (obj->type == PT_INTEGER);
364 obj->val.integer = val;
365 }
368 double pdf_get_real (struct pdf_obj *obj)
369 {
370 if (obj->type == PT_IND_REF)
371 obj = pdf_deref_ind_obj (obj);
373 pdf_assert (obj->type == PT_REAL);
375 return (obj->val.real);
376 }
378 void pdf_set_real (struct pdf_obj *obj, double val)
379 {
380 if (obj->type == PT_IND_REF)
381 obj = pdf_deref_ind_obj (obj);
383 pdf_assert (obj->type == PT_REAL);
385 obj->val.real = val;
386 }
389 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
390 {
391 if (o1->type == PT_IND_REF)
392 o1 = pdf_deref_ind_obj (o1);
394 if (o2->type == PT_IND_REF)
395 o2 = pdf_deref_ind_obj (o2);
397 pdf_assert (o1->type == o2->type);
399 switch (o1->type)
400 {
401 case PT_INTEGER:
402 if (o1->val.integer < o2->val.integer)
403 return (-1);
404 if (o1->val.integer > o2->val.integer)
405 return (1);
406 return (0);
407 case PT_REAL:
408 if (o1->val.real < o2->val.real)
409 return (-1);
410 if (o1->val.real > o2->val.real)
411 return (1);
412 return (0);
413 case PT_STRING:
414 {
415 int l;
416 l = o1->val.string.length;
417 if(l > o2->val.string.length)
418 l = o2->val.string.length;
419 l = memcmp (o1->val.string.content, o2->val.string.content, l);
420 if (l)
421 return l;
422 return o1->val.string.length - o2->val.string.length;
423 }
424 case PT_NAME:
425 return (strcmp (o1->val.name, o2->val.name));
426 default:
427 pdf_fatal ("invalid object type for comparison\n");
428 }
429 }
432 static int name_char_needs_quoting (char c)
433 {
434 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
435 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
436 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
437 (c == '%'));
438 }
441 void pdf_write_name (pdf_file_handle pdf_file, char *s)
442 {
443 fprintf (pdf_file->f, "/");
444 while (*s)
445 if (name_char_needs_quoting (*s))
446 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
447 else
448 fprintf (pdf_file->f, "%c", *(s++));
449 fprintf (pdf_file->f, " ");
450 }
453 static int pdf_write_literal_string (pdf_file_handle pdf_file, char *s, int n)
454 {
455 int i,p;
456 if(pdf_file) fprintf (pdf_file->f, "(");
457 for (i=p=0;n;n--) {
458 int j,k;
459 k=0;
460 switch(*s){
461 case '\\':
462 k=1;
463 break;
464 case '(':
465 for(j=k=1;k && j<n;j++)
466 k+=(s[j]=='(')?1:(s[j]==')')?-1:0;
467 p+=!k;
468 break;
469 case ')':
470 if(p)
471 p--;
472 else
473 k=1;
474 break;
475 }
476 if(k) {
477 i++;
478 if(pdf_file) fprintf (pdf_file->f, "\\");
479 }
480 i++;
481 if(pdf_file) fprintf (pdf_file->f, "%c", *(s++));
482 }
483 if(pdf_file) fprintf (pdf_file->f, ") ");
484 return i;
485 }
488 void pdf_write_string (pdf_file_handle pdf_file, char *s, int n)
489 {
490 if(pdf_write_literal_string (NULL,s,n)<2*n)
491 pdf_write_literal_string (pdf_file,s,n);
492 else {
493 fprintf (pdf_file->f, "<");
494 for(;n--;)
495 fprintf (pdf_file->f, "%.2X",*(s++));
496 fprintf (pdf_file->f, "> ");
497 }
498 }
501 void pdf_write_real (pdf_file_handle pdf_file, double num)
502 {
503 /* $$$ not actually good enough, precision needs to be variable,
504 and no exponent is allowed */
505 fprintf (pdf_file->f, "%0f ", num);
506 }
509 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
510 {
511 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
512 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
513 }
516 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
517 {
518 struct pdf_array_elem *elem;
520 pdf_assert (array_obj->type == PT_ARRAY);
522 fprintf (pdf_file->f, "[ ");
523 for (elem = array_obj->val.array.first; elem; elem = elem->next)
524 {
525 pdf_write_obj (pdf_file, elem->val);
526 fprintf (pdf_file->f, " ");
527 }
528 fprintf (pdf_file->f, "] ");
529 }
532 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
533 {
534 struct pdf_dict_entry *entry;
536 pdf_assert (dict_obj->type == PT_DICTIONARY);
538 fprintf (pdf_file->f, "<<\r\n");
539 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
540 {
541 pdf_write_name (pdf_file, entry->key);
542 fprintf (pdf_file->f, " ");
543 pdf_write_obj (pdf_file, entry->val);
544 fprintf (pdf_file->f, "\r\n");
545 }
546 fprintf (pdf_file->f, ">>\r\n");
547 }
550 void pdf_stream_write_data (pdf_file_handle pdf_file,
551 struct pdf_obj *stream,
552 char *data,
553 unsigned long len)
554 {
555 while (len)
556 {
557 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
558 data += l2;
559 len -= l2;
560 if (ferror (pdf_file->f))
561 pdf_fatal ("error writing stream data\n");
562 }
563 }
566 void pdf_stream_printf (pdf_file_handle pdf_file,
567 struct pdf_obj *stream,
568 char *fmt, ...)
569 {
570 va_list ap;
572 va_start (ap, fmt);
573 vfprintf (pdf_file->f, fmt, ap);
574 va_end (ap);
575 }
578 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
579 {
580 unsigned long begin_pos, end_pos;
582 pdf_assert (stream->type == PT_STREAM);
584 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
585 fprintf (pdf_file->f, "stream\r\n");
586 begin_pos = ftell (pdf_file->f);
587 stream->val.stream.callback (pdf_file,
588 stream,
589 stream->val.stream.app_data);
590 end_pos = ftell (pdf_file->f);
592 fprintf (pdf_file->f, "\r\nendstream\r\n");
594 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
595 }
598 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
599 {
600 switch (obj->type)
601 {
602 case PT_NULL:
603 fprintf (pdf_file->f, "null ");
604 break;
605 case PT_BOOL:
606 if (obj->val.boolean)
607 fprintf (pdf_file->f, "true ");
608 else
609 fprintf (pdf_file->f, "false ");
610 break;
611 case PT_NAME:
612 pdf_write_name (pdf_file, obj->val.name);
613 break;
614 case PT_STRING:
615 pdf_write_string (pdf_file, obj->val.string.content, obj->val.string.length);
616 break;
617 case PT_INTEGER:
618 fprintf (pdf_file->f, "%ld ", obj->val.integer);
619 break;
620 case PT_REAL:
621 pdf_write_real (pdf_file, obj->val.real);
622 break;
623 case PT_IND_REF:
624 pdf_write_ind_ref (pdf_file, obj);
625 break;
626 case PT_DICTIONARY:
627 pdf_write_dict (pdf_file, obj);
628 break;
629 case PT_ARRAY:
630 pdf_write_array (pdf_file, obj);
631 break;
632 case PT_STREAM:
633 pdf_write_stream (pdf_file, obj);
634 break;
635 default:
636 pdf_fatal ("bad object type\n");
637 }
638 }
641 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
642 {
643 struct pdf_obj *obj;
645 if (ind_obj->type == PT_IND_REF)
646 obj = pdf_deref_ind_obj (ind_obj);
647 else
648 obj = ind_obj;
650 obj->file_offset = ftell (pdf_file->f);
651 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
652 pdf_write_obj (pdf_file, obj);
653 fprintf (pdf_file->f, "endobj\r\n");
654 }
657 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
658 {
659 struct pdf_obj *ind_obj;
660 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
661 if (! ind_obj->file_offset)
662 pdf_write_ind_obj (pdf_file, ind_obj);
663 }
666 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
667 {
668 struct pdf_obj *ind_obj;
669 pdf_file->xref_offset = ftell (pdf_file->f);
670 fprintf (pdf_file->f, "xref\r\n");
671 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
672 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
673 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
674 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
675 return (pdf_file->last_ind_obj->obj_num + 1);
676 }
679 /* this isn't really a PDF primitive data type */
680 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
681 {
682 char XObject_name [4] = "Im ";
684 XObject_name [2] = ++pdf_page->last_XObject_name;
686 if (! pdf_page->XObject_dict)
687 {
688 pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
689 pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
690 }
692 pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
694 return (pdf_page->last_XObject_name);
695 }