pdf_prim.c

Sat, 08 Mar 2003 06:52:09 +0000

author
eric
date
Sat, 08 Mar 2003 06:52:09 +0000
changeset 85
dcfd1d4b5c24
parent 82
abb03c7f4aab
child 91
e63762afae80
permissions
-rw-r--r--

add linked list of name trees to struct pdf_file, and finalize all name trees when PDF file is closed.

eric@62 1 /*
eric@62 2 * t2p: Create a PDF file from the contents of one or more TIFF
eric@62 3 * bilevel image files. The images in the resulting PDF file
eric@62 4 * will be compressed using ITU-T T.6 (G4) fax encoding.
eric@62 5 *
eric@62 6 * PDF routines
eric@82 7 * $Id: pdf_prim.c,v 1.7 2003/03/07 03:02:31 eric Exp $
eric@62 8 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
eric@62 9 *
eric@62 10 * This program is free software; you can redistribute it and/or modify
eric@62 11 * it under the terms of the GNU General Public License version 2 as
eric@62 12 * published by the Free Software Foundation. Note that permission is
eric@62 13 * not granted to redistribute this program under the terms of any
eric@62 14 * other version of the General Public License.
eric@62 15 *
eric@62 16 * This program is distributed in the hope that it will be useful,
eric@62 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
eric@62 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
eric@62 19 * GNU General Public License for more details.
eric@62 20 *
eric@62 21 * You should have received a copy of the GNU General Public License
eric@62 22 * along with this program; if not, write to the Free Software
eric@62 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
eric@62 24 */
eric@62 25
eric@62 26
eric@66 27 #include <stdarg.h>
eric@62 28 #include <stdbool.h>
eric@62 29 #include <stdint.h>
eric@59 30 #include <stdio.h>
eric@59 31 #include <stdlib.h>
eric@59 32 #include <string.h>
eric@59 33
eric@62 34 #include "bitblt.h"
eric@60 35 #include "pdf.h"
eric@60 36 #include "pdf_util.h"
eric@60 37 #include "pdf_prim.h"
eric@60 38 #include "pdf_private.h"
eric@59 39
eric@59 40
eric@59 41 struct pdf_array_elem
eric@59 42 {
eric@59 43 struct pdf_array_elem *next;
eric@59 44 struct pdf_obj *val;
eric@59 45 };
eric@59 46
eric@59 47
eric@59 48 struct pdf_array
eric@59 49 {
eric@59 50 struct pdf_array_elem *first;
eric@59 51 struct pdf_array_elem *last;
eric@59 52 };
eric@59 53
eric@59 54
eric@59 55 struct pdf_dict_entry
eric@59 56 {
eric@59 57 struct pdf_dict_entry *next;
eric@59 58 char *key;
eric@59 59 struct pdf_obj *val;
eric@59 60 };
eric@59 61
eric@59 62
eric@59 63 struct pdf_dict
eric@59 64 {
eric@59 65 struct pdf_dict_entry *first;
eric@59 66 };
eric@59 67
eric@59 68
eric@67 69 #define STREAM_BUF_SIZE 4096
eric@67 70
eric@59 71 struct pdf_stream
eric@59 72 {
eric@59 73 struct pdf_obj *stream_dict;
eric@59 74 struct pdf_obj *length;
eric@59 75 pdf_stream_write_callback callback;
eric@59 76 void *app_data; /* arg to pass to callback */
eric@59 77 struct pdf_obj *filters; /* name or array of names */
eric@59 78 struct pdf_obj *decode_parms;
eric@67 79
eric@67 80 /* The following fields are used by pdf_stream_write_bits() and
eric@67 81 pdf_stream_flush_bits(). */
eric@67 82 uint32_t byte_idx; /* index to next byte position in data buffer */
eric@67 83 uint32_t bit_idx; /* index to next bit position in data buffer,
eric@67 84 0 = MSB, 7 = LSB */
eric@67 85 uint8_t data [STREAM_BUF_SIZE];
eric@59 86 };
eric@59 87
eric@59 88
eric@59 89 struct pdf_obj
eric@59 90 {
eric@59 91 /* these fields only apply to indirectly referenced objects */
eric@59 92 struct pdf_obj *prev;
eric@59 93 struct pdf_obj *next;
eric@59 94 unsigned long obj_num;
eric@59 95 unsigned long obj_gen;
eric@59 96 long int file_offset;
eric@59 97
eric@59 98 /* these fields apply to all objects */
eric@59 99 unsigned long ref_count;
eric@59 100 pdf_obj_type type;
eric@59 101 union {
eric@62 102 bool boolean;
eric@59 103 char *name;
eric@59 104 char *string;
eric@74 105 long integer;
eric@59 106 double real;
eric@59 107 struct pdf_obj *ind_ref;
eric@59 108 struct pdf_dict dict;
eric@59 109 struct pdf_array array;
eric@59 110 struct pdf_stream stream;
eric@59 111 } val;
eric@59 112 };
eric@59 113
eric@59 114
eric@59 115 struct pdf_obj *ref (struct pdf_obj *obj)
eric@59 116 {
eric@59 117 obj->ref_count++;
eric@59 118 return (obj);
eric@59 119 }
eric@59 120
eric@59 121
eric@59 122 void unref (struct pdf_obj *obj)
eric@59 123 {
eric@59 124 if ((--obj->ref_count) == 0)
eric@59 125 {
eric@59 126 /* $$$ free the object */
eric@59 127 }
eric@59 128 }
eric@59 129
eric@59 130
eric@59 131 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
eric@59 132 {
eric@59 133 pdf_assert (ind_obj->type == PT_IND_REF);
eric@59 134 return (ind_obj->val.ind_ref);
eric@59 135 }
eric@59 136
eric@59 137
eric@59 138 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
eric@59 139 {
eric@59 140 struct pdf_dict_entry *entry;
eric@59 141
eric@59 142 if (dict_obj->type == PT_IND_REF)
eric@59 143 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 144
eric@59 145 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 146
eric@59 147 /* replacing existing entry? */
eric@59 148 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 149 if (strcmp (entry->key, key) == 0)
eric@59 150 {
eric@59 151 unref (entry->val);
eric@59 152 entry->val = ref (val);
eric@59 153 return;
eric@59 154 }
eric@59 155
eric@59 156 /* new entry */
eric@67 157 entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
eric@59 158
eric@59 159 entry->next = dict_obj->val.dict.first;
eric@59 160 dict_obj->val.dict.first = entry;
eric@59 161
eric@59 162 entry->key = pdf_strdup (key);
eric@59 163 entry->val = ref (val);
eric@59 164 }
eric@59 165
eric@59 166
eric@59 167 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
eric@59 168 {
eric@59 169 struct pdf_dict_entry *entry;
eric@59 170
eric@59 171 if (dict_obj->type == PT_IND_REF)
eric@59 172 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 173
eric@59 174 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 175
eric@59 176 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 177 if (strcmp (entry->key, key) == 0)
eric@59 178 return (entry->val);
eric@59 179
eric@59 180 return (NULL);
eric@59 181 }
eric@59 182
eric@59 183
eric@59 184 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
eric@59 185 {
eric@67 186 struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
eric@59 187
eric@59 188 if (array_obj->type == PT_IND_REF)
eric@59 189 array_obj = pdf_deref_ind_obj (array_obj);
eric@59 190
eric@59 191 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 192
eric@59 193 elem->val = ref (val);
eric@59 194
eric@59 195 if (! array_obj->val.array.first)
eric@59 196 array_obj->val.array.first = elem;
eric@59 197 else
eric@59 198 array_obj->val.array.last->next = elem;
eric@59 199
eric@59 200 array_obj->val.array.last = elem;
eric@59 201 }
eric@59 202
eric@59 203
eric@59 204 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
eric@59 205 {
eric@67 206 struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
eric@59 207 obj->type = type;
eric@59 208 return (obj);
eric@59 209 }
eric@59 210
eric@59 211
eric@62 212 struct pdf_obj *pdf_new_bool (bool val)
eric@59 213 {
eric@59 214 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
eric@62 215 obj->val.boolean = val;
eric@59 216 return (obj);
eric@59 217 }
eric@59 218
eric@59 219
eric@59 220 struct pdf_obj *pdf_new_name (char *name)
eric@59 221 {
eric@59 222 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
eric@59 223 obj->val.name = pdf_strdup (name);
eric@59 224 return (obj);
eric@59 225 }
eric@59 226
eric@59 227
eric@59 228 struct pdf_obj *pdf_new_string (char *str)
eric@59 229 {
eric@59 230 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
eric@59 231 obj->val.string = pdf_strdup (str);
eric@59 232 return (obj);
eric@59 233 }
eric@59 234
eric@59 235
eric@74 236 struct pdf_obj *pdf_new_integer (long val)
eric@59 237 {
eric@59 238 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
eric@59 239 obj->val.integer = val;
eric@59 240 return (obj);
eric@59 241 }
eric@59 242
eric@59 243
eric@59 244 struct pdf_obj *pdf_new_real (double val)
eric@59 245 {
eric@59 246 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
eric@59 247 obj->val.real = val;
eric@59 248 return (obj);
eric@59 249 }
eric@59 250
eric@59 251
eric@59 252 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
eric@59 253 struct pdf_obj *stream_dict,
eric@59 254 pdf_stream_write_callback callback,
eric@59 255 void *app_data)
eric@59 256 {
eric@59 257 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
eric@59 258
eric@59 259 obj->val.stream.stream_dict = stream_dict;
eric@59 260 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
eric@59 261 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
eric@59 262
eric@59 263 obj->val.stream.callback = callback;
eric@59 264 obj->val.stream.app_data = app_data;
eric@59 265 return (obj);
eric@59 266 }
eric@59 267
eric@59 268
eric@59 269 /* $$$ currently limited to one filter per stream */
eric@59 270 void pdf_stream_add_filter (struct pdf_obj *stream,
eric@59 271 char *filter_name,
eric@59 272 struct pdf_obj *decode_parms)
eric@59 273 {
eric@59 274 if (stream->type == PT_IND_REF)
eric@59 275 stream = pdf_deref_ind_obj (stream);
eric@59 276
eric@59 277 pdf_assert (stream->type == PT_STREAM);
eric@59 278
eric@59 279 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
eric@59 280 if (decode_parms)
eric@59 281 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
eric@59 282 }
eric@59 283
eric@59 284
eric@59 285 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 286 {
eric@59 287 struct pdf_obj *ind_obj;
eric@59 288
eric@59 289 pdf_assert (obj->type != PT_IND_REF);
eric@59 290
eric@59 291 ind_obj = pdf_new_obj (PT_IND_REF);
eric@59 292
eric@59 293 ind_obj->type = PT_IND_REF;
eric@59 294 ind_obj->val.ind_ref = obj;
eric@59 295
eric@59 296 /* is there already an indirect reference to this object? */
eric@59 297 if (! obj->obj_num)
eric@59 298 {
eric@59 299 /* no, assign object number/generation and add to linked list */
eric@59 300 if (! pdf_file->first_ind_obj)
eric@59 301 {
eric@59 302 obj->obj_num = 1;
eric@59 303 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
eric@59 304 }
eric@59 305 else
eric@59 306 {
eric@59 307 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
eric@59 308 pdf_file->last_ind_obj->next = obj;
eric@59 309 obj->prev = pdf_file->last_ind_obj;
eric@59 310 pdf_file->last_ind_obj = obj;
eric@59 311 }
eric@59 312 }
eric@59 313
eric@59 314 return (ind_obj);
eric@59 315 }
eric@59 316
eric@59 317
eric@74 318 long pdf_get_integer (struct pdf_obj *obj)
eric@59 319 {
eric@59 320 if (obj->type == PT_IND_REF)
eric@59 321 obj = pdf_deref_ind_obj (obj);
eric@59 322
eric@59 323 pdf_assert (obj->type == PT_INTEGER);
eric@59 324
eric@59 325 return (obj->val.integer);
eric@59 326 }
eric@59 327
eric@74 328 void pdf_set_integer (struct pdf_obj *obj, long val)
eric@59 329 {
eric@59 330 if (obj->type == PT_IND_REF)
eric@59 331 obj = pdf_deref_ind_obj (obj);
eric@59 332
eric@59 333 pdf_assert (obj->type == PT_INTEGER);
eric@59 334
eric@59 335 obj->val.integer = val;
eric@59 336 }
eric@59 337
eric@59 338
eric@59 339 double pdf_get_real (struct pdf_obj *obj)
eric@59 340 {
eric@59 341 if (obj->type == PT_IND_REF)
eric@59 342 obj = pdf_deref_ind_obj (obj);
eric@59 343
eric@59 344 pdf_assert (obj->type == PT_REAL);
eric@59 345
eric@59 346 return (obj->val.real);
eric@59 347 }
eric@59 348
eric@59 349 void pdf_set_real (struct pdf_obj *obj, double val)
eric@59 350 {
eric@59 351 if (obj->type == PT_IND_REF)
eric@59 352 obj = pdf_deref_ind_obj (obj);
eric@59 353
eric@59 354 pdf_assert (obj->type == PT_REAL);
eric@59 355
eric@59 356 obj->val.real = val;
eric@59 357 }
eric@59 358
eric@59 359
eric@82 360 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
eric@82 361 {
eric@82 362 if (o1->type == PT_IND_REF)
eric@82 363 o1 = pdf_deref_ind_obj (o1);
eric@82 364
eric@82 365 if (o2->type == PT_IND_REF)
eric@82 366 o2 = pdf_deref_ind_obj (o2);
eric@82 367
eric@82 368 pdf_assert (o1->type == o2->type);
eric@82 369
eric@82 370 switch (o1->type)
eric@82 371 {
eric@82 372 case PT_INTEGER:
eric@82 373 if (o1->val.integer < o2->val.integer)
eric@82 374 return (-1);
eric@82 375 if (o1->val.integer > o2->val.integer)
eric@82 376 return (1);
eric@82 377 return (0);
eric@82 378 case PT_REAL:
eric@82 379 if (o1->val.real < o2->val.real)
eric@82 380 return (-1);
eric@82 381 if (o1->val.real > o2->val.real)
eric@82 382 return (1);
eric@82 383 return (0);
eric@82 384 case PT_STRING:
eric@82 385 return (strcmp (o1->val.string, o2->val.string));
eric@82 386 default:
eric@82 387 pdf_fatal ("invalid object type for comparison\n");
eric@82 388 }
eric@82 389 }
eric@82 390
eric@82 391
eric@59 392 static int name_char_needs_quoting (char c)
eric@59 393 {
eric@59 394 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
eric@59 395 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
eric@59 396 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
eric@59 397 (c == '%'));
eric@59 398 }
eric@59 399
eric@59 400
eric@59 401 void pdf_write_name (pdf_file_handle pdf_file, char *s)
eric@59 402 {
eric@59 403 fprintf (pdf_file->f, "/");
eric@59 404 while (*s)
eric@59 405 if (name_char_needs_quoting (*s))
eric@59 406 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
eric@59 407 else
eric@59 408 fprintf (pdf_file->f, "%c", *(s++));
eric@59 409 fprintf (pdf_file->f, " ");
eric@59 410 }
eric@59 411
eric@59 412
eric@59 413 static int string_char_needs_quoting (char c)
eric@59 414 {
eric@59 415 return ((c < ' ') || (c > '~') || (c == '\\') ||
eric@59 416 (c == '(') || (c == ')'));
eric@59 417 }
eric@59 418
eric@59 419
eric@59 420 void pdf_write_string (pdf_file_handle pdf_file, char *s)
eric@59 421 {
eric@59 422 fprintf (pdf_file->f, "(");
eric@59 423 while (*s)
eric@59 424 if (string_char_needs_quoting (*s))
eric@59 425 fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
eric@59 426 else
eric@59 427 fprintf (pdf_file->f, "%c", *(s++));
eric@59 428 fprintf (pdf_file->f, ") ");
eric@59 429 }
eric@59 430
eric@59 431
eric@59 432 void pdf_write_real (pdf_file_handle pdf_file, double num)
eric@59 433 {
eric@59 434 /* $$$ not actually good enough, precision needs to be variable,
eric@59 435 and no exponent is allowed */
eric@59 436 fprintf (pdf_file->f, "%0f ", num);
eric@59 437 }
eric@59 438
eric@59 439
eric@59 440 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 441 {
eric@59 442 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
eric@59 443 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
eric@59 444 }
eric@59 445
eric@59 446
eric@59 447 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
eric@59 448 {
eric@59 449 struct pdf_array_elem *elem;
eric@59 450
eric@59 451 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 452
eric@59 453 fprintf (pdf_file->f, "[ ");
eric@59 454 for (elem = array_obj->val.array.first; elem; elem = elem->next)
eric@59 455 {
eric@59 456 pdf_write_obj (pdf_file, elem->val);
eric@59 457 fprintf (pdf_file->f, " ");
eric@59 458 }
eric@59 459 fprintf (pdf_file->f, "] ");
eric@59 460 }
eric@59 461
eric@59 462
eric@59 463 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
eric@59 464 {
eric@59 465 struct pdf_dict_entry *entry;
eric@59 466
eric@59 467 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 468
eric@59 469 fprintf (pdf_file->f, "<<\r\n");
eric@59 470 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 471 {
eric@59 472 pdf_write_name (pdf_file, entry->key);
eric@59 473 fprintf (pdf_file->f, " ");
eric@59 474 pdf_write_obj (pdf_file, entry->val);
eric@59 475 fprintf (pdf_file->f, "\r\n");
eric@59 476 }
eric@59 477 fprintf (pdf_file->f, ">>\r\n");
eric@59 478 }
eric@59 479
eric@59 480
eric@59 481 void pdf_stream_write_data (pdf_file_handle pdf_file,
eric@59 482 struct pdf_obj *stream,
eric@59 483 char *data,
eric@59 484 unsigned long len)
eric@59 485 {
eric@59 486 while (len)
eric@59 487 {
eric@59 488 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
eric@59 489 data += l2;
eric@59 490 len -= l2;
eric@59 491 if (ferror (pdf_file->f))
eric@59 492 pdf_fatal ("error writing stream data\n");
eric@59 493 }
eric@59 494 }
eric@59 495
eric@59 496
eric@67 497 void pdf_stream_flush_bits (pdf_file_handle pdf_file,
eric@67 498 struct pdf_obj *stream)
eric@67 499 {
eric@67 500 struct pdf_stream *s = & stream->val.stream;
eric@67 501
eric@67 502 if (s->bit_idx)
eric@67 503 {
eric@67 504 /* zero remaining bits in last byte */
eric@67 505 s->data [s->byte_idx] &= ~ ((1 << (8 - s->bit_idx)) - 1);
eric@67 506 s->byte_idx++;
eric@67 507 s->bit_idx = 0;
eric@67 508 }
eric@67 509 pdf_stream_write_data (pdf_file, stream,
eric@67 510 (char *) & s->data [0],
eric@67 511 s->byte_idx);
eric@67 512 s->byte_idx = 0;
eric@67 513 }
eric@67 514
eric@67 515
eric@67 516 static void pdf_stream_advance_byte (pdf_file_handle pdf_file,
eric@67 517 struct pdf_obj *stream)
eric@67 518 {
eric@67 519 struct pdf_stream *s = & stream->val.stream;
eric@67 520
eric@67 521 s->byte_idx++;
eric@67 522 s->bit_idx = 0;
eric@67 523 if (s->byte_idx == STREAM_BUF_SIZE)
eric@67 524 pdf_stream_flush_bits (pdf_file, stream);
eric@67 525 }
eric@67 526
eric@67 527
eric@67 528 void pdf_stream_write_bits (pdf_file_handle pdf_file,
eric@67 529 struct pdf_obj *stream,
eric@67 530 uint32_t count,
eric@67 531 uint32_t bits)
eric@67 532 {
eric@67 533 struct pdf_stream *s = & stream->val.stream;
eric@67 534
eric@67 535 uint32_t b2; /* how many bits will fit in byte in data buffer */
eric@67 536 uint32_t c2; /* how many bits to transfer on this iteration */
eric@67 537 uint32_t d2; /* bits to transfer on this iteration */
eric@67 538
eric@67 539 while (count)
eric@67 540 {
eric@67 541 b2 = 8 - s->bit_idx;
eric@67 542 if (b2 >= count)
eric@67 543 c2 = count;
eric@67 544 else
eric@67 545 c2 = b2;
eric@67 546 d2 = bits >> (count - c2);
eric@67 547 s->data [s->byte_idx] |= (d2 << (b2 + c2));
eric@67 548 s->bit_idx += c2;
eric@67 549 if (s->bit_idx > 7)
eric@67 550 pdf_stream_advance_byte (pdf_file, stream);
eric@67 551 count -= c2;
eric@67 552 }
eric@67 553 }
eric@67 554
eric@67 555
eric@66 556 void pdf_stream_printf (pdf_file_handle pdf_file,
eric@66 557 struct pdf_obj *stream,
eric@66 558 char *fmt, ...)
eric@66 559 {
eric@66 560 va_list ap;
eric@66 561
eric@66 562 va_start (ap, fmt);
eric@66 563 vfprintf (pdf_file->f, fmt, ap);
eric@66 564 va_end (ap);
eric@66 565 }
eric@66 566
eric@66 567
eric@59 568 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
eric@59 569 {
eric@59 570 unsigned long begin_pos, end_pos;
eric@59 571
eric@59 572 pdf_assert (stream->type == PT_STREAM);
eric@59 573
eric@59 574 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
eric@59 575 fprintf (pdf_file->f, "stream\r\n");
eric@59 576 begin_pos = ftell (pdf_file->f);
eric@59 577 stream->val.stream.callback (pdf_file,
eric@59 578 stream,
eric@59 579 stream->val.stream.app_data);
eric@59 580 end_pos = ftell (pdf_file->f);
eric@59 581 fprintf (pdf_file->f, "\r\nendstream\r\n");
eric@59 582
eric@59 583 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
eric@59 584 }
eric@59 585
eric@59 586
eric@59 587 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 588 {
eric@59 589 switch (obj->type)
eric@59 590 {
eric@59 591 case PT_NULL:
eric@59 592 fprintf (pdf_file->f, "null ");
eric@59 593 break;
eric@59 594 case PT_BOOL:
eric@62 595 if (obj->val.boolean)
eric@59 596 fprintf (pdf_file->f, "true ");
eric@59 597 else
eric@59 598 fprintf (pdf_file->f, "false ");
eric@59 599 break;
eric@59 600 case PT_NAME:
eric@59 601 pdf_write_name (pdf_file, obj->val.name);
eric@59 602 break;
eric@59 603 case PT_STRING:
eric@59 604 pdf_write_string (pdf_file, obj->val.string);
eric@59 605 break;
eric@59 606 case PT_INTEGER:
eric@59 607 fprintf (pdf_file->f, "%ld ", obj->val.integer);
eric@59 608 break;
eric@59 609 case PT_REAL:
eric@59 610 pdf_write_real (pdf_file, obj->val.real);
eric@59 611 break;
eric@59 612 case PT_IND_REF:
eric@59 613 pdf_write_ind_ref (pdf_file, obj);
eric@59 614 break;
eric@59 615 case PT_DICTIONARY:
eric@59 616 pdf_write_dict (pdf_file, obj);
eric@59 617 break;
eric@59 618 case PT_ARRAY:
eric@59 619 pdf_write_array (pdf_file, obj);
eric@59 620 break;
eric@59 621 case PT_STREAM:
eric@59 622 pdf_write_stream (pdf_file, obj);
eric@59 623 break;
eric@59 624 default:
eric@59 625 pdf_fatal ("bad object type\n");
eric@59 626 }
eric@59 627 }
eric@59 628
eric@59 629
eric@59 630 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 631 {
eric@59 632 struct pdf_obj *obj;
eric@59 633
eric@59 634 if (ind_obj->type == PT_IND_REF)
eric@59 635 obj = pdf_deref_ind_obj (ind_obj);
eric@59 636 else
eric@59 637 obj = ind_obj;
eric@59 638
eric@59 639 obj->file_offset = ftell (pdf_file->f);
eric@59 640 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
eric@59 641 pdf_write_obj (pdf_file, obj);
eric@59 642 fprintf (pdf_file->f, "endobj\r\n");
eric@59 643 }
eric@59 644
eric@59 645
eric@59 646 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
eric@59 647 {
eric@59 648 struct pdf_obj *ind_obj;
eric@59 649 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 650 if (! ind_obj->file_offset)
eric@59 651 pdf_write_ind_obj (pdf_file, ind_obj);
eric@59 652 }
eric@59 653
eric@59 654
eric@59 655 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
eric@59 656 {
eric@59 657 struct pdf_obj *ind_obj;
eric@59 658 pdf_file->xref_offset = ftell (pdf_file->f);
eric@59 659 fprintf (pdf_file->f, "xref\r\n");
eric@59 660 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
eric@59 661 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
eric@59 662 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 663 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
eric@59 664 return (pdf_file->last_ind_obj->obj_num + 1);
eric@59 665 }
eric@59 666
eric@59 667