pdf_prim.c

changeset 59
e8821eb2fb08
child 60
ffb5b1e54eb2
     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 +