1.1 diff -r d1c6dc4bf34a -r e8821eb2fb08 pdf_prim.c 1.2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 +++ b/pdf_prim.c Thu Feb 20 12:16:00 2003 +0000 1.4 @@ -0,0 +1,525 @@ 1.5 +#include <stdio.h> 1.6 +#include <stdlib.h> 1.7 +#include <string.h> 1.8 + 1.9 +#include "libpdf.h" 1.10 +#include "libpdf_util.h" 1.11 +#include "libpdf_prim.h" 1.12 +#include "libpdf_private.h" 1.13 + 1.14 + 1.15 +struct pdf_array_elem 1.16 +{ 1.17 + struct pdf_array_elem *next; 1.18 + struct pdf_obj *val; 1.19 +}; 1.20 + 1.21 + 1.22 +struct pdf_array 1.23 +{ 1.24 + struct pdf_array_elem *first; 1.25 + struct pdf_array_elem *last; 1.26 +}; 1.27 + 1.28 + 1.29 +struct pdf_dict_entry 1.30 +{ 1.31 + struct pdf_dict_entry *next; 1.32 + char *key; 1.33 + struct pdf_obj *val; 1.34 +}; 1.35 + 1.36 + 1.37 +struct pdf_dict 1.38 +{ 1.39 + struct pdf_dict_entry *first; 1.40 +}; 1.41 + 1.42 + 1.43 +struct pdf_stream 1.44 +{ 1.45 + struct pdf_obj *stream_dict; 1.46 + struct pdf_obj *length; 1.47 + pdf_stream_write_callback callback; 1.48 + void *app_data; /* arg to pass to callback */ 1.49 + struct pdf_obj *filters; /* name or array of names */ 1.50 + struct pdf_obj *decode_parms; 1.51 +}; 1.52 + 1.53 + 1.54 +struct pdf_obj 1.55 +{ 1.56 + /* these fields only apply to indirectly referenced objects */ 1.57 + struct pdf_obj *prev; 1.58 + struct pdf_obj *next; 1.59 + unsigned long obj_num; 1.60 + unsigned long obj_gen; 1.61 + long int file_offset; 1.62 + 1.63 + /* these fields apply to all objects */ 1.64 + unsigned long ref_count; 1.65 + pdf_obj_type type; 1.66 + union { 1.67 + int bool; 1.68 + char *name; 1.69 + char *string; 1.70 + unsigned long integer; 1.71 + double real; 1.72 + struct pdf_obj *ind_ref; 1.73 + struct pdf_dict dict; 1.74 + struct pdf_array array; 1.75 + struct pdf_stream stream; 1.76 + } val; 1.77 +}; 1.78 + 1.79 + 1.80 +struct pdf_obj *ref (struct pdf_obj *obj) 1.81 +{ 1.82 + obj->ref_count++; 1.83 + return (obj); 1.84 +} 1.85 + 1.86 + 1.87 +void unref (struct pdf_obj *obj) 1.88 +{ 1.89 + if ((--obj->ref_count) == 0) 1.90 + { 1.91 + /* $$$ free the object */ 1.92 + } 1.93 +} 1.94 + 1.95 + 1.96 +struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj) 1.97 +{ 1.98 + pdf_assert (ind_obj->type == PT_IND_REF); 1.99 + return (ind_obj->val.ind_ref); 1.100 +} 1.101 + 1.102 + 1.103 +void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val) 1.104 +{ 1.105 + struct pdf_dict_entry *entry; 1.106 + 1.107 + if (dict_obj->type == PT_IND_REF) 1.108 + dict_obj = pdf_deref_ind_obj (dict_obj); 1.109 + 1.110 + pdf_assert (dict_obj->type == PT_DICTIONARY); 1.111 + 1.112 + /* replacing existing entry? */ 1.113 + for (entry = dict_obj->val.dict.first; entry; entry = entry->next) 1.114 + if (strcmp (entry->key, key) == 0) 1.115 + { 1.116 + unref (entry->val); 1.117 + entry->val = ref (val); 1.118 + return; 1.119 + } 1.120 + 1.121 + /* new entry */ 1.122 + entry = pdf_calloc (sizeof (struct pdf_dict_entry)); 1.123 + 1.124 + entry->next = dict_obj->val.dict.first; 1.125 + dict_obj->val.dict.first = entry; 1.126 + 1.127 + entry->key = pdf_strdup (key); 1.128 + entry->val = ref (val); 1.129 +} 1.130 + 1.131 + 1.132 +struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key) 1.133 +{ 1.134 + struct pdf_dict_entry *entry; 1.135 + 1.136 + if (dict_obj->type == PT_IND_REF) 1.137 + dict_obj = pdf_deref_ind_obj (dict_obj); 1.138 + 1.139 + pdf_assert (dict_obj->type == PT_DICTIONARY); 1.140 + 1.141 + for (entry = dict_obj->val.dict.first; entry; entry = entry->next) 1.142 + if (strcmp (entry->key, key) == 0) 1.143 + return (entry->val); 1.144 + 1.145 + return (NULL); 1.146 +} 1.147 + 1.148 + 1.149 +void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val) 1.150 +{ 1.151 + struct pdf_array_elem *elem = pdf_calloc (sizeof (struct pdf_array_elem)); 1.152 + 1.153 + if (array_obj->type == PT_IND_REF) 1.154 + array_obj = pdf_deref_ind_obj (array_obj); 1.155 + 1.156 + pdf_assert (array_obj->type == PT_ARRAY); 1.157 + 1.158 + elem->val = ref (val); 1.159 + 1.160 + if (! array_obj->val.array.first) 1.161 + array_obj->val.array.first = elem; 1.162 + else 1.163 + array_obj->val.array.last->next = elem; 1.164 + 1.165 + array_obj->val.array.last = elem; 1.166 +} 1.167 + 1.168 + 1.169 +struct pdf_obj *pdf_new_obj (pdf_obj_type type) 1.170 +{ 1.171 + struct pdf_obj *obj = pdf_calloc (sizeof (struct pdf_obj)); 1.172 + obj->type = type; 1.173 + return (obj); 1.174 +} 1.175 + 1.176 + 1.177 +struct pdf_obj *pdf_new_bool (int bool) 1.178 +{ 1.179 + struct pdf_obj *obj = pdf_new_obj (PT_BOOL); 1.180 + obj->val.bool = bool; 1.181 + return (obj); 1.182 +} 1.183 + 1.184 + 1.185 +struct pdf_obj *pdf_new_name (char *name) 1.186 +{ 1.187 + struct pdf_obj *obj = pdf_new_obj (PT_NAME); 1.188 + obj->val.name = pdf_strdup (name); 1.189 + return (obj); 1.190 +} 1.191 + 1.192 + 1.193 +struct pdf_obj *pdf_new_string (char *str) 1.194 +{ 1.195 + struct pdf_obj *obj = pdf_new_obj (PT_STRING); 1.196 + obj->val.string = pdf_strdup (str); 1.197 + return (obj); 1.198 +} 1.199 + 1.200 + 1.201 +struct pdf_obj *pdf_new_integer (unsigned long val) 1.202 +{ 1.203 + struct pdf_obj *obj = pdf_new_obj (PT_INTEGER); 1.204 + obj->val.integer = val; 1.205 + return (obj); 1.206 +} 1.207 + 1.208 + 1.209 +struct pdf_obj *pdf_new_real (double val) 1.210 +{ 1.211 + struct pdf_obj *obj = pdf_new_obj (PT_REAL); 1.212 + obj->val.real = val; 1.213 + return (obj); 1.214 +} 1.215 + 1.216 + 1.217 +struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file, 1.218 + struct pdf_obj *stream_dict, 1.219 + pdf_stream_write_callback callback, 1.220 + void *app_data) 1.221 +{ 1.222 + struct pdf_obj *obj = pdf_new_obj (PT_STREAM); 1.223 + 1.224 + obj->val.stream.stream_dict = stream_dict; 1.225 + obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0)); 1.226 + pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length); 1.227 + 1.228 + obj->val.stream.callback = callback; 1.229 + obj->val.stream.app_data = app_data; 1.230 + return (obj); 1.231 +} 1.232 + 1.233 + 1.234 +/* $$$ currently limited to one filter per stream */ 1.235 +void pdf_stream_add_filter (struct pdf_obj *stream, 1.236 + char *filter_name, 1.237 + struct pdf_obj *decode_parms) 1.238 +{ 1.239 + if (stream->type == PT_IND_REF) 1.240 + stream = pdf_deref_ind_obj (stream); 1.241 + 1.242 + pdf_assert (stream->type == PT_STREAM); 1.243 + 1.244 + pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name)); 1.245 + if (decode_parms) 1.246 + pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms); 1.247 +} 1.248 + 1.249 + 1.250 +struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj) 1.251 +{ 1.252 + struct pdf_obj *ind_obj; 1.253 + 1.254 + pdf_assert (obj->type != PT_IND_REF); 1.255 + 1.256 + ind_obj = pdf_new_obj (PT_IND_REF); 1.257 + 1.258 + ind_obj->type = PT_IND_REF; 1.259 + ind_obj->val.ind_ref = obj; 1.260 + 1.261 + /* is there already an indirect reference to this object? */ 1.262 + if (! obj->obj_num) 1.263 + { 1.264 + /* no, assign object number/generation and add to linked list */ 1.265 + if (! pdf_file->first_ind_obj) 1.266 + { 1.267 + obj->obj_num = 1; 1.268 + pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj; 1.269 + } 1.270 + else 1.271 + { 1.272 + obj->obj_num = pdf_file->last_ind_obj->obj_num + 1; 1.273 + pdf_file->last_ind_obj->next = obj; 1.274 + obj->prev = pdf_file->last_ind_obj; 1.275 + pdf_file->last_ind_obj = obj; 1.276 + } 1.277 + } 1.278 + 1.279 + return (ind_obj); 1.280 +} 1.281 + 1.282 + 1.283 +unsigned long pdf_get_integer (struct pdf_obj *obj) 1.284 +{ 1.285 + if (obj->type == PT_IND_REF) 1.286 + obj = pdf_deref_ind_obj (obj); 1.287 + 1.288 + pdf_assert (obj->type == PT_INTEGER); 1.289 + 1.290 + return (obj->val.integer); 1.291 +} 1.292 + 1.293 +void pdf_set_integer (struct pdf_obj *obj, unsigned long val) 1.294 +{ 1.295 + if (obj->type == PT_IND_REF) 1.296 + obj = pdf_deref_ind_obj (obj); 1.297 + 1.298 + pdf_assert (obj->type == PT_INTEGER); 1.299 + 1.300 + obj->val.integer = val; 1.301 +} 1.302 + 1.303 + 1.304 +double pdf_get_real (struct pdf_obj *obj) 1.305 +{ 1.306 + if (obj->type == PT_IND_REF) 1.307 + obj = pdf_deref_ind_obj (obj); 1.308 + 1.309 + pdf_assert (obj->type == PT_REAL); 1.310 + 1.311 + return (obj->val.real); 1.312 +} 1.313 + 1.314 +void pdf_set_real (struct pdf_obj *obj, double val) 1.315 +{ 1.316 + if (obj->type == PT_IND_REF) 1.317 + obj = pdf_deref_ind_obj (obj); 1.318 + 1.319 + pdf_assert (obj->type == PT_REAL); 1.320 + 1.321 + obj->val.real = val; 1.322 +} 1.323 + 1.324 + 1.325 +static int name_char_needs_quoting (char c) 1.326 +{ 1.327 + return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') || 1.328 + (c == '(') || (c == ')') || (c == '<') || (c == '>') || 1.329 + (c == '[') || (c == ']') || (c == '{') || (c == '}') || 1.330 + (c == '%')); 1.331 +} 1.332 + 1.333 + 1.334 +void pdf_write_name (pdf_file_handle pdf_file, char *s) 1.335 +{ 1.336 + fprintf (pdf_file->f, "/"); 1.337 + while (*s) 1.338 + if (name_char_needs_quoting (*s)) 1.339 + fprintf (pdf_file->f, "#%02x", 0xff & *(s++)); 1.340 + else 1.341 + fprintf (pdf_file->f, "%c", *(s++)); 1.342 + fprintf (pdf_file->f, " "); 1.343 +} 1.344 + 1.345 + 1.346 +static int string_char_needs_quoting (char c) 1.347 +{ 1.348 + return ((c < ' ') || (c > '~') || (c == '\\') || 1.349 + (c == '(') || (c == ')')); 1.350 +} 1.351 + 1.352 + 1.353 +void pdf_write_string (pdf_file_handle pdf_file, char *s) 1.354 +{ 1.355 + fprintf (pdf_file->f, "("); 1.356 + while (*s) 1.357 + if (string_char_needs_quoting (*s)) 1.358 + fprintf (pdf_file->f, "\\%03o", 0xff & *(s++)); 1.359 + else 1.360 + fprintf (pdf_file->f, "%c", *(s++)); 1.361 + fprintf (pdf_file->f, ") "); 1.362 +} 1.363 + 1.364 + 1.365 +void pdf_write_real (pdf_file_handle pdf_file, double num) 1.366 +{ 1.367 + /* $$$ not actually good enough, precision needs to be variable, 1.368 + and no exponent is allowed */ 1.369 + fprintf (pdf_file->f, "%0f ", num); 1.370 +} 1.371 + 1.372 + 1.373 +void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj) 1.374 +{ 1.375 + struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj); 1.376 + fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen); 1.377 +} 1.378 + 1.379 + 1.380 +void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj) 1.381 +{ 1.382 + struct pdf_array_elem *elem; 1.383 + 1.384 + pdf_assert (array_obj->type == PT_ARRAY); 1.385 + 1.386 + fprintf (pdf_file->f, "[ "); 1.387 + for (elem = array_obj->val.array.first; elem; elem = elem->next) 1.388 + { 1.389 + pdf_write_obj (pdf_file, elem->val); 1.390 + fprintf (pdf_file->f, " "); 1.391 + } 1.392 + fprintf (pdf_file->f, "] "); 1.393 +} 1.394 + 1.395 + 1.396 +void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj) 1.397 +{ 1.398 + struct pdf_dict_entry *entry; 1.399 + 1.400 + pdf_assert (dict_obj->type == PT_DICTIONARY); 1.401 + 1.402 + fprintf (pdf_file->f, "<<\r\n"); 1.403 + for (entry = dict_obj->val.dict.first; entry; entry = entry->next) 1.404 + { 1.405 + pdf_write_name (pdf_file, entry->key); 1.406 + fprintf (pdf_file->f, " "); 1.407 + pdf_write_obj (pdf_file, entry->val); 1.408 + fprintf (pdf_file->f, "\r\n"); 1.409 + } 1.410 + fprintf (pdf_file->f, ">>\r\n"); 1.411 +} 1.412 + 1.413 + 1.414 +void pdf_stream_write_data (pdf_file_handle pdf_file, 1.415 + struct pdf_obj *stream, 1.416 + char *data, 1.417 + unsigned long len) 1.418 +{ 1.419 + while (len) 1.420 + { 1.421 + unsigned long l2 = fwrite (data, 1, len, pdf_file->f); 1.422 + data += l2; 1.423 + len -= l2; 1.424 + if (ferror (pdf_file->f)) 1.425 + pdf_fatal ("error writing stream data\n"); 1.426 + } 1.427 +} 1.428 + 1.429 + 1.430 +void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream) 1.431 +{ 1.432 + unsigned long begin_pos, end_pos; 1.433 + 1.434 + pdf_assert (stream->type == PT_STREAM); 1.435 + 1.436 + pdf_write_dict (pdf_file, stream->val.stream.stream_dict); 1.437 + fprintf (pdf_file->f, "stream\r\n"); 1.438 + begin_pos = ftell (pdf_file->f); 1.439 + stream->val.stream.callback (pdf_file, 1.440 + stream, 1.441 + stream->val.stream.app_data); 1.442 + end_pos = ftell (pdf_file->f); 1.443 + fprintf (pdf_file->f, "\r\nendstream\r\n"); 1.444 + 1.445 + pdf_set_integer (stream->val.stream.length, end_pos - begin_pos); 1.446 +} 1.447 + 1.448 + 1.449 +void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj) 1.450 +{ 1.451 + switch (obj->type) 1.452 + { 1.453 + case PT_NULL: 1.454 + fprintf (pdf_file->f, "null "); 1.455 + break; 1.456 + case PT_BOOL: 1.457 + if (obj->val.bool) 1.458 + fprintf (pdf_file->f, "true "); 1.459 + else 1.460 + fprintf (pdf_file->f, "false "); 1.461 + break; 1.462 + case PT_NAME: 1.463 + pdf_write_name (pdf_file, obj->val.name); 1.464 + break; 1.465 + case PT_STRING: 1.466 + pdf_write_string (pdf_file, obj->val.string); 1.467 + break; 1.468 + case PT_INTEGER: 1.469 + fprintf (pdf_file->f, "%ld ", obj->val.integer); 1.470 + break; 1.471 + case PT_REAL: 1.472 + pdf_write_real (pdf_file, obj->val.real); 1.473 + break; 1.474 + case PT_IND_REF: 1.475 + pdf_write_ind_ref (pdf_file, obj); 1.476 + break; 1.477 + case PT_DICTIONARY: 1.478 + pdf_write_dict (pdf_file, obj); 1.479 + break; 1.480 + case PT_ARRAY: 1.481 + pdf_write_array (pdf_file, obj); 1.482 + break; 1.483 + case PT_STREAM: 1.484 + pdf_write_stream (pdf_file, obj); 1.485 + break; 1.486 + default: 1.487 + pdf_fatal ("bad object type\n"); 1.488 + } 1.489 +} 1.490 + 1.491 + 1.492 +void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj) 1.493 +{ 1.494 + struct pdf_obj *obj; 1.495 + 1.496 + if (ind_obj->type == PT_IND_REF) 1.497 + obj = pdf_deref_ind_obj (ind_obj); 1.498 + else 1.499 + obj = ind_obj; 1.500 + 1.501 + obj->file_offset = ftell (pdf_file->f); 1.502 + fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen); 1.503 + pdf_write_obj (pdf_file, obj); 1.504 + fprintf (pdf_file->f, "endobj\r\n"); 1.505 +} 1.506 + 1.507 + 1.508 +void pdf_write_all_ind_obj (pdf_file_handle pdf_file) 1.509 +{ 1.510 + struct pdf_obj *ind_obj; 1.511 + for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next) 1.512 + if (! ind_obj->file_offset) 1.513 + pdf_write_ind_obj (pdf_file, ind_obj); 1.514 +} 1.515 + 1.516 + 1.517 +unsigned long pdf_write_xref (pdf_file_handle pdf_file) 1.518 +{ 1.519 + struct pdf_obj *ind_obj; 1.520 + pdf_file->xref_offset = ftell (pdf_file->f); 1.521 + fprintf (pdf_file->f, "xref\r\n"); 1.522 + fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1); 1.523 + fprintf (pdf_file->f, "0000000000 65535 f\r\n"); 1.524 + for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next) 1.525 + fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset); 1.526 + return (pdf_file->last_ind_obj->obj_num + 1); 1.527 +} 1.528 + 1.529 +