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.

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