semantics.c

Tue, 01 Jan 2002 06:11:43 +0000

author
eric
date
Tue, 01 Jan 2002 06:11:43 +0000
changeset 30
35fad7ec7732
parent 26
4368c5fd9242
child 32
3aac131058da
permissions
-rw-r--r--

add support for PDF file attributes: author, creator, title, etc.

     1 #include <stdlib.h>
     2 #include <string.h>
     3 #include <stdio.h>
     5 #include "type.h"
     6 #include "semantics.h"
     7 #include "parser.tab.h"
     8 #include "tiff2pdf.h"
    11 typedef struct
    12 {
    13   boolean has_size;
    14   page_size_t size;
    16   boolean has_rotation;
    17   int rotation;
    19   boolean has_crop;
    20   crop_t crop;
    21 } input_modifiers_t;
    24 typedef struct input_context_t
    25 {
    26   struct input_context_t *parent;
    27   struct input_context_t *next;
    29   int image_count;  /* how many pages reference this context,
    30 		      including those from subcontexts */
    32   char *input_file;
    34   input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
    35 } input_context_t;
    38 typedef struct input_image_t
    39 {
    40   struct input_image_t *next;
    41   input_context_t *input_context;
    42   range_t range;
    43 } input_image_t;
    46 typedef struct output_context_t
    47 {
    48   struct output_context_t *parent;
    49   struct output_context_t *next;
    51   int page_count;  /* how many pages reference this context,
    52 		      including those from subcontexts */
    54   char *output_file;
    55   pdf_file_attributes_t file_attributes;
    57   bookmark_t *first_bookmark;
    58   bookmark_t *last_bookmark;
    60   boolean has_page_label;
    61   page_label_t page_label;
    62 } output_context_t;
    65 typedef struct output_page_t
    66 {
    67   struct output_page_t *next;
    68   output_context_t *output_context;
    69   range_t range;
    70   bookmark_t *bookmark_list;
    71 } output_page_t;
    74 #define SEMANTIC_DEBUG
    75 #ifdef SEMANTIC_DEBUG
    76 #define SDBG(x) printf x
    77 #else
    78 #define SDBG(x)
    79 #endif
    82 FILE *yyin;
    83 int line;  /* line number in spec file */
    85 int bookmark_level;
    87 input_context_t *first_input_context;
    88 input_context_t *last_input_context;
    90 input_modifier_type_t current_modifier_context;
    92 input_image_t *first_input_image;
    93 input_image_t *last_input_image;
    95 output_context_t *first_output_context;
    96 output_context_t *last_output_context;
    98 output_page_t *first_output_page;
    99 output_page_t *last_output_page;
   102 void input_push_context (void)
   103 {
   104   input_context_t *new_input_context;
   106   new_input_context = malloc (sizeof (input_context_t));
   107   if (! new_input_context)
   108     {
   109       fprintf (stderr, "failed to malloc an input context\n");
   110       return;
   111     }
   113   if (last_input_context)
   114     {
   115       memcpy (new_input_context, last_input_context, sizeof (input_context_t));
   116       new_input_context->image_count = 0;
   117     }
   118   else
   119     {
   120       memset (new_input_context, 0, sizeof (input_context_t));
   121       first_input_context = new_input_context;
   122     }
   124   new_input_context->parent = last_input_context;
   125   last_input_context = new_input_context;
   126 };
   128 void input_pop_context (void)
   129 {
   130   if (! last_input_context)
   131     {
   132       fprintf (stderr, "failed to pop an input context\n");
   133       return;
   134     }
   136   last_input_context = last_input_context->parent;
   137 };
   139 void input_set_modifier_context (input_modifier_type_t type)
   140 {
   141   current_modifier_context = type;
   142 #ifdef SEMANTIC_DEBUG
   143   SDBG(("modifier type "));
   144   switch (type)
   145     {
   146     case INPUT_MODIFIER_ALL: SDBG(("all")); break;
   147     case INPUT_MODIFIER_ODD: SDBG(("odd")); break;
   148     case INPUT_MODIFIER_EVEN: SDBG(("even")); break;
   149     default: SDBG(("unknown %d", type));
   150     }
   151   SDBG(("\n"));
   152 #endif /* SEMANTIC_DEBUG */
   153 }
   155 static void input_clone (void)
   156 {
   157   input_context_t *new_input_context;
   159   if (! last_input_context->image_count)
   160     return;
   162   new_input_context = malloc (sizeof (input_context_t));
   163   if (! new_input_context)
   164     {
   165       fprintf (stderr, "failed to malloc an input context\n");
   166       return;
   167     }
   169   memcpy (new_input_context, last_input_context, sizeof (input_context_t));
   170   new_input_context->image_count = 0;
   171   last_input_context->next = new_input_context;
   172 }
   174 void input_set_file (char *name)
   175 {
   176   input_clone ();
   177   last_input_context->input_file = name;
   178 };
   180 void input_set_rotation (int rotation)
   181 {
   182   last_input_context->modifiers [current_modifier_context].has_rotation = 1;
   183   last_input_context->modifiers [current_modifier_context].rotation = rotation;
   184   SDBG(("rotation %d\n", rotation));
   185 }
   187 static void increment_input_image_count (int count)
   188 {
   189   input_context_t *context;
   191   for (context = last_input_context; context; context = context->parent)
   192     context->image_count += count;
   193 }
   195 void input_images (range_t range)
   196 {
   197   input_image_t *new_image;
   198   int count = ((range.last - range.first) + 1);
   200 #ifdef SEMANTIC_DEBUG
   201   if (range.first == range.last)
   202     SDBG(("image %d\n", range.first));
   203   else
   204     SDBG(("images %d..%d\n", range.first, range.last));
   205 #endif /* SEMANTIC_DEBUG */
   207   new_image = calloc (1, sizeof (input_image_t));
   208   if (! new_image)
   209     {
   210       fprintf (stderr, "failed to malloc an input image struct\n");
   211       return;
   212     }
   213   if (first_input_image)
   214     {
   215       last_input_image->next = new_image;
   216       last_input_image = new_image;
   217     }
   218   else
   219     {
   220       first_input_image = last_input_image = new_image;
   221     }
   222   new_image->range = range;
   223   new_image->input_context = last_input_context;
   224   increment_input_image_count (count);
   225 }
   228 void output_push_context (void)
   229 {
   230   output_context_t *new_output_context;
   232   new_output_context = malloc (sizeof (output_context_t));
   233   if (! new_output_context)
   234     {
   235       fprintf (stderr, "failed to malloc an output context\n");
   236       return;
   237     }
   239   if (last_output_context)
   240     {
   241       memcpy (new_output_context, last_output_context, sizeof (output_context_t));
   242       new_output_context->page_count = 0;
   243       new_output_context->first_bookmark = NULL;
   244       new_output_context->last_bookmark = NULL;
   245     }
   246   else
   247     {
   248       memset (new_output_context, 0, sizeof (output_context_t));
   249       first_output_context = new_output_context;
   250     }
   252   new_output_context->parent = last_output_context;
   253   last_output_context = new_output_context;
   254 };
   256 void output_pop_context (void)
   257 {
   258   if (! last_output_context)
   259     {
   260       fprintf (stderr, "failed to pop an output context\n");
   261       return;
   262     }
   264   last_output_context = last_output_context->parent;
   265 };
   267 static void output_clone (void)
   268 {
   269   output_context_t *new_output_context;
   271   if (! last_output_context->page_count)
   272     return;
   274   new_output_context = malloc (sizeof (output_context_t));
   275   if (! new_output_context)
   276     {
   277       fprintf (stderr, "failed to malloc an output context\n");
   278       return;
   279     }
   281   memcpy (new_output_context, last_output_context, sizeof (output_context_t));
   282   new_output_context->page_count = 0;
   283   last_output_context->next = new_output_context;
   284 }
   286 void output_set_file (char *name)
   287 {
   288   output_clone ();
   289   last_output_context->output_file = name;
   290   last_output_context->file_attributes.author = NULL;
   291   last_output_context->file_attributes.creator = NULL;
   292   last_output_context->file_attributes.title = NULL;
   293   last_output_context->file_attributes.subject = NULL;
   294   last_output_context->file_attributes.keywords = NULL;
   295 };
   297 void output_set_author (char *author)
   298 {
   299   last_output_context->file_attributes.author = author;
   300 }
   302 void output_set_creator (char *creator)
   303 {
   304   last_output_context->file_attributes.creator = creator;
   305 }
   307 void output_set_title (char *title)
   308 {
   309   last_output_context->file_attributes.title = title;
   310 }
   312 void output_set_subject (char *subject)
   313 {
   314   last_output_context->file_attributes.subject = subject;
   315 }
   317 void output_set_keywords (char *keywords)
   318 {
   319   last_output_context->file_attributes.keywords = keywords;
   320 }
   322 void output_set_bookmark (char *name)
   323 {
   324   bookmark_t *new_bookmark;
   326   /* As the language is defined (parser.y), a bookmark can only appear
   327      at the beginning of a context! */
   328   if (last_output_context->page_count)
   329     {
   330       fprintf (stderr, "internal error, bookmark not at beginning of context\n");
   331       exit (2);
   332     }
   334   new_bookmark = calloc (1, sizeof (bookmark_t));
   335   if (! new_bookmark)
   336     {
   337       fprintf (stderr, "failed to calloc a bookmark\n");
   338       return;
   339     }
   341   new_bookmark->level = bookmark_level;
   342   new_bookmark->name = name;
   343   if (last_output_context->first_bookmark)
   344     last_output_context->last_bookmark->next = new_bookmark;
   345   else
   346     last_output_context->first_bookmark = new_bookmark;
   347   last_output_context->last_bookmark = new_bookmark;
   348 }
   350 void output_set_page_label (page_label_t label)
   351 {
   352   output_clone ();
   353   last_output_context->has_page_label = 1;
   354   last_output_context->page_label = label;
   355 }
   357 static void increment_output_page_count (int count)
   358 {
   359   output_context_t *context;
   361   for (context = last_output_context; context; context = context->parent)
   362     context->page_count += count;
   363 }
   366 void output_pages (range_t range)
   367 {
   368   output_page_t *new_page;
   369   output_context_t *context;
   370   int count = ((range.last - range.first) + 1);
   372 #ifdef SEMANTIC_DEBUG
   373   if (range.first == range.last)
   374     SDBG(("page %d\n", range.first));
   375   else
   376     SDBG(("pages %d..%d\n", range.first, range.last));
   377 #endif /* SEMANTIC_DEBUG */
   379   new_page = calloc (1, sizeof (output_page_t));
   380   if (! new_page)
   381     {
   382       fprintf (stderr, "failed to malloc an output page struct\n");
   383       return;
   384     }
   385   if (first_output_page)
   386     {
   387       last_output_page->next = new_page;
   388       last_output_page = new_page;
   389     }
   390   else
   391     {
   392       first_output_page = last_output_page = new_page;
   393     }
   394   new_page->range = range;
   395   new_page->output_context = last_output_context;
   397   /* transfer bookmarks from context(s) to page */
   398   for (context = last_output_context; context; context = context->parent)
   399     if (context->first_bookmark)
   400       {
   401 	context->last_bookmark->next = new_page->bookmark_list;
   402 	new_page->bookmark_list = context->first_bookmark;
   403 	context->first_bookmark = NULL;
   404 	context->last_bookmark = NULL;
   405       }
   407   increment_output_page_count (count);
   408 }
   411 void yyerror (char *s)
   412 {
   413   fprintf (stderr, "%d: %s\n", line, s);
   414 }
   417 static char *get_input_file (input_context_t *context)
   418 {
   419   for (; context; context = context->parent)
   420     if (context->input_file)
   421       return (context->input_file);
   422   fprintf (stderr, "no input file name found\n");
   423   exit (2);
   424 }
   426 static int get_input_rotation (input_context_t *context, input_modifier_type_t type)
   427 {
   428   for (; context; context = context->parent)
   429     {
   430       if (context->modifiers [type].has_rotation)
   431 	return (context->modifiers [type].rotation);
   432       if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation)
   433 	return (context->modifiers [INPUT_MODIFIER_ALL].rotation);
   434     }
   435   return (0);  /* default */
   436 }
   438 static char *get_output_file (output_context_t *context)
   439 {
   440   for (; context; context = context->parent)
   441     if (context->output_file)
   442       return (context->output_file);
   443   fprintf (stderr, "no output file found\n");
   444   exit (2);
   445 }
   447 static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context)
   448 {
   449   for (; context; context = context->parent)
   450     if (context->output_file)
   451       return (& context->file_attributes);
   452   fprintf (stderr, "no output file found\n");
   453   exit (2);
   454 }
   456 static page_label_t *get_output_page_label (output_context_t *context)
   457 {
   458   for (; context; context = context->parent)
   459     if (context->has_page_label)
   460       return (& context->page_label);
   461   return (NULL);  /* default */
   462 }
   465 #ifdef SEMANTIC_DEBUG
   466 void dump_input_tree (void)
   467 {
   468   input_image_t *image;
   469   int i;
   471   printf ("input images:\n");
   472   for (image = first_input_image; image; image = image->next)
   473     for (i = image->range.first; i <= image->range.last; i++)
   474       {
   475 	input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
   476 	printf ("file '%s' image %d, rotation %d\n",
   477 	        get_input_file (image->input_context),
   478 		i, 
   479 		get_input_rotation (image->input_context, parity));
   480       }
   481 }
   483 void dump_output_tree (void)
   484 {
   485   int i;
   486   output_page_t *page;
   487   bookmark_t *bookmark;
   489   printf ("output pages:\n");
   490   for (page = first_output_page; page; page = page->next)
   491     {
   492       if (page->bookmark_list)
   493 	{
   494 	  for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next)
   495 	    printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name);
   496 	}
   497       for (i = page->range.first; i <= page->range.last; i++)
   498 	{
   499 	  page_label_t *label = get_output_page_label (page->output_context);
   500 	  printf ("file \"%s\" ", get_output_file (page->output_context));
   501 	  if (label)
   502 	    {
   503 	      printf ("label ");
   504 	      if (label->prefix)
   505 		printf ("\"%s\" ", label->prefix);
   506 	      if (label->style)
   507 		printf ("'%c' ", label->style);
   508 	    }
   509 	  printf ("page %d\n", i);
   510 	}
   511     }
   512 }
   513 #endif /* SEMANTIC_DEBUG */
   516 static inline int range_count (range_t range)
   517 {
   518   return ((range.last - range.first) + 1);
   519 }
   522 boolean parse_spec_file (char *fn)
   523 {
   524   boolean result = 0;
   526   yyin = fopen (fn, "r");
   527   if (! yyin)
   528     {
   529       fprintf (stderr, "can't open spec file '%s'\n", fn);
   530       goto fail;
   531     }
   533   line = 1;
   535   input_push_context ();  /* create root input context */
   536   input_push_context ();  /* create inital input context */
   538   output_push_context ();  /* create root output context */
   539   output_push_context ();  /* create initial output context */
   541   yyparse ();
   543   if (first_input_context->image_count != first_output_context->page_count)
   544     {
   545       fprintf (stderr, "input image count %d != output page count %d\n",
   546 	       first_input_context->image_count,
   547 	       first_output_context->page_count);
   548       goto fail;
   549     }
   551   fprintf (stderr, "%d pages specified\n", first_input_context->image_count);
   553   result = 1;
   555 #ifdef SEMANTIC_DEBUG
   556   dump_input_tree ();
   557   dump_output_tree ();
   558 #endif /* SEMANTIC_DEBUG */
   560  fail:
   561   if (yyin)
   562     fclose (yyin);
   564   return (result);
   565 }
   568 boolean process_specs (void)
   569 {
   570   input_image_t *image = NULL;
   571   output_page_t *page = NULL;
   572   int i = 0;
   573   int p = 0;
   574   int page_index = 0;
   575   input_attributes_t input_attributes;
   576   input_modifier_type_t parity;
   577   page_label_t *page_label;
   579   for (;;)
   580     {
   581       if ((! image) || (i >= range_count (image->range)))
   582 	{
   583 	  if (image)
   584 	    image = image->next;
   585 	  else
   586 	    image = first_input_image;
   587 	  if (! image)
   588 	    return (0);
   589 	  i = 0;
   590 	  if (! open_tiff_input_file (get_input_file (image->input_context)))
   591 	    return (0);
   592 	}
   594       if ((! page) || (p >= range_count (page->range)))
   595 	{
   596 	  if (page)
   597 	    page = page->next;
   598 	  else
   599 	    page = first_output_page;
   600 	  p = 0;
   601 	  if (! open_pdf_output_file (get_output_file (page->output_context),
   602 				      get_output_file_attributes (page->output_context)))
   603 	    return (0);
   604 	  page_label = get_output_page_label (page->output_context);
   605 	  process_page_numbers (page_index,
   606 				range_count (page->range),
   607 				page->range.first,
   608 				page_label);
   609 	}
   611       parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
   613       memset (& input_attributes, 0, sizeof (input_attributes));
   614       input_attributes.rotation = get_input_rotation (image->input_context,
   615 						      parity);;
   617       process_page (image->range.first + i,
   618 		    input_attributes,
   619 		    page->bookmark_list);
   620       i++;
   621       p++;
   622       page_index++;
   623     }
   625   return (1);
   626 }