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