pdf_prim.c

Thu, 20 Feb 2003 12:20:28 +0000

author
eric
date
Thu, 20 Feb 2003 12:20:28 +0000
changeset 60
ffb5b1e54eb2
parent 59
e8821eb2fb08
child 62
9bd354b83e16
permissions
-rw-r--r--

fix includes.

eric@59 1 #include <stdio.h>
eric@59 2 #include <stdlib.h>
eric@59 3 #include <string.h>
eric@59 4
eric@60 5 #include "pdf.h"
eric@60 6 #include "pdf_util.h"
eric@60 7 #include "pdf_prim.h"
eric@60 8 #include "pdf_private.h"
eric@59 9
eric@59 10
eric@59 11 struct pdf_array_elem
eric@59 12 {
eric@59 13 struct pdf_array_elem *next;
eric@59 14 struct pdf_obj *val;
eric@59 15 };
eric@59 16
eric@59 17
eric@59 18 struct pdf_array
eric@59 19 {
eric@59 20 struct pdf_array_elem *first;
eric@59 21 struct pdf_array_elem *last;
eric@59 22 };
eric@59 23
eric@59 24
eric@59 25 struct pdf_dict_entry
eric@59 26 {
eric@59 27 struct pdf_dict_entry *next;
eric@59 28 char *key;
eric@59 29 struct pdf_obj *val;
eric@59 30 };
eric@59 31
eric@59 32
eric@59 33 struct pdf_dict
eric@59 34 {
eric@59 35 struct pdf_dict_entry *first;
eric@59 36 };
eric@59 37
eric@59 38
eric@59 39 struct pdf_stream
eric@59 40 {
eric@59 41 struct pdf_obj *stream_dict;
eric@59 42 struct pdf_obj *length;
eric@59 43 pdf_stream_write_callback callback;
eric@59 44 void *app_data; /* arg to pass to callback */
eric@59 45 struct pdf_obj *filters; /* name or array of names */
eric@59 46 struct pdf_obj *decode_parms;
eric@59 47 };
eric@59 48
eric@59 49
eric@59 50 struct pdf_obj
eric@59 51 {
eric@59 52 /* these fields only apply to indirectly referenced objects */
eric@59 53 struct pdf_obj *prev;
eric@59 54 struct pdf_obj *next;
eric@59 55 unsigned long obj_num;
eric@59 56 unsigned long obj_gen;
eric@59 57 long int file_offset;
eric@59 58
eric@59 59 /* these fields apply to all objects */
eric@59 60 unsigned long ref_count;
eric@59 61 pdf_obj_type type;
eric@59 62 union {
eric@59 63 int bool;
eric@59 64 char *name;
eric@59 65 char *string;
eric@59 66 unsigned long integer;
eric@59 67 double real;
eric@59 68 struct pdf_obj *ind_ref;
eric@59 69 struct pdf_dict dict;
eric@59 70 struct pdf_array array;
eric@59 71 struct pdf_stream stream;
eric@59 72 } val;
eric@59 73 };
eric@59 74
eric@59 75
eric@59 76 struct pdf_obj *ref (struct pdf_obj *obj)
eric@59 77 {
eric@59 78 obj->ref_count++;
eric@59 79 return (obj);
eric@59 80 }
eric@59 81
eric@59 82
eric@59 83 void unref (struct pdf_obj *obj)
eric@59 84 {
eric@59 85 if ((--obj->ref_count) == 0)
eric@59 86 {
eric@59 87 /* $$$ free the object */
eric@59 88 }
eric@59 89 }
eric@59 90
eric@59 91
eric@59 92 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
eric@59 93 {
eric@59 94 pdf_assert (ind_obj->type == PT_IND_REF);
eric@59 95 return (ind_obj->val.ind_ref);
eric@59 96 }
eric@59 97
eric@59 98
eric@59 99 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
eric@59 100 {
eric@59 101 struct pdf_dict_entry *entry;
eric@59 102
eric@59 103 if (dict_obj->type == PT_IND_REF)
eric@59 104 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 105
eric@59 106 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 107
eric@59 108 /* replacing existing entry? */
eric@59 109 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 110 if (strcmp (entry->key, key) == 0)
eric@59 111 {
eric@59 112 unref (entry->val);
eric@59 113 entry->val = ref (val);
eric@59 114 return;
eric@59 115 }
eric@59 116
eric@59 117 /* new entry */
eric@59 118 entry = pdf_calloc (sizeof (struct pdf_dict_entry));
eric@59 119
eric@59 120 entry->next = dict_obj->val.dict.first;
eric@59 121 dict_obj->val.dict.first = entry;
eric@59 122
eric@59 123 entry->key = pdf_strdup (key);
eric@59 124 entry->val = ref (val);
eric@59 125 }
eric@59 126
eric@59 127
eric@59 128 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
eric@59 129 {
eric@59 130 struct pdf_dict_entry *entry;
eric@59 131
eric@59 132 if (dict_obj->type == PT_IND_REF)
eric@59 133 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 134
eric@59 135 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 136
eric@59 137 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 138 if (strcmp (entry->key, key) == 0)
eric@59 139 return (entry->val);
eric@59 140
eric@59 141 return (NULL);
eric@59 142 }
eric@59 143
eric@59 144
eric@59 145 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
eric@59 146 {
eric@59 147 struct pdf_array_elem *elem = pdf_calloc (sizeof (struct pdf_array_elem));
eric@59 148
eric@59 149 if (array_obj->type == PT_IND_REF)
eric@59 150 array_obj = pdf_deref_ind_obj (array_obj);
eric@59 151
eric@59 152 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 153
eric@59 154 elem->val = ref (val);
eric@59 155
eric@59 156 if (! array_obj->val.array.first)
eric@59 157 array_obj->val.array.first = elem;
eric@59 158 else
eric@59 159 array_obj->val.array.last->next = elem;
eric@59 160
eric@59 161 array_obj->val.array.last = elem;
eric@59 162 }
eric@59 163
eric@59 164
eric@59 165 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
eric@59 166 {
eric@59 167 struct pdf_obj *obj = pdf_calloc (sizeof (struct pdf_obj));
eric@59 168 obj->type = type;
eric@59 169 return (obj);
eric@59 170 }
eric@59 171
eric@59 172
eric@59 173 struct pdf_obj *pdf_new_bool (int bool)
eric@59 174 {
eric@59 175 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
eric@59 176 obj->val.bool = bool;
eric@59 177 return (obj);
eric@59 178 }
eric@59 179
eric@59 180
eric@59 181 struct pdf_obj *pdf_new_name (char *name)
eric@59 182 {
eric@59 183 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
eric@59 184 obj->val.name = pdf_strdup (name);
eric@59 185 return (obj);
eric@59 186 }
eric@59 187
eric@59 188
eric@59 189 struct pdf_obj *pdf_new_string (char *str)
eric@59 190 {
eric@59 191 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
eric@59 192 obj->val.string = pdf_strdup (str);
eric@59 193 return (obj);
eric@59 194 }
eric@59 195
eric@59 196
eric@59 197 struct pdf_obj *pdf_new_integer (unsigned long val)
eric@59 198 {
eric@59 199 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
eric@59 200 obj->val.integer = val;
eric@59 201 return (obj);
eric@59 202 }
eric@59 203
eric@59 204
eric@59 205 struct pdf_obj *pdf_new_real (double val)
eric@59 206 {
eric@59 207 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
eric@59 208 obj->val.real = val;
eric@59 209 return (obj);
eric@59 210 }
eric@59 211
eric@59 212
eric@59 213 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
eric@59 214 struct pdf_obj *stream_dict,
eric@59 215 pdf_stream_write_callback callback,
eric@59 216 void *app_data)
eric@59 217 {
eric@59 218 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
eric@59 219
eric@59 220 obj->val.stream.stream_dict = stream_dict;
eric@59 221 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
eric@59 222 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
eric@59 223
eric@59 224 obj->val.stream.callback = callback;
eric@59 225 obj->val.stream.app_data = app_data;
eric@59 226 return (obj);
eric@59 227 }
eric@59 228
eric@59 229
eric@59 230 /* $$$ currently limited to one filter per stream */
eric@59 231 void pdf_stream_add_filter (struct pdf_obj *stream,
eric@59 232 char *filter_name,
eric@59 233 struct pdf_obj *decode_parms)
eric@59 234 {
eric@59 235 if (stream->type == PT_IND_REF)
eric@59 236 stream = pdf_deref_ind_obj (stream);
eric@59 237
eric@59 238 pdf_assert (stream->type == PT_STREAM);
eric@59 239
eric@59 240 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
eric@59 241 if (decode_parms)
eric@59 242 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
eric@59 243 }
eric@59 244
eric@59 245
eric@59 246 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 247 {
eric@59 248 struct pdf_obj *ind_obj;
eric@59 249
eric@59 250 pdf_assert (obj->type != PT_IND_REF);
eric@59 251
eric@59 252 ind_obj = pdf_new_obj (PT_IND_REF);
eric@59 253
eric@59 254 ind_obj->type = PT_IND_REF;
eric@59 255 ind_obj->val.ind_ref = obj;
eric@59 256
eric@59 257 /* is there already an indirect reference to this object? */
eric@59 258 if (! obj->obj_num)
eric@59 259 {
eric@59 260 /* no, assign object number/generation and add to linked list */
eric@59 261 if (! pdf_file->first_ind_obj)
eric@59 262 {
eric@59 263 obj->obj_num = 1;
eric@59 264 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
eric@59 265 }
eric@59 266 else
eric@59 267 {
eric@59 268 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
eric@59 269 pdf_file->last_ind_obj->next = obj;
eric@59 270 obj->prev = pdf_file->last_ind_obj;
eric@59 271 pdf_file->last_ind_obj = obj;
eric@59 272 }
eric@59 273 }
eric@59 274
eric@59 275 return (ind_obj);
eric@59 276 }
eric@59 277
eric@59 278
eric@59 279 unsigned long pdf_get_integer (struct pdf_obj *obj)
eric@59 280 {
eric@59 281 if (obj->type == PT_IND_REF)
eric@59 282 obj = pdf_deref_ind_obj (obj);
eric@59 283
eric@59 284 pdf_assert (obj->type == PT_INTEGER);
eric@59 285
eric@59 286 return (obj->val.integer);
eric@59 287 }
eric@59 288
eric@59 289 void pdf_set_integer (struct pdf_obj *obj, unsigned long val)
eric@59 290 {
eric@59 291 if (obj->type == PT_IND_REF)
eric@59 292 obj = pdf_deref_ind_obj (obj);
eric@59 293
eric@59 294 pdf_assert (obj->type == PT_INTEGER);
eric@59 295
eric@59 296 obj->val.integer = val;
eric@59 297 }
eric@59 298
eric@59 299
eric@59 300 double pdf_get_real (struct pdf_obj *obj)
eric@59 301 {
eric@59 302 if (obj->type == PT_IND_REF)
eric@59 303 obj = pdf_deref_ind_obj (obj);
eric@59 304
eric@59 305 pdf_assert (obj->type == PT_REAL);
eric@59 306
eric@59 307 return (obj->val.real);
eric@59 308 }
eric@59 309
eric@59 310 void pdf_set_real (struct pdf_obj *obj, double val)
eric@59 311 {
eric@59 312 if (obj->type == PT_IND_REF)
eric@59 313 obj = pdf_deref_ind_obj (obj);
eric@59 314
eric@59 315 pdf_assert (obj->type == PT_REAL);
eric@59 316
eric@59 317 obj->val.real = val;
eric@59 318 }
eric@59 319
eric@59 320
eric@59 321 static int name_char_needs_quoting (char c)
eric@59 322 {
eric@59 323 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
eric@59 324 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
eric@59 325 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
eric@59 326 (c == '%'));
eric@59 327 }
eric@59 328
eric@59 329
eric@59 330 void pdf_write_name (pdf_file_handle pdf_file, char *s)
eric@59 331 {
eric@59 332 fprintf (pdf_file->f, "/");
eric@59 333 while (*s)
eric@59 334 if (name_char_needs_quoting (*s))
eric@59 335 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
eric@59 336 else
eric@59 337 fprintf (pdf_file->f, "%c", *(s++));
eric@59 338 fprintf (pdf_file->f, " ");
eric@59 339 }
eric@59 340
eric@59 341
eric@59 342 static int string_char_needs_quoting (char c)
eric@59 343 {
eric@59 344 return ((c < ' ') || (c > '~') || (c == '\\') ||
eric@59 345 (c == '(') || (c == ')'));
eric@59 346 }
eric@59 347
eric@59 348
eric@59 349 void pdf_write_string (pdf_file_handle pdf_file, char *s)
eric@59 350 {
eric@59 351 fprintf (pdf_file->f, "(");
eric@59 352 while (*s)
eric@59 353 if (string_char_needs_quoting (*s))
eric@59 354 fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
eric@59 355 else
eric@59 356 fprintf (pdf_file->f, "%c", *(s++));
eric@59 357 fprintf (pdf_file->f, ") ");
eric@59 358 }
eric@59 359
eric@59 360
eric@59 361 void pdf_write_real (pdf_file_handle pdf_file, double num)
eric@59 362 {
eric@59 363 /* $$$ not actually good enough, precision needs to be variable,
eric@59 364 and no exponent is allowed */
eric@59 365 fprintf (pdf_file->f, "%0f ", num);
eric@59 366 }
eric@59 367
eric@59 368
eric@59 369 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 370 {
eric@59 371 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
eric@59 372 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
eric@59 373 }
eric@59 374
eric@59 375
eric@59 376 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
eric@59 377 {
eric@59 378 struct pdf_array_elem *elem;
eric@59 379
eric@59 380 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 381
eric@59 382 fprintf (pdf_file->f, "[ ");
eric@59 383 for (elem = array_obj->val.array.first; elem; elem = elem->next)
eric@59 384 {
eric@59 385 pdf_write_obj (pdf_file, elem->val);
eric@59 386 fprintf (pdf_file->f, " ");
eric@59 387 }
eric@59 388 fprintf (pdf_file->f, "] ");
eric@59 389 }
eric@59 390
eric@59 391
eric@59 392 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
eric@59 393 {
eric@59 394 struct pdf_dict_entry *entry;
eric@59 395
eric@59 396 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 397
eric@59 398 fprintf (pdf_file->f, "<<\r\n");
eric@59 399 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 400 {
eric@59 401 pdf_write_name (pdf_file, entry->key);
eric@59 402 fprintf (pdf_file->f, " ");
eric@59 403 pdf_write_obj (pdf_file, entry->val);
eric@59 404 fprintf (pdf_file->f, "\r\n");
eric@59 405 }
eric@59 406 fprintf (pdf_file->f, ">>\r\n");
eric@59 407 }
eric@59 408
eric@59 409
eric@59 410 void pdf_stream_write_data (pdf_file_handle pdf_file,
eric@59 411 struct pdf_obj *stream,
eric@59 412 char *data,
eric@59 413 unsigned long len)
eric@59 414 {
eric@59 415 while (len)
eric@59 416 {
eric@59 417 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
eric@59 418 data += l2;
eric@59 419 len -= l2;
eric@59 420 if (ferror (pdf_file->f))
eric@59 421 pdf_fatal ("error writing stream data\n");
eric@59 422 }
eric@59 423 }
eric@59 424
eric@59 425
eric@59 426 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
eric@59 427 {
eric@59 428 unsigned long begin_pos, end_pos;
eric@59 429
eric@59 430 pdf_assert (stream->type == PT_STREAM);
eric@59 431
eric@59 432 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
eric@59 433 fprintf (pdf_file->f, "stream\r\n");
eric@59 434 begin_pos = ftell (pdf_file->f);
eric@59 435 stream->val.stream.callback (pdf_file,
eric@59 436 stream,
eric@59 437 stream->val.stream.app_data);
eric@59 438 end_pos = ftell (pdf_file->f);
eric@59 439 fprintf (pdf_file->f, "\r\nendstream\r\n");
eric@59 440
eric@59 441 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
eric@59 442 }
eric@59 443
eric@59 444
eric@59 445 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 446 {
eric@59 447 switch (obj->type)
eric@59 448 {
eric@59 449 case PT_NULL:
eric@59 450 fprintf (pdf_file->f, "null ");
eric@59 451 break;
eric@59 452 case PT_BOOL:
eric@59 453 if (obj->val.bool)
eric@59 454 fprintf (pdf_file->f, "true ");
eric@59 455 else
eric@59 456 fprintf (pdf_file->f, "false ");
eric@59 457 break;
eric@59 458 case PT_NAME:
eric@59 459 pdf_write_name (pdf_file, obj->val.name);
eric@59 460 break;
eric@59 461 case PT_STRING:
eric@59 462 pdf_write_string (pdf_file, obj->val.string);
eric@59 463 break;
eric@59 464 case PT_INTEGER:
eric@59 465 fprintf (pdf_file->f, "%ld ", obj->val.integer);
eric@59 466 break;
eric@59 467 case PT_REAL:
eric@59 468 pdf_write_real (pdf_file, obj->val.real);
eric@59 469 break;
eric@59 470 case PT_IND_REF:
eric@59 471 pdf_write_ind_ref (pdf_file, obj);
eric@59 472 break;
eric@59 473 case PT_DICTIONARY:
eric@59 474 pdf_write_dict (pdf_file, obj);
eric@59 475 break;
eric@59 476 case PT_ARRAY:
eric@59 477 pdf_write_array (pdf_file, obj);
eric@59 478 break;
eric@59 479 case PT_STREAM:
eric@59 480 pdf_write_stream (pdf_file, obj);
eric@59 481 break;
eric@59 482 default:
eric@59 483 pdf_fatal ("bad object type\n");
eric@59 484 }
eric@59 485 }
eric@59 486
eric@59 487
eric@59 488 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 489 {
eric@59 490 struct pdf_obj *obj;
eric@59 491
eric@59 492 if (ind_obj->type == PT_IND_REF)
eric@59 493 obj = pdf_deref_ind_obj (ind_obj);
eric@59 494 else
eric@59 495 obj = ind_obj;
eric@59 496
eric@59 497 obj->file_offset = ftell (pdf_file->f);
eric@59 498 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
eric@59 499 pdf_write_obj (pdf_file, obj);
eric@59 500 fprintf (pdf_file->f, "endobj\r\n");
eric@59 501 }
eric@59 502
eric@59 503
eric@59 504 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
eric@59 505 {
eric@59 506 struct pdf_obj *ind_obj;
eric@59 507 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 508 if (! ind_obj->file_offset)
eric@59 509 pdf_write_ind_obj (pdf_file, ind_obj);
eric@59 510 }
eric@59 511
eric@59 512
eric@59 513 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
eric@59 514 {
eric@59 515 struct pdf_obj *ind_obj;
eric@59 516 pdf_file->xref_offset = ftell (pdf_file->f);
eric@59 517 fprintf (pdf_file->f, "xref\r\n");
eric@59 518 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
eric@59 519 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
eric@59 520 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 521 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
eric@59 522 return (pdf_file->last_ind_obj->obj_num + 1);
eric@59 523 }
eric@59 524
eric@59 525