pdf_prim.c

Mon, 14 Dec 2009 16:18:21 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Dec 2009 16:18:21 +0000
changeset 172
2fae6df568f6
parent 166
301f6f17c364
permissions
-rw-r--r--

remove erroneous 0.33-philpem1 tag

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * PDF routines
     5  * $Id: pdf_prim.c,v 1.13 2003/03/19 23:44:53 eric Exp $
     6  * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License version 2 as
    10  * published by the Free Software Foundation.  Note that permission is
    11  * not granted to redistribute this program under the terms of any
    12  * other version of the General Public License.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    22  */
    25 #include <stdarg.h>
    26 #include <stdbool.h>
    27 #include <stdint.h>
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    32 #include "bitblt.h"
    33 #include "pdf.h"
    34 #include "pdf_util.h"
    35 #include "pdf_prim.h"
    36 #include "pdf_private.h"
    39 struct pdf_array_elem
    40 {
    41   struct pdf_array_elem *next;
    42   struct pdf_obj        *val;
    43 };
    46 struct pdf_array
    47 {
    48   struct pdf_array_elem *first;
    49   struct pdf_array_elem *last;
    50 };
    53 struct pdf_dict_entry
    54 {
    55   struct pdf_dict_entry *next;
    56   char                  *key;
    57   struct pdf_obj        *val;
    58 };
    61 struct pdf_dict
    62 {
    63   struct pdf_dict_entry *first;
    64 };
    67 struct pdf_stream
    68 {
    69   struct pdf_obj *stream_dict;
    70   struct pdf_obj *length;
    71   pdf_stream_write_callback callback;
    72   void *app_data;  /* arg to pass to callback */
    73   struct pdf_obj *filters;  /* name or array of names */
    74   struct pdf_obj *decode_parms;
    75 };
    78 struct pdf_obj
    79 {
    80   /* these fields only apply to indirectly referenced objects */
    81   struct pdf_obj      *prev;
    82   struct pdf_obj      *next;
    83   unsigned long       obj_num;
    84   unsigned long       obj_gen;
    85   long int            file_offset;
    87   /* these fields apply to all objects */
    88   unsigned long       ref_count;
    89   pdf_obj_type        type;
    90   union {
    91     bool              boolean;
    92     char              *name;
    93     struct {
    94       char            *content;
    95       int             length;
    96     }                 string;
    97     long              integer;
    98     double            real;
    99     struct pdf_obj    *ind_ref;
   100     struct pdf_dict   dict;
   101     struct pdf_array  array;
   102     struct pdf_stream stream;
   103   } val;
   104 };
   107 struct pdf_obj *ref (struct pdf_obj *obj)
   108 {
   109   obj->ref_count++;
   110   return (obj);
   111 }
   114 void unref (struct pdf_obj *obj)
   115 {
   116   if ((--obj->ref_count) == 0)
   117     {
   118       /* $$$ free the object */
   119     }
   120 }
   123 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
   124 {
   125   pdf_assert (ind_obj->type == PT_IND_REF);
   126   return (ind_obj->val.ind_ref);
   127 }
   130 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
   131 {
   132   struct pdf_dict_entry *entry;
   134   if (dict_obj->type == PT_IND_REF)
   135     dict_obj = pdf_deref_ind_obj (dict_obj);
   137   pdf_assert (dict_obj->type == PT_DICTIONARY);
   139   /* replacing existing entry? */
   140   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   141     if (strcmp (entry->key, key) == 0)
   142       {
   143 	unref (entry->val);
   144 	entry->val = ref (val);
   145 	return;
   146       }
   148   /* new entry */
   149   entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
   151   entry->next = dict_obj->val.dict.first;
   152   dict_obj->val.dict.first = entry;
   154   entry->key = pdf_strdup (key);
   155   entry->val = ref (val);
   156 }
   159 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
   160 {
   161   struct pdf_dict_entry *entry;
   163   if (dict_obj->type == PT_IND_REF)
   164     dict_obj = pdf_deref_ind_obj (dict_obj);
   166   pdf_assert (dict_obj->type == PT_DICTIONARY);
   168   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   169     if (strcmp (entry->key, key) == 0)
   170       return (entry->val);
   172   return (NULL);
   173 }
   176 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
   177 {
   178   struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
   180   if (array_obj->type == PT_IND_REF)
   181     array_obj = pdf_deref_ind_obj (array_obj);
   183   pdf_assert (array_obj->type == PT_ARRAY);
   185   elem->val = ref (val);
   187   if (! array_obj->val.array.first)
   188     array_obj->val.array.first = elem;
   189   else
   190     array_obj->val.array.last->next = elem;
   192   array_obj->val.array.last = elem;
   193 }
   196 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
   197 {
   198   struct pdf_array_elem *elem;
   200   if (array_obj->type == PT_IND_REF)
   201     array_obj = pdf_deref_ind_obj (array_obj);
   203   pdf_assert (array_obj->type == PT_ARRAY);
   205   for (elem = array_obj->val.array.first; elem; elem = elem->next)
   206     if (pdf_compare_obj (val, elem->val) == 0)
   207       return;
   209   elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
   211   elem->val = ref (val);
   213   if (! array_obj->val.array.first)
   214     array_obj->val.array.first = elem;
   215   else
   216     array_obj->val.array.last->next = elem;
   218   array_obj->val.array.last = elem;
   219 }
   222 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
   223 {
   224   struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
   225   obj->type = type;
   226   return (obj);
   227 }
   230 struct pdf_obj *pdf_new_bool (bool val)
   231 {
   232   struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
   233   obj->val.boolean = val;
   234   return (obj);
   235 }
   238 struct pdf_obj *pdf_new_name (char *name)
   239 {
   240   struct pdf_obj *obj = pdf_new_obj (PT_NAME);
   241   obj->val.name = pdf_strdup (name);
   242   return (obj);
   243 }
   246 struct pdf_obj *pdf_new_string (char *str)
   247 {
   248   struct pdf_obj *obj = pdf_new_obj (PT_STRING);
   249   obj->val.string.content = pdf_strdup (str);
   250   obj->val.string.length = strlen(str);
   251   return (obj);
   252 }
   255 struct pdf_obj *pdf_new_string_n (char *str, int n)
   256 {
   257   struct pdf_obj *obj = pdf_new_obj (PT_STRING);
   258   obj->val.string.length = n;
   259   obj->val.string.content = pdf_calloc (1,n);
   260   memcpy(obj->val.string.content, str, n);
   261   return (obj);
   262 }
   265 struct pdf_obj *pdf_new_integer (long val)
   266 {
   267   struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
   268   obj->val.integer = val;
   269   return (obj);
   270 }
   273 struct pdf_obj *pdf_new_real (double val)
   274 {
   275   struct pdf_obj *obj = pdf_new_obj (PT_REAL);
   276   obj->val.real = val;
   277   return (obj);
   278 }
   281 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
   282 				struct pdf_obj *stream_dict,
   283 				pdf_stream_write_callback callback,
   284 				void *app_data)
   285 {
   286   struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
   288   obj->val.stream.stream_dict = stream_dict;
   289   obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
   290   pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
   292   obj->val.stream.callback = callback;
   293   obj->val.stream.app_data = app_data;
   294   return (obj);
   295 }
   298 /* $$$ currently limited to one filter per stream */
   299 void pdf_stream_add_filter (struct pdf_obj *stream,
   300 			    char *filter_name,
   301 			    struct pdf_obj *decode_parms)
   302 {
   303   if (stream->type == PT_IND_REF)
   304     stream = pdf_deref_ind_obj (stream);
   306   pdf_assert (stream->type == PT_STREAM);
   308   pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
   309   if (decode_parms)
   310     pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
   311 }
   314 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
   315 {
   316   struct pdf_obj *ind_obj;
   318   pdf_assert (obj->type != PT_IND_REF);
   320   ind_obj = pdf_new_obj (PT_IND_REF);
   322   ind_obj->type = PT_IND_REF;
   323   ind_obj->val.ind_ref = obj;
   325   /* is there already an indirect reference to this object? */
   326   if (! obj->obj_num)
   327     {
   328       /* no, assign object number/generation and add to linked list */
   329       if (! pdf_file->first_ind_obj)
   330 	{
   331 	  obj->obj_num = 1;
   332 	  pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
   333 	}
   334       else
   335 	{
   336 	  obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
   337 	  pdf_file->last_ind_obj->next = obj;
   338 	  obj->prev = pdf_file->last_ind_obj;
   339 	  pdf_file->last_ind_obj = obj;
   340 	}
   341     }
   343   return (ind_obj);
   344 }
   347 long pdf_get_integer (struct pdf_obj *obj)
   348 {
   349   if (obj->type == PT_IND_REF)
   350     obj = pdf_deref_ind_obj (obj);
   352   pdf_assert (obj->type == PT_INTEGER);
   354   return (obj->val.integer);
   355 }
   357 void pdf_set_integer (struct pdf_obj *obj, long val)
   358 {
   359   if (obj->type == PT_IND_REF)
   360     obj = pdf_deref_ind_obj (obj);
   362   pdf_assert (obj->type == PT_INTEGER);
   364   obj->val.integer = val;
   365 }
   368 double pdf_get_real (struct pdf_obj *obj)
   369 {
   370   if (obj->type == PT_IND_REF)
   371     obj = pdf_deref_ind_obj (obj);
   373   pdf_assert (obj->type == PT_REAL);
   375   return (obj->val.real);
   376 }
   378 void pdf_set_real (struct pdf_obj *obj, double val)
   379 {
   380   if (obj->type == PT_IND_REF)
   381     obj = pdf_deref_ind_obj (obj);
   383   pdf_assert (obj->type == PT_REAL);
   385   obj->val.real = val;
   386 }
   389 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
   390 {
   391   if (o1->type == PT_IND_REF)
   392     o1 = pdf_deref_ind_obj (o1);
   394   if (o2->type == PT_IND_REF)
   395     o2 = pdf_deref_ind_obj (o2);
   397   pdf_assert (o1->type == o2->type);
   399   switch (o1->type)
   400     {
   401     case PT_INTEGER:
   402       if (o1->val.integer < o2->val.integer)
   403 	return (-1);
   404       if (o1->val.integer > o2->val.integer)
   405 	return (1);
   406       return (0);
   407     case PT_REAL:
   408       if (o1->val.real < o2->val.real)
   409 	return (-1);
   410       if (o1->val.real > o2->val.real)
   411 	return (1);
   412       return (0);
   413     case PT_STRING:
   414       {
   415 	int l;
   416 	l = o1->val.string.length;
   417 	if(l > o2->val.string.length)
   418 	  l = o2->val.string.length;
   419 	l = memcmp (o1->val.string.content, o2->val.string.content, l);
   420         if (l)
   421 	  return l;
   422 	return o1->val.string.length - o2->val.string.length;
   423       }
   424     case PT_NAME:
   425       return (strcmp (o1->val.name, o2->val.name));
   426     default:
   427       pdf_fatal ("invalid object type for comparison\n");
   428     }
   429 }
   432 static int name_char_needs_quoting (char c)
   433 {
   434   return ((c < '!')  || (c > '~')  || (c == '/') || (c == '\\') ||
   435 	  (c == '(') || (c == ')') || (c == '<') || (c == '>')  ||
   436 	  (c == '[') || (c == ']') || (c == '{') || (c == '}')  ||
   437 	  (c == '%'));
   438 }
   441 void pdf_write_name (pdf_file_handle pdf_file, char *s)
   442 {
   443   fprintf (pdf_file->f, "/");
   444   while (*s)
   445     if (name_char_needs_quoting (*s))
   446       fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
   447     else
   448       fprintf (pdf_file->f, "%c", *(s++));
   449   fprintf (pdf_file->f, " ");
   450 }
   453 static int pdf_write_literal_string (pdf_file_handle pdf_file, char *s, int n)
   454 {
   455   int i,p;
   456   if(pdf_file) fprintf (pdf_file->f, "(");
   457   for (i=p=0;n;n--) {
   458     int j,k;
   459     k=0;
   460     switch(*s){
   461       case '\\':
   462 	k=1;
   463 	break;
   464       case '(':
   465 	for(j=k=1;k && j<n;j++)
   466 	  k+=(s[j]=='(')?1:(s[j]==')')?-1:0;
   467 	p+=!k;
   468 	break;
   469       case ')':
   470 	if(p)
   471 	  p--;
   472 	else
   473 	  k=1;
   474 	break;
   475     }
   476     if(k) {
   477       i++;
   478       if(pdf_file) fprintf (pdf_file->f, "\\");
   479     }
   480     i++;
   481     if(pdf_file) fprintf (pdf_file->f, "%c", *(s++));
   482   }
   483   if(pdf_file) fprintf (pdf_file->f, ") ");
   484   return i;
   485 }
   488 void pdf_write_string (pdf_file_handle pdf_file, char *s, int n)
   489 {
   490   if(pdf_write_literal_string (NULL,s,n)<2*n)
   491     pdf_write_literal_string (pdf_file,s,n);
   492   else {
   493     fprintf (pdf_file->f, "<");
   494     for(;n--;)
   495       fprintf (pdf_file->f, "%.2X",*(s++));
   496     fprintf (pdf_file->f, "> ");
   497   }
   498 }
   501 void pdf_write_real (pdf_file_handle pdf_file, double num)
   502 {
   503   /* $$$ not actually good enough, precision needs to be variable,
   504      and no exponent is allowed */
   505   fprintf (pdf_file->f, "%0f ", num);
   506 }
   509 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   510 {
   511   struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
   512   fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
   513 }
   516 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
   517 {
   518   struct pdf_array_elem *elem;
   520   pdf_assert (array_obj->type == PT_ARRAY);
   522   fprintf (pdf_file->f, "[ ");
   523   for (elem = array_obj->val.array.first; elem; elem = elem->next)
   524     {
   525       pdf_write_obj (pdf_file, elem->val);
   526       fprintf (pdf_file->f, " ");
   527     }
   528   fprintf (pdf_file->f, "] ");
   529 }
   532 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
   533 {
   534   struct pdf_dict_entry *entry;
   536   pdf_assert (dict_obj->type == PT_DICTIONARY);
   538   fprintf (pdf_file->f, "<<\r\n");
   539   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   540     {
   541       pdf_write_name (pdf_file, entry->key);
   542       fprintf (pdf_file->f, " ");
   543       pdf_write_obj (pdf_file, entry->val);
   544       fprintf (pdf_file->f, "\r\n");
   545     }
   546   fprintf (pdf_file->f, ">>\r\n");
   547 }
   550 void pdf_stream_write_data (pdf_file_handle pdf_file,
   551 			    struct pdf_obj *stream,
   552 			    char *data,
   553 			    unsigned long len)
   554 {
   555   while (len)
   556     {
   557       unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
   558       data += l2;
   559       len -= l2;
   560       if (ferror (pdf_file->f))
   561 	pdf_fatal ("error writing stream data\n");
   562     }
   563 }
   566 void pdf_stream_printf (pdf_file_handle pdf_file,
   567 			struct pdf_obj *stream,
   568 			char *fmt, ...)
   569 {
   570   va_list ap;
   572   va_start (ap, fmt);
   573   vfprintf (pdf_file->f, fmt, ap);
   574   va_end (ap);
   575 }
   578 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
   579 {
   580   unsigned long begin_pos, end_pos;
   582   pdf_assert (stream->type == PT_STREAM);
   584   pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
   585   fprintf (pdf_file->f, "stream\r\n");
   586   begin_pos = ftell (pdf_file->f);
   587   stream->val.stream.callback (pdf_file,
   588 			       stream,
   589 			       stream->val.stream.app_data);
   590   end_pos = ftell (pdf_file->f);
   592   fprintf (pdf_file->f, "\r\nendstream\r\n");
   594   pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
   595 }
   598 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
   599 {
   600   switch (obj->type)
   601     {
   602     case PT_NULL:
   603       fprintf (pdf_file->f, "null ");
   604       break;
   605     case PT_BOOL:
   606       if (obj->val.boolean)
   607 	fprintf (pdf_file->f, "true ");
   608       else
   609 	fprintf (pdf_file->f, "false ");
   610       break;
   611     case PT_NAME:
   612       pdf_write_name (pdf_file, obj->val.name);
   613       break;
   614     case PT_STRING:
   615       pdf_write_string (pdf_file, obj->val.string.content, obj->val.string.length);
   616       break;
   617     case PT_INTEGER:
   618       fprintf (pdf_file->f, "%ld ", obj->val.integer);
   619       break;
   620     case PT_REAL:
   621       pdf_write_real (pdf_file, obj->val.real);
   622       break;
   623     case PT_IND_REF:
   624       pdf_write_ind_ref (pdf_file, obj);
   625       break;
   626     case PT_DICTIONARY:
   627       pdf_write_dict (pdf_file, obj);
   628       break;
   629     case PT_ARRAY:
   630       pdf_write_array (pdf_file, obj);
   631       break;
   632     case PT_STREAM:
   633       pdf_write_stream (pdf_file, obj);
   634       break;
   635     default:
   636       pdf_fatal ("bad object type\n");
   637     }
   638 }
   641 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   642 {
   643   struct pdf_obj *obj;
   645   if (ind_obj->type == PT_IND_REF)
   646     obj = pdf_deref_ind_obj (ind_obj);
   647   else
   648     obj = ind_obj;
   650   obj->file_offset = ftell (pdf_file->f);
   651   fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
   652   pdf_write_obj (pdf_file, obj);
   653   fprintf (pdf_file->f, "endobj\r\n");
   654 }
   657 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
   658 {
   659   struct pdf_obj *ind_obj;
   660   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   661     if (! ind_obj->file_offset)
   662       pdf_write_ind_obj (pdf_file, ind_obj);
   663 }
   666 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
   667 {
   668   struct pdf_obj *ind_obj;
   669   pdf_file->xref_offset = ftell (pdf_file->f);
   670   fprintf (pdf_file->f, "xref\r\n");
   671   fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
   672   fprintf (pdf_file->f, "0000000000 65535 f\r\n");
   673   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   674     fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
   675   return (pdf_file->last_ind_obj->obj_num + 1);
   676 }
   679 /* this isn't really a PDF primitive data type */
   680 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
   681 {
   682   char XObject_name [4] = "Im ";
   684   XObject_name [2] = ++pdf_page->last_XObject_name;
   686   if (! pdf_page->XObject_dict)
   687     {
   688       pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
   689       pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
   690     }
   692   pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
   694   return (pdf_page->last_XObject_name);
   695 }