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.

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