1/* 2 * "$Id: pstops.c 11093 2013-07-03 20:48:42Z msweet $" 3 * 4 * PostScript filter for CUPS. 5 * 6 * Copyright 2007-2012 by Apple Inc. 7 * Copyright 1993-2007 by Easy Software Products. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * This file is subject to the Apple OS-Developed Software exception. 16 * 17 * Contents: 18 * 19 * main() - Main entry. 20 * add_page() - Add a page to the pages array. 21 * cancel_job() - Flag the job as canceled. 22 * check_range() - Check to see if the current page is selected for 23 * printing. 24 * copy_bytes() - Copy bytes from the input file to stdout. 25 * copy_comments() - Copy all of the comments section. 26 * copy_dsc() - Copy a DSC-conforming document. 27 * copy_non_dsc() - Copy a document that does not conform to the DSC. 28 * copy_page() - Copy a page description. 29 * copy_prolog() - Copy the document prolog section. 30 * copy_setup() - Copy the document setup section. 31 * copy_trailer() - Copy the document trailer. 32 * do_prolog() - Send the necessary document prolog commands. 33 * do_setup() - Send the necessary document setup commands. 34 * doc_printf() - Send a formatted string to stdout and/or the temp 35 * file. 36 * doc_puts() - Send a nul-terminated string to stdout and/or the 37 * temp file. 38 * doc_write() - Send data to stdout and/or the temp file. 39 * end_nup() - End processing for N-up printing. 40 * include_feature() - Include a printer option/feature command. 41 * parse_text() - Parse a text value in a comment. 42 * set_pstops_options() - Set pstops options. 43 * skip_page() - Skip past a page that won't be printed. 44 * start_nup() - Start processing for N-up printing. 45 * write_label_prolog() - Write the prolog with the classification and page 46 * label. 47 * write_labels() - Write the actual page labels. 48 * write_options() - Write options provided via %%IncludeFeature. 49 */ 50 51/* 52 * Include necessary headers... 53 */ 54 55#include "common.h" 56#include <limits.h> 57#include <math.h> 58#include <cups/file.h> 59#include <cups/array.h> 60#include <cups/language-private.h> 61#include <signal.h> 62 63 64/* 65 * Constants... 66 */ 67 68#define PSTOPS_BORDERNONE 0 /* No border or hairline border */ 69#define PSTOPS_BORDERTHICK 1 /* Think border */ 70#define PSTOPS_BORDERSINGLE 2 /* Single-line hairline border */ 71#define PSTOPS_BORDERSINGLE2 3 /* Single-line thick border */ 72#define PSTOPS_BORDERDOUBLE 4 /* Double-line hairline border */ 73#define PSTOPS_BORDERDOUBLE2 5 /* Double-line thick border */ 74 75#define PSTOPS_LAYOUT_LRBT 0 /* Left to right, bottom to top */ 76#define PSTOPS_LAYOUT_LRTB 1 /* Left to right, top to bottom */ 77#define PSTOPS_LAYOUT_RLBT 2 /* Right to left, bottom to top */ 78#define PSTOPS_LAYOUT_RLTB 3 /* Right to left, top to bottom */ 79#define PSTOPS_LAYOUT_BTLR 4 /* Bottom to top, left to right */ 80#define PSTOPS_LAYOUT_TBLR 5 /* Top to bottom, left to right */ 81#define PSTOPS_LAYOUT_BTRL 6 /* Bottom to top, right to left */ 82#define PSTOPS_LAYOUT_TBRL 7 /* Top to bottom, right to left */ 83 84#define PSTOPS_LAYOUT_NEGATEY 1 /* The bits for the layout */ 85#define PSTOPS_LAYOUT_NEGATEX 2 /* definitions above... */ 86#define PSTOPS_LAYOUT_VERTICAL 4 87 88 89/* 90 * Types... 91 */ 92 93typedef struct /**** Page information ****/ 94{ 95 char *label; /* Page label */ 96 int bounding_box[4]; /* PageBoundingBox */ 97 off_t offset; /* Offset to start of page */ 98 ssize_t length; /* Number of bytes for page */ 99 int num_options; /* Number of options for this page */ 100 cups_option_t *options; /* Options for this page */ 101} pstops_page_t; 102 103typedef struct /**** Document information ****/ 104{ 105 int page; /* Current page */ 106 int bounding_box[4]; /* BoundingBox from header */ 107 int new_bounding_box[4]; /* New composite bounding box */ 108 int num_options; /* Number of document-wide options */ 109 cups_option_t *options; /* Document-wide options */ 110 int normal_landscape, /* Normal rotation for landscape? */ 111 saw_eof, /* Saw the %%EOF comment? */ 112 slow_collate, /* Collate copies by hand? */ 113 slow_duplex, /* Duplex pages slowly? */ 114 slow_order, /* Reverse pages slowly? */ 115 use_ESPshowpage; /* Use ESPshowpage? */ 116 cups_array_t *pages; /* Pages in document */ 117 cups_file_t *temp; /* Temporary file, if any */ 118 char tempfile[1024]; /* Temporary filename */ 119 int job_id; /* Job ID */ 120 const char *user, /* User name */ 121 *title; /* Job name */ 122 int copies; /* Number of copies */ 123 const char *ap_input_slot, /* AP_FIRSTPAGE_InputSlot value */ 124 *ap_manual_feed, /* AP_FIRSTPAGE_ManualFeed value */ 125 *ap_media_color, /* AP_FIRSTPAGE_MediaColor value */ 126 *ap_media_type, /* AP_FIRSTPAGE_MediaType value */ 127 *ap_page_region, /* AP_FIRSTPAGE_PageRegion value */ 128 *ap_page_size; /* AP_FIRSTPAGE_PageSize value */ 129 int collate, /* Collate copies? */ 130 emit_jcl, /* Emit JCL commands? */ 131 fit_to_page; /* Fit pages to media */ 132 const char *input_slot, /* InputSlot value */ 133 *manual_feed, /* ManualFeed value */ 134 *media_color, /* MediaColor value */ 135 *media_type, /* MediaType value */ 136 *page_region, /* PageRegion value */ 137 *page_size; /* PageSize value */ 138 int mirror, /* doc->mirror/mirror pages */ 139 number_up, /* Number of pages on each sheet */ 140 number_up_layout, /* doc->number_up_layout of N-up pages */ 141 output_order, /* Requested reverse output order? */ 142 page_border; /* doc->page_border around pages */ 143 const char *page_label, /* page-label option, if any */ 144 *page_ranges, /* page-ranges option, if any */ 145 *page_set; /* page-set option, if any */ 146} pstops_doc_t; 147 148 149/* 150 * Convenience macros... 151 */ 152 153#define is_first_page(p) (doc->number_up == 1 || \ 154 ((p) % doc->number_up) == 1) 155#define is_last_page(p) (doc->number_up == 1 || \ 156 ((p) % doc->number_up) == 0) 157#define is_not_last_page(p) (doc->number_up > 1 && \ 158 ((p) % doc->number_up) != 0) 159 160 161/* 162 * Local globals... 163 */ 164 165static int JobCanceled = 0;/* Set to 1 on SIGTERM */ 166 167 168/* 169 * Local functions... 170 */ 171 172static pstops_page_t *add_page(pstops_doc_t *doc, const char *label); 173static void cancel_job(int sig); 174static int check_range(pstops_doc_t *doc, int page); 175static void copy_bytes(cups_file_t *fp, off_t offset, 176 size_t length); 177static ssize_t copy_comments(cups_file_t *fp, pstops_doc_t *doc, 178 ppd_file_t *ppd, char *line, 179 ssize_t linelen, size_t linesize); 180static void copy_dsc(cups_file_t *fp, pstops_doc_t *doc, 181 ppd_file_t *ppd, char *line, ssize_t linelen, 182 size_t linesize); 183static void copy_non_dsc(cups_file_t *fp, pstops_doc_t *doc, 184 ppd_file_t *ppd, char *line, 185 ssize_t linelen, size_t linesize); 186static ssize_t copy_page(cups_file_t *fp, pstops_doc_t *doc, 187 ppd_file_t *ppd, int number, char *line, 188 ssize_t linelen, size_t linesize); 189static ssize_t copy_prolog(cups_file_t *fp, pstops_doc_t *doc, 190 ppd_file_t *ppd, char *line, 191 ssize_t linelen, size_t linesize); 192static ssize_t copy_setup(cups_file_t *fp, pstops_doc_t *doc, 193 ppd_file_t *ppd, char *line, 194 ssize_t linelen, size_t linesize); 195static ssize_t copy_trailer(cups_file_t *fp, pstops_doc_t *doc, 196 ppd_file_t *ppd, int number, char *line, 197 ssize_t linelen, size_t linesize); 198static void do_prolog(pstops_doc_t *doc, ppd_file_t *ppd); 199static void do_setup(pstops_doc_t *doc, ppd_file_t *ppd); 200static void doc_printf(pstops_doc_t *doc, const char *format, ...) 201 __attribute__ ((__format__ (__printf__, 2, 3))); 202static void doc_puts(pstops_doc_t *doc, const char *s); 203static void doc_write(pstops_doc_t *doc, const char *s, size_t len); 204static void end_nup(pstops_doc_t *doc, int number); 205static int include_feature(ppd_file_t *ppd, const char *line, 206 int num_options, 207 cups_option_t **options); 208static char *parse_text(const char *start, char **end, char *buffer, 209 size_t bufsize); 210static void set_pstops_options(pstops_doc_t *doc, ppd_file_t *ppd, 211 char *argv[], int num_options, 212 cups_option_t *options); 213static ssize_t skip_page(cups_file_t *fp, char *line, ssize_t linelen, 214 size_t linesize); 215static void start_nup(pstops_doc_t *doc, int number, 216 int show_border, const int *bounding_box); 217static void write_label_prolog(pstops_doc_t *doc, const char *label, 218 float bottom, float top, 219 float width); 220static void write_labels(pstops_doc_t *doc, int orient); 221static void write_options(pstops_doc_t *doc, ppd_file_t *ppd, 222 int num_options, cups_option_t *options); 223 224 225/* 226 * 'main()' - Main entry. 227 */ 228 229int /* O - Exit status */ 230main(int argc, /* I - Number of command-line args */ 231 char *argv[]) /* I - Command-line arguments */ 232{ 233 pstops_doc_t doc; /* Document information */ 234 cups_file_t *fp; /* Print file */ 235 ppd_file_t *ppd; /* PPD file */ 236 int num_options; /* Number of print options */ 237 cups_option_t *options; /* Print options */ 238 char line[8192]; /* Line buffer */ 239 size_t len; /* Length of line buffer */ 240#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) 241 struct sigaction action; /* Actions for POSIX signals */ 242#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ 243 244 245 /* 246 * Make sure status messages are not buffered... 247 */ 248 249 setbuf(stderr, NULL); 250 251 /* 252 * Ignore broken pipe signals... 253 */ 254 255 signal(SIGPIPE, SIG_IGN); 256 257 /* 258 * Check command-line... 259 */ 260 261 if (argc < 6 || argc > 7) 262 { 263 _cupsLangPrintf(stderr, 264 _("Usage: %s job-id user title copies options [file]"), 265 argv[0]); 266 return (1); 267 } 268 269 /* 270 * Register a signal handler to cleanly cancel a job. 271 */ 272 273#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ 274 sigset(SIGTERM, cancel_job); 275#elif defined(HAVE_SIGACTION) 276 memset(&action, 0, sizeof(action)); 277 278 sigemptyset(&action.sa_mask); 279 action.sa_handler = cancel_job; 280 sigaction(SIGTERM, &action, NULL); 281#else 282 signal(SIGTERM, cancel_job); 283#endif /* HAVE_SIGSET */ 284 285 /* 286 * If we have 7 arguments, print the file named on the command-line. 287 * Otherwise, send stdin instead... 288 */ 289 290 if (argc == 6) 291 fp = cupsFileStdin(); 292 else 293 { 294 /* 295 * Try to open the print file... 296 */ 297 298 if ((fp = cupsFileOpen(argv[6], "r")) == NULL) 299 { 300 _cupsLangPrintError("ERROR", _("Unable to open print file")); 301 return (1); 302 } 303 } 304 305 /* 306 * Read the first line to see if we have DSC comments... 307 */ 308 309 if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0) 310 { 311 fputs("DEBUG: The print file is empty.\n", stderr); 312 return (1); 313 } 314 315 /* 316 * Process command-line options... 317 */ 318 319 options = NULL; 320 num_options = cupsParseOptions(argv[5], 0, &options); 321 ppd = SetCommonOptions(num_options, options, 1); 322 323 set_pstops_options(&doc, ppd, argv, num_options, options); 324 325 /* 326 * Write any "exit server" options that have been selected... 327 */ 328 329 ppdEmit(ppd, stdout, PPD_ORDER_EXIT); 330 331 /* 332 * Write any JCL commands that are needed to print PostScript code... 333 */ 334 335 if (doc.emit_jcl) 336 ppdEmitJCL(ppd, stdout, doc.job_id, doc.user, doc.title); 337 338 /* 339 * Start with a DSC header... 340 */ 341 342 puts("%!PS-Adobe-3.0"); 343 344 /* 345 * Skip leading PJL in the document... 346 */ 347 348 while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5)) 349 { 350 /* 351 * Yup, we have leading PJL fun, so skip it until we hit the line 352 * with "ENTER LANGUAGE"... 353 */ 354 355 fputs("DEBUG: Skipping PJL header...\n", stderr); 356 357 while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2)) 358 if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0) 359 break; 360 361 if (!strncmp(line, "%!", 2)) 362 break; 363 364 if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0) 365 break; 366 } 367 368 /* 369 * Now see if the document conforms to the Adobe Document Structuring 370 * Conventions... 371 */ 372 373 if (!strncmp(line, "%!PS-Adobe-", 11)) 374 { 375 /* 376 * Yes, filter the document... 377 */ 378 379 copy_dsc(fp, &doc, ppd, line, len, sizeof(line)); 380 } 381 else 382 { 383 /* 384 * No, display an error message and treat the file as if it contains 385 * a single page... 386 */ 387 388 copy_non_dsc(fp, &doc, ppd, line, len, sizeof(line)); 389 } 390 391 /* 392 * Send %%EOF as needed... 393 */ 394 395 if (!doc.saw_eof) 396 puts("%%EOF"); 397 398 /* 399 * End the job with the appropriate JCL command or CTRL-D... 400 */ 401 402 if (doc.emit_jcl) 403 { 404 if (ppd && ppd->jcl_end) 405 ppdEmitJCLEnd(ppd, stdout); 406 else 407 putchar(0x04); 408 } 409 410 /* 411 * Close files and remove the temporary file if needed... 412 */ 413 414 if (doc.temp) 415 { 416 cupsFileClose(doc.temp); 417 unlink(doc.tempfile); 418 } 419 420 ppdClose(ppd); 421 cupsFreeOptions(num_options, options); 422 423 cupsFileClose(fp); 424 425 return (0); 426} 427 428 429/* 430 * 'add_page()' - Add a page to the pages array. 431 */ 432 433static pstops_page_t * /* O - New page info object */ 434add_page(pstops_doc_t *doc, /* I - Document information */ 435 const char *label) /* I - Page label */ 436{ 437 pstops_page_t *pageinfo; /* New page info object */ 438 439 440 if (!doc->pages) 441 doc->pages = cupsArrayNew(NULL, NULL); 442 443 if (!doc->pages) 444 { 445 _cupsLangPrintError("EMERG", _("Unable to allocate memory for pages array")); 446 exit(1); 447 } 448 449 if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL) 450 { 451 _cupsLangPrintError("EMERG", _("Unable to allocate memory for page info")); 452 exit(1); 453 } 454 455 pageinfo->label = strdup(label); 456 pageinfo->offset = cupsFileTell(doc->temp); 457 458 cupsArrayAdd(doc->pages, pageinfo); 459 460 doc->page ++; 461 462 return (pageinfo); 463} 464 465 466/* 467 * 'cancel_job()' - Flag the job as canceled. 468 */ 469 470static void 471cancel_job(int sig) /* I - Signal number (unused) */ 472{ 473 (void)sig; 474 475 JobCanceled = 1; 476} 477 478 479/* 480 * 'check_range()' - Check to see if the current page is selected for 481 * printing. 482 */ 483 484static int /* O - 1 if selected, 0 otherwise */ 485check_range(pstops_doc_t *doc, /* I - Document information */ 486 int page) /* I - Page number */ 487{ 488 const char *range; /* Pointer into range string */ 489 int lower, upper; /* Lower and upper page numbers */ 490 491 492 if (doc->page_set) 493 { 494 /* 495 * See if we only print even or odd pages... 496 */ 497 498 if (!_cups_strcasecmp(doc->page_set, "even") && (page & 1)) 499 return (0); 500 501 if (!_cups_strcasecmp(doc->page_set, "odd") && !(page & 1)) 502 return (0); 503 } 504 505 if (!doc->page_ranges) 506 return (1); /* No range, print all pages... */ 507 508 for (range = doc->page_ranges; *range != '\0';) 509 { 510 if (*range == '-') 511 { 512 lower = 1; 513 range ++; 514 upper = strtol(range, (char **)&range, 10); 515 } 516 else 517 { 518 lower = strtol(range, (char **)&range, 10); 519 520 if (*range == '-') 521 { 522 range ++; 523 if (!isdigit(*range & 255)) 524 upper = 65535; 525 else 526 upper = strtol(range, (char **)&range, 10); 527 } 528 else 529 upper = lower; 530 } 531 532 if (page >= lower && page <= upper) 533 return (1); 534 535 if (*range == ',') 536 range ++; 537 else 538 break; 539 } 540 541 return (0); 542} 543 544 545/* 546 * 'copy_bytes()' - Copy bytes from the input file to stdout. 547 */ 548 549static void 550copy_bytes(cups_file_t *fp, /* I - File to read from */ 551 off_t offset, /* I - Offset to page data */ 552 size_t length) /* I - Length of page data */ 553{ 554 char buffer[8192]; /* Data buffer */ 555 ssize_t nbytes; /* Number of bytes read */ 556 size_t nleft; /* Number of bytes left/remaining */ 557 558 559 nleft = length; 560 561 if (cupsFileSeek(fp, offset) < 0) 562 { 563 _cupsLangPrintError("ERROR", _("Unable to see in file")); 564 return; 565 } 566 567 while (nleft > 0 || length == 0) 568 { 569 if (nleft > sizeof(buffer) || length == 0) 570 nbytes = sizeof(buffer); 571 else 572 nbytes = nleft; 573 574 if ((nbytes = cupsFileRead(fp, buffer, nbytes)) < 1) 575 return; 576 577 nleft -= nbytes; 578 579 fwrite(buffer, 1, nbytes, stdout); 580 } 581} 582 583 584/* 585 * 'copy_comments()' - Copy all of the comments section. 586 * 587 * This function expects "line" to be filled with a comment line. 588 * On return, "line" will contain the next line in the file, if any. 589 */ 590 591static ssize_t /* O - Length of next line */ 592copy_comments(cups_file_t *fp, /* I - File to read from */ 593 pstops_doc_t *doc, /* I - Document info */ 594 ppd_file_t *ppd, /* I - PPD file */ 595 char *line, /* I - Line buffer */ 596 ssize_t linelen, /* I - Length of initial line */ 597 size_t linesize) /* I - Size of line buffer */ 598{ 599 int saw_bounding_box, /* Saw %%BoundingBox: comment? */ 600 saw_for, /* Saw %%For: comment? */ 601 saw_pages, /* Saw %%Pages: comment? */ 602 saw_title; /* Saw %%Title: comment? */ 603 604 605 /* 606 * Loop until we see %%EndComments or a non-comment line... 607 */ 608 609 saw_bounding_box = 0; 610 saw_for = 0; 611 saw_pages = 0; 612 saw_title = 0; 613 614 while (line[0] == '%') 615 { 616 /* 617 * Strip trailing whitespace... 618 */ 619 620 while (linelen > 0) 621 { 622 linelen --; 623 624 if (!isspace(line[linelen] & 255)) 625 break; 626 else 627 line[linelen] = '\0'; 628 } 629 630 /* 631 * Log the header... 632 */ 633 634 fprintf(stderr, "DEBUG: %s\n", line); 635 636 /* 637 * Pull the headers out... 638 */ 639 640 if (!strncmp(line, "%%Pages:", 8)) 641 { 642 int pages; /* Number of pages */ 643 644 if (saw_pages) 645 fputs("DEBUG: A duplicate %%Pages: comment was seen.\n", stderr); 646 647 saw_pages = 1; 648 649 if (Duplex && (pages = atoi(line + 8)) > 0 && pages <= doc->number_up) 650 { 651 /* 652 * Since we will only be printing on a single page, disable duplexing. 653 */ 654 655 Duplex = 0; 656 doc->slow_duplex = 0; 657 658 if (cupsGetOption("sides", doc->num_options, doc->options)) 659 doc->num_options = cupsAddOption("sides", "one-sided", 660 doc->num_options, &(doc->options)); 661 662 if (cupsGetOption("Duplex", doc->num_options, doc->options)) 663 doc->num_options = cupsAddOption("Duplex", "None", 664 doc->num_options, &(doc->options)); 665 666 if (cupsGetOption("EFDuplex", doc->num_options, doc->options)) 667 doc->num_options = cupsAddOption("EFDuplex", "None", 668 doc->num_options, &(doc->options)); 669 670 if (cupsGetOption("EFDuplexing", doc->num_options, doc->options)) 671 doc->num_options = cupsAddOption("EFDuplexing", "False", 672 doc->num_options, &(doc->options)); 673 674 if (cupsGetOption("KD03Duplex", doc->num_options, doc->options)) 675 doc->num_options = cupsAddOption("KD03Duplex", "None", 676 doc->num_options, &(doc->options)); 677 678 if (cupsGetOption("JCLDuplex", doc->num_options, doc->options)) 679 doc->num_options = cupsAddOption("JCLDuplex", "None", 680 doc->num_options, &(doc->options)); 681 682 ppdMarkOption(ppd, "Duplex", "None"); 683 ppdMarkOption(ppd, "EFDuplex", "None"); 684 ppdMarkOption(ppd, "EFDuplexing", "False"); 685 ppdMarkOption(ppd, "KD03Duplex", "None"); 686 ppdMarkOption(ppd, "JCLDuplex", "None"); 687 } 688 } 689 else if (!strncmp(line, "%%BoundingBox:", 14)) 690 { 691 if (saw_bounding_box) 692 fputs("DEBUG: A duplicate %%BoundingBox: comment was seen.\n", stderr); 693 else if (strstr(line + 14, "(atend)")) 694 { 695 /* 696 * Do nothing for now but use the default imageable area... 697 */ 698 } 699 else if (sscanf(line + 14, "%d%d%d%d", doc->bounding_box + 0, 700 doc->bounding_box + 1, doc->bounding_box + 2, 701 doc->bounding_box + 3) != 4) 702 { 703 fputs("DEBUG: A bad %%BoundingBox: comment was seen.\n", stderr); 704 705 doc->bounding_box[0] = (int)PageLeft; 706 doc->bounding_box[1] = (int)PageBottom; 707 doc->bounding_box[2] = (int)PageRight; 708 doc->bounding_box[3] = (int)PageTop; 709 } 710 711 saw_bounding_box = 1; 712 } 713 else if (!strncmp(line, "%%For:", 6)) 714 { 715 saw_for = 1; 716 doc_printf(doc, "%s\n", line); 717 } 718 else if (!strncmp(line, "%%Title:", 8)) 719 { 720 saw_title = 1; 721 doc_printf(doc, "%s\n", line); 722 } 723 else if (!strncmp(line, "%cupsRotation:", 14)) 724 { 725 /* 726 * Reset orientation of document? 727 */ 728 729 int orient = (atoi(line + 14) / 90) & 3; 730 731 if (orient != Orientation) 732 { 733 /* 734 * Yes, update things so that the pages come out right... 735 */ 736 737 Orientation = (4 - Orientation + orient) & 3; 738 UpdatePageVars(); 739 Orientation = orient; 740 } 741 } 742 else if (!strcmp(line, "%%EndComments")) 743 { 744 linelen = cupsFileGetLine(fp, line, linesize); 745 break; 746 } 747 else if (strncmp(line, "%!", 2) && strncmp(line, "%cups", 5)) 748 doc_printf(doc, "%s\n", line); 749 750 if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0) 751 break; 752 } 753 754 if (!saw_bounding_box) 755 fputs("DEBUG: There wasn't a %%BoundingBox: comment in the header.\n", 756 stderr); 757 758 if (!saw_pages) 759 fputs("DEBUG: There wasn't a %%Pages: comment in the header.\n", stderr); 760 761 if (!saw_for) 762 WriteTextComment("For", doc->user); 763 764 if (!saw_title) 765 WriteTextComment("Title", doc->title); 766 767 if (doc->copies != 1 && (!doc->collate || !doc->slow_collate)) 768 { 769 /* 770 * Tell the document processor the copy and duplex options 771 * that are required... 772 */ 773 774 doc_printf(doc, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies, 775 doc->collate ? " collate" : "", 776 Duplex ? " duplex" : ""); 777 778 /* 779 * Apple uses RBI comments for various non-PPD options... 780 */ 781 782 doc_printf(doc, "%%RBINumCopies: %d\n", doc->copies); 783 } 784 else 785 { 786 /* 787 * Tell the document processor the duplex option that is required... 788 */ 789 790 if (Duplex) 791 doc_puts(doc, "%%Requirements: duplex\n"); 792 793 /* 794 * Apple uses RBI comments for various non-PPD options... 795 */ 796 797 doc_puts(doc, "%RBINumCopies: 1\n"); 798 } 799 800 doc_puts(doc, "%%Pages: (atend)\n"); 801 doc_puts(doc, "%%BoundingBox: (atend)\n"); 802 doc_puts(doc, "%%EndComments\n"); 803 804 return (linelen); 805} 806 807 808/* 809 * 'copy_dsc()' - Copy a DSC-conforming document. 810 * 811 * This function expects "line" to be filled with the %!PS-Adobe comment line. 812 */ 813 814static void 815copy_dsc(cups_file_t *fp, /* I - File to read from */ 816 pstops_doc_t *doc, /* I - Document info */ 817 ppd_file_t *ppd, /* I - PPD file */ 818 char *line, /* I - Line buffer */ 819 ssize_t linelen, /* I - Length of initial line */ 820 size_t linesize) /* I - Size of line buffer */ 821{ 822 int number; /* Page number */ 823 pstops_page_t *pageinfo; /* Page information */ 824 825 826 /* 827 * Make sure we use ESPshowpage for EPS files... 828 */ 829 830 if (strstr(line, "EPSF")) 831 { 832 doc->use_ESPshowpage = 1; 833 doc->number_up = 1; 834 } 835 836 /* 837 * Start sending the document with any commands needed... 838 */ 839 840 fprintf(stderr, "DEBUG: Before copy_comments - %s", line); 841 linelen = copy_comments(fp, doc, ppd, line, linelen, linesize); 842 843 /* 844 * Now find the prolog section, if any... 845 */ 846 847 fprintf(stderr, "DEBUG: Before copy_prolog - %s", line); 848 linelen = copy_prolog(fp, doc, ppd, line, linelen, linesize); 849 850 /* 851 * Then the document setup section... 852 */ 853 854 fprintf(stderr, "DEBUG: Before copy_setup - %s", line); 855 linelen = copy_setup(fp, doc, ppd, line, linelen, linesize); 856 857 /* 858 * Copy until we see %%Page:... 859 */ 860 861 while (strncmp(line, "%%Page:", 7) && strncmp(line, "%%Trailer", 9)) 862 { 863 doc_write(doc, line, linelen); 864 865 if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0) 866 break; 867 } 868 869 /* 870 * Then process pages until we have no more... 871 */ 872 873 number = 0; 874 875 fprintf(stderr, "DEBUG: Before page loop - %s", line); 876 while (!strncmp(line, "%%Page:", 7)) 877 { 878 if (JobCanceled) 879 break; 880 881 number ++; 882 883 if (check_range(doc, (number - 1) / doc->number_up + 1)) 884 { 885 fprintf(stderr, "DEBUG: Copying page %d...\n", number); 886 linelen = copy_page(fp, doc, ppd, number, line, linelen, linesize); 887 } 888 else 889 { 890 fprintf(stderr, "DEBUG: Skipping page %d...\n", number); 891 linelen = skip_page(fp, line, linelen, linesize); 892 } 893 } 894 895 /* 896 * Finish up the last page(s)... 897 */ 898 899 if (number && is_not_last_page(number) && cupsArrayLast(doc->pages) && 900 check_range(doc, (number - 1) / doc->number_up + 1)) 901 { 902 pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages); 903 904 start_nup(doc, doc->number_up, 0, doc->bounding_box); 905 doc_puts(doc, "showpage\n"); 906 end_nup(doc, doc->number_up); 907 908 pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset; 909 } 910 911 if (doc->slow_duplex && (doc->page & 1)) 912 { 913 /* 914 * Make sure we have an even number of pages... 915 */ 916 917 pageinfo = add_page(doc, "(filler)"); 918 919 if (!doc->slow_order) 920 { 921 if (!ppd || !ppd->num_filters) 922 fprintf(stderr, "PAGE: %d %d\n", doc->page, 923 doc->slow_collate ? 1 : doc->copies); 924 925 printf("%%%%Page: (filler) %d\n", doc->page); 926 } 927 928 start_nup(doc, doc->number_up, 0, doc->bounding_box); 929 doc_puts(doc, "showpage\n"); 930 end_nup(doc, doc->number_up); 931 932 pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset; 933 } 934 935 /* 936 * Make additional copies as necessary... 937 */ 938 939 number = doc->slow_order ? 0 : doc->page; 940 941 if (doc->temp && !JobCanceled && cupsArrayCount(doc->pages) > 0) 942 { 943 int copy; /* Current copy */ 944 945 946 /* 947 * Reopen the temporary file for reading... 948 */ 949 950 cupsFileClose(doc->temp); 951 952 doc->temp = cupsFileOpen(doc->tempfile, "r"); 953 954 /* 955 * Make the copies... 956 */ 957 958 if (doc->slow_collate) 959 copy = !doc->slow_order; 960 else 961 copy = doc->copies - 1; 962 963 for (; copy < doc->copies; copy ++) 964 { 965 if (JobCanceled) 966 break; 967 968 /* 969 * Send end-of-job stuff followed by any start-of-job stuff required 970 * for the JCL options... 971 */ 972 973 if (number && doc->emit_jcl && ppd && ppd->jcl_end) 974 { 975 /* 976 * Send the trailer... 977 */ 978 979 puts("%%Trailer"); 980 printf("%%%%Pages: %d\n", cupsArrayCount(doc->pages)); 981 if (doc->number_up > 1 || doc->fit_to_page) 982 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", 983 PageLeft, PageBottom, PageRight, PageTop); 984 else 985 printf("%%%%BoundingBox: %d %d %d %d\n", 986 doc->new_bounding_box[0], doc->new_bounding_box[1], 987 doc->new_bounding_box[2], doc->new_bounding_box[3]); 988 puts("%%EOF"); 989 990 /* 991 * Start a new document... 992 */ 993 994 ppdEmitJCLEnd(ppd, stdout); 995 ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title); 996 997 puts("%!PS-Adobe-3.0"); 998 999 number = 0; 1000 } 1001 1002 /* 1003 * Copy the prolog as needed... 1004 */ 1005 1006 if (!number) 1007 { 1008 pageinfo = (pstops_page_t *)cupsArrayFirst(doc->pages); 1009 copy_bytes(doc->temp, 0, pageinfo->offset); 1010 } 1011 1012 /* 1013 * Then copy all of the pages... 1014 */ 1015 1016 pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayLast(doc->pages) : 1017 (pstops_page_t *)cupsArrayFirst(doc->pages); 1018 1019 while (pageinfo) 1020 { 1021 if (JobCanceled) 1022 break; 1023 1024 number ++; 1025 1026 if (!ppd || !ppd->num_filters) 1027 fprintf(stderr, "PAGE: %d %d\n", number, 1028 doc->slow_collate ? 1 : doc->copies); 1029 1030 if (doc->number_up > 1) 1031 { 1032 printf("%%%%Page: (%d) %d\n", number, number); 1033 printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n", 1034 PageLeft, PageBottom, PageRight, PageTop); 1035 } 1036 else 1037 { 1038 printf("%%%%Page: %s %d\n", pageinfo->label, number); 1039 printf("%%%%PageBoundingBox: %d %d %d %d\n", 1040 pageinfo->bounding_box[0], pageinfo->bounding_box[1], 1041 pageinfo->bounding_box[2], pageinfo->bounding_box[3]); 1042 } 1043 1044 copy_bytes(doc->temp, pageinfo->offset, pageinfo->length); 1045 1046 pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayPrev(doc->pages) : 1047 (pstops_page_t *)cupsArrayNext(doc->pages); 1048 } 1049 } 1050 } 1051 1052 /* 1053 * Restore the old showpage operator as needed... 1054 */ 1055 1056 if (doc->use_ESPshowpage) 1057 puts("userdict/showpage/ESPshowpage load put\n"); 1058 1059 /* 1060 * Write/copy the trailer... 1061 */ 1062 1063 if (!JobCanceled) 1064 copy_trailer(fp, doc, ppd, number, line, linelen, linesize); 1065} 1066 1067 1068/* 1069 * 'copy_non_dsc()' - Copy a document that does not conform to the DSC. 1070 * 1071 * This function expects "line" to be filled with the %! comment line. 1072 */ 1073 1074static void 1075copy_non_dsc(cups_file_t *fp, /* I - File to read from */ 1076 pstops_doc_t *doc, /* I - Document info */ 1077 ppd_file_t *ppd, /* I - PPD file */ 1078 char *line, /* I - Line buffer */ 1079 ssize_t linelen, /* I - Length of initial line */ 1080 size_t linesize) /* I - Size of line buffer */ 1081{ 1082 int copy; /* Current copy */ 1083 char buffer[8192]; /* Copy buffer */ 1084 int bytes; /* Number of bytes copied */ 1085 1086 1087 /* 1088 * First let the user know that they are attempting to print a file 1089 * that may not print correctly... 1090 */ 1091 1092 fputs("DEBUG: This document does not conform to the Adobe Document " 1093 "Structuring Conventions and may not print correctly.\n", stderr); 1094 1095 /* 1096 * Then write a standard DSC comment section... 1097 */ 1098 1099 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom, 1100 PageRight, PageTop); 1101 1102 if (doc->slow_collate && doc->copies > 1) 1103 printf("%%%%Pages: %d\n", doc->copies); 1104 else 1105 puts("%%Pages: 1"); 1106 1107 WriteTextComment("For", doc->user); 1108 WriteTextComment("Title", doc->title); 1109 1110 if (doc->copies != 1 && (!doc->collate || !doc->slow_collate)) 1111 { 1112 /* 1113 * Tell the document processor the copy and duplex options 1114 * that are required... 1115 */ 1116 1117 printf("%%%%Requirements: numcopies(%d)%s%s\n", doc->copies, 1118 doc->collate ? " collate" : "", 1119 Duplex ? " duplex" : ""); 1120 1121 /* 1122 * Apple uses RBI comments for various non-PPD options... 1123 */ 1124 1125 printf("%%RBINumCopies: %d\n", doc->copies); 1126 } 1127 else 1128 { 1129 /* 1130 * Tell the document processor the duplex option that is required... 1131 */ 1132 1133 if (Duplex) 1134 puts("%%Requirements: duplex"); 1135 1136 /* 1137 * Apple uses RBI comments for various non-PPD options... 1138 */ 1139 1140 puts("%RBINumCopies: 1"); 1141 } 1142 1143 puts("%%EndComments"); 1144 1145 /* 1146 * Then the prolog... 1147 */ 1148 1149 puts("%%BeginProlog"); 1150 1151 do_prolog(doc, ppd); 1152 1153 puts("%%EndProlog"); 1154 1155 /* 1156 * Then the setup section... 1157 */ 1158 1159 puts("%%BeginSetup"); 1160 1161 do_setup(doc, ppd); 1162 1163 puts("%%EndSetup"); 1164 1165 /* 1166 * Finally, embed a copy of the file inside a %%Page... 1167 */ 1168 1169 if (!ppd || !ppd->num_filters) 1170 fprintf(stderr, "PAGE: 1 %d\n", doc->temp ? 1 : doc->copies); 1171 1172 puts("%%Page: 1 1"); 1173 puts("%%BeginPageSetup"); 1174 ppdEmit(ppd, stdout, PPD_ORDER_PAGE); 1175 puts("%%EndPageSetup"); 1176 puts("%%BeginDocument: nondsc"); 1177 1178 fwrite(line, linelen, 1, stdout); 1179 1180 if (doc->temp) 1181 cupsFileWrite(doc->temp, line, linelen); 1182 1183 while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0) 1184 { 1185 fwrite(buffer, 1, bytes, stdout); 1186 1187 if (doc->temp) 1188 cupsFileWrite(doc->temp, buffer, bytes); 1189 } 1190 1191 puts("%%EndDocument"); 1192 1193 if (doc->use_ESPshowpage) 1194 { 1195 WriteLabels(Orientation); 1196 puts("ESPshowpage"); 1197 } 1198 1199 if (doc->temp && !JobCanceled) 1200 { 1201 /* 1202 * Reopen the temporary file for reading... 1203 */ 1204 1205 cupsFileClose(doc->temp); 1206 1207 doc->temp = cupsFileOpen(doc->tempfile, "r"); 1208 1209 /* 1210 * Make the additional copies as needed... 1211 */ 1212 1213 for (copy = 1; copy < doc->copies; copy ++) 1214 { 1215 if (JobCanceled) 1216 break; 1217 1218 if (!ppd || !ppd->num_filters) 1219 fputs("PAGE: 1 1\n", stderr); 1220 1221 printf("%%%%Page: %d %d\n", copy + 1, copy + 1); 1222 puts("%%BeginPageSetup"); 1223 ppdEmit(ppd, stdout, PPD_ORDER_PAGE); 1224 puts("%%EndPageSetup"); 1225 puts("%%BeginDocument: nondsc"); 1226 1227 copy_bytes(doc->temp, 0, 0); 1228 1229 puts("%%EndDocument"); 1230 1231 if (doc->use_ESPshowpage) 1232 { 1233 WriteLabels(Orientation); 1234 puts("ESPshowpage"); 1235 } 1236 } 1237 } 1238 1239 /* 1240 * Restore the old showpage operator as needed... 1241 */ 1242 1243 if (doc->use_ESPshowpage) 1244 puts("userdict/showpage/ESPshowpage load put\n"); 1245} 1246 1247 1248/* 1249 * 'copy_page()' - Copy a page description. 1250 * 1251 * This function expects "line" to be filled with a %%Page comment line. 1252 * On return, "line" will contain the next line in the file, if any. 1253 */ 1254 1255static ssize_t /* O - Length of next line */ 1256copy_page(cups_file_t *fp, /* I - File to read from */ 1257 pstops_doc_t *doc, /* I - Document info */ 1258 ppd_file_t *ppd, /* I - PPD file */ 1259 int number, /* I - Current page number */ 1260 char *line, /* I - Line buffer */ 1261 ssize_t linelen, /* I - Length of initial line */ 1262 size_t linesize) /* I - Size of line buffer */ 1263{ 1264 char label[256], /* Page label string */ 1265 *ptr; /* Pointer into line */ 1266 int level; /* Embedded document level */ 1267 pstops_page_t *pageinfo; /* Page information */ 1268 int first_page; /* First page on N-up output? */ 1269 int has_page_setup = 0; /* Does the page have %%Begin/EndPageSetup? */ 1270 int bounding_box[4]; /* PageBoundingBox */ 1271 1272 1273 /* 1274 * Get the page label for this page... 1275 */ 1276 1277 first_page = is_first_page(number); 1278 1279 if (!parse_text(line + 7, &ptr, label, sizeof(label))) 1280 { 1281 fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr); 1282 label[0] = '\0'; 1283 number = doc->page; 1284 } 1285 else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255)) 1286 { 1287 fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr); 1288 number = doc->page; 1289 } 1290 1291 /* 1292 * Create or update the current output page... 1293 */ 1294 1295 if (first_page) 1296 pageinfo = add_page(doc, label); 1297 else 1298 pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages); 1299 1300 /* 1301 * Handle first page override... 1302 */ 1303 1304 if (doc->ap_input_slot || doc->ap_manual_feed) 1305 { 1306 if ((doc->page == 1 && (!doc->slow_order || !Duplex)) || 1307 (doc->page == 2 && doc->slow_order && Duplex)) 1308 { 1309 /* 1310 * First page/sheet gets AP_FIRSTPAGE_* options... 1311 */ 1312 1313 pageinfo->num_options = cupsAddOption("InputSlot", doc->ap_input_slot, 1314 pageinfo->num_options, 1315 &(pageinfo->options)); 1316 pageinfo->num_options = cupsAddOption("ManualFeed", 1317 doc->ap_input_slot ? "False" : 1318 doc->ap_manual_feed, 1319 pageinfo->num_options, 1320 &(pageinfo->options)); 1321 pageinfo->num_options = cupsAddOption("MediaColor", doc->ap_media_color, 1322 pageinfo->num_options, 1323 &(pageinfo->options)); 1324 pageinfo->num_options = cupsAddOption("MediaType", doc->ap_media_type, 1325 pageinfo->num_options, 1326 &(pageinfo->options)); 1327 pageinfo->num_options = cupsAddOption("PageRegion", doc->ap_page_region, 1328 pageinfo->num_options, 1329 &(pageinfo->options)); 1330 pageinfo->num_options = cupsAddOption("PageSize", doc->ap_page_size, 1331 pageinfo->num_options, 1332 &(pageinfo->options)); 1333 } 1334 else if (doc->page == (Duplex + 2)) 1335 { 1336 /* 1337 * Second page/sheet gets default options... 1338 */ 1339 1340 pageinfo->num_options = cupsAddOption("InputSlot", doc->input_slot, 1341 pageinfo->num_options, 1342 &(pageinfo->options)); 1343 pageinfo->num_options = cupsAddOption("ManualFeed", 1344 doc->input_slot ? "False" : 1345 doc->manual_feed, 1346 pageinfo->num_options, 1347 &(pageinfo->options)); 1348 pageinfo->num_options = cupsAddOption("MediaColor", doc->media_color, 1349 pageinfo->num_options, 1350 &(pageinfo->options)); 1351 pageinfo->num_options = cupsAddOption("MediaType", doc->media_type, 1352 pageinfo->num_options, 1353 &(pageinfo->options)); 1354 pageinfo->num_options = cupsAddOption("PageRegion", doc->page_region, 1355 pageinfo->num_options, 1356 &(pageinfo->options)); 1357 pageinfo->num_options = cupsAddOption("PageSize", doc->page_size, 1358 pageinfo->num_options, 1359 &(pageinfo->options)); 1360 } 1361 } 1362 1363 /* 1364 * Scan comments until we see something other than %%Page*: or 1365 * %%Include*... 1366 */ 1367 1368 memcpy(bounding_box, doc->bounding_box, sizeof(bounding_box)); 1369 1370 while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0) 1371 { 1372 if (!strncmp(line, "%%PageBoundingBox:", 18)) 1373 { 1374 /* 1375 * %%PageBoundingBox: llx lly urx ury 1376 */ 1377 1378 if (sscanf(line + 18, "%d%d%d%d", bounding_box + 0, 1379 bounding_box + 1, bounding_box + 2, 1380 bounding_box + 3) != 4) 1381 { 1382 fputs("DEBUG: There was a bad %%PageBoundingBox: comment in the file.\n", stderr); 1383 memcpy(bounding_box, doc->bounding_box, 1384 sizeof(bounding_box)); 1385 } 1386 else if (doc->number_up == 1 && !doc->fit_to_page && Orientation) 1387 { 1388 int temp_bbox[4]; /* Temporary bounding box */ 1389 1390 1391 memcpy(temp_bbox, bounding_box, sizeof(temp_bbox)); 1392 1393 fprintf(stderr, "DEBUG: Orientation = %d\n", Orientation); 1394 fprintf(stderr, "DEBUG: original bounding_box = [ %d %d %d %d ]\n", 1395 bounding_box[0], bounding_box[1], 1396 bounding_box[2], bounding_box[3]); 1397 fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", 1398 PageWidth, PageLength); 1399 1400 switch (Orientation) 1401 { 1402 case 1 : /* Landscape */ 1403 bounding_box[0] = PageLength - temp_bbox[3]; 1404 bounding_box[1] = temp_bbox[0]; 1405 bounding_box[2] = PageLength - temp_bbox[1]; 1406 bounding_box[3] = temp_bbox[2]; 1407 break; 1408 1409 case 2 : /* Reverse Portrait */ 1410 bounding_box[0] = PageWidth - temp_bbox[2]; 1411 bounding_box[1] = PageLength - temp_bbox[3]; 1412 bounding_box[2] = PageWidth - temp_bbox[0]; 1413 bounding_box[3] = PageLength - temp_bbox[1]; 1414 break; 1415 1416 case 3 : /* Reverse Landscape */ 1417 bounding_box[0] = temp_bbox[1]; 1418 bounding_box[1] = PageWidth - temp_bbox[2]; 1419 bounding_box[2] = temp_bbox[3]; 1420 bounding_box[3] = PageWidth - temp_bbox[0]; 1421 break; 1422 } 1423 1424 fprintf(stderr, "DEBUG: updated bounding_box = [ %d %d %d %d ]\n", 1425 bounding_box[0], bounding_box[1], 1426 bounding_box[2], bounding_box[3]); 1427 } 1428 } 1429#if 0 1430 else if (!strncmp(line, "%%PageCustomColors:", 19) || 1431 !strncmp(line, "%%PageMedia:", 12) || 1432 !strncmp(line, "%%PageOrientation:", 18) || 1433 !strncmp(line, "%%PageProcessColors:", 20) || 1434 !strncmp(line, "%%PageRequirements:", 18) || 1435 !strncmp(line, "%%PageResources:", 16)) 1436 { 1437 /* 1438 * Copy literal... 1439 */ 1440 } 1441#endif /* 0 */ 1442 else if (!strncmp(line, "%%PageCustomColors:", 19)) 1443 { 1444 /* 1445 * %%PageCustomColors: ... 1446 */ 1447 } 1448 else if (!strncmp(line, "%%PageMedia:", 12)) 1449 { 1450 /* 1451 * %%PageMedia: ... 1452 */ 1453 } 1454 else if (!strncmp(line, "%%PageOrientation:", 18)) 1455 { 1456 /* 1457 * %%PageOrientation: ... 1458 */ 1459 } 1460 else if (!strncmp(line, "%%PageProcessColors:", 20)) 1461 { 1462 /* 1463 * %%PageProcessColors: ... 1464 */ 1465 } 1466 else if (!strncmp(line, "%%PageRequirements:", 18)) 1467 { 1468 /* 1469 * %%PageRequirements: ... 1470 */ 1471 } 1472 else if (!strncmp(line, "%%PageResources:", 16)) 1473 { 1474 /* 1475 * %%PageResources: ... 1476 */ 1477 } 1478 else if (!strncmp(line, "%%IncludeFeature:", 17)) 1479 { 1480 /* 1481 * %%IncludeFeature: *MainKeyword OptionKeyword 1482 */ 1483 1484 if (doc->number_up == 1 &&!doc->fit_to_page) 1485 pageinfo->num_options = include_feature(ppd, line, 1486 pageinfo->num_options, 1487 &(pageinfo->options)); 1488 } 1489 else if (!strncmp(line, "%%BeginPageSetup", 16)) 1490 { 1491 has_page_setup = 1; 1492 break; 1493 } 1494 else 1495 break; 1496 } 1497 1498 if (doc->number_up == 1) 1499 { 1500 /* 1501 * Update the document's composite and page bounding box... 1502 */ 1503 1504 memcpy(pageinfo->bounding_box, bounding_box, 1505 sizeof(pageinfo->bounding_box)); 1506 1507 if (bounding_box[0] < doc->new_bounding_box[0]) 1508 doc->new_bounding_box[0] = bounding_box[0]; 1509 if (bounding_box[1] < doc->new_bounding_box[1]) 1510 doc->new_bounding_box[1] = bounding_box[1]; 1511 if (bounding_box[2] > doc->new_bounding_box[2]) 1512 doc->new_bounding_box[2] = bounding_box[2]; 1513 if (bounding_box[3] > doc->new_bounding_box[3]) 1514 doc->new_bounding_box[3] = bounding_box[3]; 1515 } 1516 1517 /* 1518 * Output the page header as needed... 1519 */ 1520 1521 if (!doc->slow_order && first_page) 1522 { 1523 if (!ppd || !ppd->num_filters) 1524 fprintf(stderr, "PAGE: %d %d\n", doc->page, 1525 doc->slow_collate ? 1 : doc->copies); 1526 1527 if (doc->number_up > 1) 1528 { 1529 printf("%%%%Page: (%d) %d\n", doc->page, doc->page); 1530 printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n", 1531 PageLeft, PageBottom, PageRight, PageTop); 1532 } 1533 else 1534 { 1535 printf("%%%%Page: %s %d\n", pageinfo->label, doc->page); 1536 printf("%%%%PageBoundingBox: %d %d %d %d\n", 1537 pageinfo->bounding_box[0], pageinfo->bounding_box[1], 1538 pageinfo->bounding_box[2], pageinfo->bounding_box[3]); 1539 } 1540 } 1541 1542 /* 1543 * Copy any page setup commands... 1544 */ 1545 1546 if (first_page) 1547 doc_puts(doc, "%%BeginPageSetup\n"); 1548 1549 if (has_page_setup) 1550 { 1551 int feature = 0; /* In a Begin/EndFeature block? */ 1552 1553 while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0) 1554 { 1555 if (!strncmp(line, "%%EndPageSetup", 14)) 1556 break; 1557 else if (!strncmp(line, "%%BeginFeature:", 15)) 1558 { 1559 feature = 1; 1560 1561 if (doc->number_up > 1 || doc->fit_to_page) 1562 continue; 1563 } 1564 else if (!strncmp(line, "%%EndFeature", 12)) 1565 { 1566 feature = 0; 1567 1568 if (doc->number_up > 1 || doc->fit_to_page) 1569 continue; 1570 } 1571 else if (!strncmp(line, "%%IncludeFeature:", 17)) 1572 { 1573 pageinfo->num_options = include_feature(ppd, line, 1574 pageinfo->num_options, 1575 &(pageinfo->options)); 1576 continue; 1577 } 1578 else if (!strncmp(line, "%%Include", 9)) 1579 continue; 1580 1581 if (line[0] != '%' && !feature) 1582 break; 1583 1584 if (!feature || (doc->number_up == 1 && !doc->fit_to_page)) 1585 doc_write(doc, line, linelen); 1586 } 1587 1588 /* 1589 * Skip %%EndPageSetup... 1590 */ 1591 1592 if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14)) 1593 linelen = cupsFileGetLine(fp, line, linesize); 1594 } 1595 1596 if (first_page) 1597 { 1598 char *page_setup; /* PageSetup commands to send */ 1599 1600 1601 if (pageinfo->num_options > 0) 1602 write_options(doc, ppd, pageinfo->num_options, pageinfo->options); 1603 1604 /* 1605 * Output commands for the current page... 1606 */ 1607 1608 page_setup = ppdEmitString(ppd, PPD_ORDER_PAGE, 0); 1609 1610 if (page_setup) 1611 { 1612 doc_puts(doc, page_setup); 1613 free(page_setup); 1614 } 1615 } 1616 1617 /* 1618 * Prep for the start of the page description... 1619 */ 1620 1621 start_nup(doc, number, 1, bounding_box); 1622 1623 if (first_page) 1624 doc_puts(doc, "%%EndPageSetup\n"); 1625 1626 /* 1627 * Read the rest of the page description... 1628 */ 1629 1630 level = 0; 1631 1632 do 1633 { 1634 if (level == 0 && 1635 (!strncmp(line, "%%Page:", 7) || 1636 !strncmp(line, "%%Trailer", 9) || 1637 !strncmp(line, "%%EOF", 5))) 1638 break; 1639 else if (!strncmp(line, "%%BeginDocument", 15) || 1640 !strncmp(line, "%ADO_BeginApplication", 21)) 1641 { 1642 doc_write(doc, line, linelen); 1643 1644 level ++; 1645 } 1646 else if ((!strncmp(line, "%%EndDocument", 13) || 1647 !strncmp(line, "%ADO_EndApplication", 19)) && level > 0) 1648 { 1649 doc_write(doc, line, linelen); 1650 1651 level --; 1652 } 1653 else if (!strncmp(line, "%%BeginBinary:", 14) || 1654 (!strncmp(line, "%%BeginData:", 12) && 1655 !strstr(line, "ASCII") && !strstr(line, "Hex"))) 1656 { 1657 /* 1658 * Copy binary data... 1659 */ 1660 1661 int bytes; /* Bytes of data */ 1662 1663 1664 doc_write(doc, line, linelen); 1665 1666 bytes = atoi(strchr(line, ':') + 1); 1667 1668 while (bytes > 0) 1669 { 1670 if (bytes > linesize) 1671 linelen = cupsFileRead(fp, line, linesize); 1672 else 1673 linelen = cupsFileRead(fp, line, bytes); 1674 1675 if (linelen < 1) 1676 { 1677 line[0] = '\0'; 1678 perror("ERROR: Early end-of-file while reading binary data"); 1679 return (0); 1680 } 1681 1682 doc_write(doc, line, linelen); 1683 1684 bytes -= linelen; 1685 } 1686 } 1687 else 1688 doc_write(doc, line, linelen); 1689 } 1690 while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0); 1691 1692 /* 1693 * Finish up this page and return... 1694 */ 1695 1696 end_nup(doc, number); 1697 1698 pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset; 1699 1700 return (linelen); 1701} 1702 1703 1704/* 1705 * 'copy_prolog()' - Copy the document prolog section. 1706 * 1707 * This function expects "line" to be filled with a %%BeginProlog comment line. 1708 * On return, "line" will contain the next line in the file, if any. 1709 */ 1710 1711static ssize_t /* O - Length of next line */ 1712copy_prolog(cups_file_t *fp, /* I - File to read from */ 1713 pstops_doc_t *doc, /* I - Document info */ 1714 ppd_file_t *ppd, /* I - PPD file */ 1715 char *line, /* I - Line buffer */ 1716 ssize_t linelen, /* I - Length of initial line */ 1717 size_t linesize) /* I - Size of line buffer */ 1718{ 1719 while (strncmp(line, "%%BeginProlog", 13)) 1720 { 1721 if (!strncmp(line, "%%BeginSetup", 12) || !strncmp(line, "%%Page:", 7)) 1722 break; 1723 1724 doc_write(doc, line, linelen); 1725 1726 if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0) 1727 break; 1728 } 1729 1730 doc_puts(doc, "%%BeginProlog\n"); 1731 1732 do_prolog(doc, ppd); 1733 1734 if (!strncmp(line, "%%BeginProlog", 13)) 1735 { 1736 while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0) 1737 { 1738 if (!strncmp(line, "%%EndProlog", 11) || 1739 !strncmp(line, "%%BeginSetup", 12) || 1740 !strncmp(line, "%%Page:", 7)) 1741 break; 1742 1743 doc_write(doc, line, linelen); 1744 } 1745 1746 if (!strncmp(line, "%%EndProlog", 11)) 1747 linelen = cupsFileGetLine(fp, line, linesize); 1748 else 1749 fputs("DEBUG: The %%EndProlog comment is missing.\n", stderr); 1750 } 1751 1752 doc_puts(doc, "%%EndProlog\n"); 1753 1754 return (linelen); 1755} 1756 1757 1758/* 1759 * 'copy_setup()' - Copy the document setup section. 1760 * 1761 * This function expects "line" to be filled with a %%BeginSetup comment line. 1762 * On return, "line" will contain the next line in the file, if any. 1763 */ 1764 1765static ssize_t /* O - Length of next line */ 1766copy_setup(cups_file_t *fp, /* I - File to read from */ 1767 pstops_doc_t *doc, /* I - Document info */ 1768 ppd_file_t *ppd, /* I - PPD file */ 1769 char *line, /* I - Line buffer */ 1770 ssize_t linelen, /* I - Length of initial line */ 1771 size_t linesize) /* I - Size of line buffer */ 1772{ 1773 int num_options; /* Number of options */ 1774 cups_option_t *options; /* Options */ 1775 1776 1777 while (strncmp(line, "%%BeginSetup", 12)) 1778 { 1779 if (!strncmp(line, "%%Page:", 7)) 1780 break; 1781 1782 doc_write(doc, line, linelen); 1783 1784 if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0) 1785 break; 1786 } 1787 1788 doc_puts(doc, "%%BeginSetup\n"); 1789 1790 do_setup(doc, ppd); 1791 1792 num_options = 0; 1793 options = NULL; 1794 1795 if (!strncmp(line, "%%BeginSetup", 12)) 1796 { 1797 while (strncmp(line, "%%EndSetup", 10)) 1798 { 1799 if (!strncmp(line, "%%Page:", 7)) 1800 break; 1801 else if (!strncmp(line, "%%IncludeFeature:", 17)) 1802 { 1803 /* 1804 * %%IncludeFeature: *MainKeyword OptionKeyword 1805 */ 1806 1807 if (doc->number_up == 1 && !doc->fit_to_page) 1808 num_options = include_feature(ppd, line, num_options, &options); 1809 } 1810 else if (strncmp(line, "%%BeginSetup", 12)) 1811 doc_write(doc, line, linelen); 1812 1813 if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0) 1814 break; 1815 } 1816 1817 if (!strncmp(line, "%%EndSetup", 10)) 1818 linelen = cupsFileGetLine(fp, line, linesize); 1819 else 1820 fputs("DEBUG: The %%EndSetup comment is missing.\n", stderr); 1821 } 1822 1823 if (num_options > 0) 1824 { 1825 write_options(doc, ppd, num_options, options); 1826 cupsFreeOptions(num_options, options); 1827 } 1828 1829 doc_puts(doc, "%%EndSetup\n"); 1830 1831 return (linelen); 1832} 1833 1834 1835/* 1836 * 'copy_trailer()' - Copy the document trailer. 1837 * 1838 * This function expects "line" to be filled with a %%Trailer comment line. 1839 * On return, "line" will contain the next line in the file, if any. 1840 */ 1841 1842static ssize_t /* O - Length of next line */ 1843copy_trailer(cups_file_t *fp, /* I - File to read from */ 1844 pstops_doc_t *doc, /* I - Document info */ 1845 ppd_file_t *ppd, /* I - PPD file */ 1846 int number, /* I - Number of pages */ 1847 char *line, /* I - Line buffer */ 1848 ssize_t linelen, /* I - Length of initial line */ 1849 size_t linesize) /* I - Size of line buffer */ 1850{ 1851 /* 1852 * Write the trailer comments... 1853 */ 1854 1855 puts("%%Trailer"); 1856 1857 while (linelen > 0) 1858 { 1859 if (!strncmp(line, "%%EOF", 5)) 1860 break; 1861 else if (strncmp(line, "%%Trailer", 9) && 1862 strncmp(line, "%%Pages:", 8) && 1863 strncmp(line, "%%BoundingBox:", 14)) 1864 fwrite(line, 1, linelen, stdout); 1865 1866 linelen = cupsFileGetLine(fp, line, linesize); 1867 } 1868 1869 fprintf(stderr, "DEBUG: Wrote %d pages...\n", number); 1870 1871 printf("%%%%Pages: %d\n", number); 1872 if (doc->number_up > 1 || doc->fit_to_page) 1873 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", 1874 PageLeft, PageBottom, PageRight, PageTop); 1875 else 1876 printf("%%%%BoundingBox: %d %d %d %d\n", 1877 doc->new_bounding_box[0], doc->new_bounding_box[1], 1878 doc->new_bounding_box[2], doc->new_bounding_box[3]); 1879 1880 return (linelen); 1881} 1882 1883 1884/* 1885 * 'do_prolog()' - Send the necessary document prolog commands. 1886 */ 1887 1888static void 1889do_prolog(pstops_doc_t *doc, /* I - Document information */ 1890 ppd_file_t *ppd) /* I - PPD file */ 1891{ 1892 char *ps; /* PS commands */ 1893 1894 1895 /* 1896 * Send the document prolog commands... 1897 */ 1898 1899 if (ppd && ppd->patches) 1900 { 1901 doc_puts(doc, "%%BeginFeature: *JobPatchFile 1\n"); 1902 doc_puts(doc, ppd->patches); 1903 doc_puts(doc, "\n%%EndFeature\n"); 1904 } 1905 1906 if ((ps = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL) 1907 { 1908 doc_puts(doc, ps); 1909 free(ps); 1910 } 1911 1912 /* 1913 * Define ESPshowpage here so that applications that define their 1914 * own procedure to do a showpage pick it up... 1915 */ 1916 1917 if (doc->use_ESPshowpage) 1918 doc_puts(doc, "userdict/ESPshowpage/showpage load put\n" 1919 "userdict/showpage{}put\n"); 1920} 1921 1922 1923/* 1924 * 'do_setup()' - Send the necessary document setup commands. 1925 */ 1926 1927static void 1928do_setup(pstops_doc_t *doc, /* I - Document information */ 1929 ppd_file_t *ppd) /* I - PPD file */ 1930{ 1931 char *ps; /* PS commands */ 1932 1933 1934 /* 1935 * Disable CTRL-D so that embedded files don't cause printing 1936 * errors... 1937 */ 1938 1939 doc_puts(doc, "% Disable CTRL-D as an end-of-file marker...\n"); 1940 doc_puts(doc, "userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n"); 1941 1942 /* 1943 * Mark job options... 1944 */ 1945 1946 cupsMarkOptions(ppd, doc->num_options, doc->options); 1947 1948 /* 1949 * Send all the printer-specific setup commands... 1950 */ 1951 1952 if ((ps = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL) 1953 { 1954 doc_puts(doc, ps); 1955 free(ps); 1956 } 1957 1958 if ((ps = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL) 1959 { 1960 doc_puts(doc, ps); 1961 free(ps); 1962 } 1963 1964 /* 1965 * Set the number of copies for the job... 1966 */ 1967 1968 if (doc->copies != 1 && (!doc->collate || !doc->slow_collate)) 1969 { 1970 doc_printf(doc, "%%RBIBeginNonPPDFeature: *NumCopies %d\n", doc->copies); 1971 doc_printf(doc, 1972 "%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n" 1973 "{1 dict begin/NumCopies exch def currentdict end " 1974 "setpagedevice}\n" 1975 "{userdict/#copies 3 -1 roll put}ifelse\n", doc->copies); 1976 doc_puts(doc, "%RBIEndNonPPDFeature\n"); 1977 } 1978 1979 /* 1980 * If we are doing N-up printing, disable setpagedevice... 1981 */ 1982 1983 if (doc->number_up > 1) 1984 { 1985 doc_puts(doc, "userdict/CUPSsetpagedevice/setpagedevice load put\n"); 1986 doc_puts(doc, "userdict/setpagedevice{pop}bind put\n"); 1987 } 1988 1989 /* 1990 * Make sure we have rectclip and rectstroke procedures of some sort... 1991 */ 1992 1993 doc_puts(doc, 1994 "% x y w h ESPrc - Clip to a rectangle.\n" 1995 "userdict/ESPrc/rectclip where{pop/rectclip load}\n" 1996 "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" 1997 "neg 0 rlineto closepath clip newpath}bind}ifelse put\n"); 1998 1999 doc_puts(doc, 2000 "% x y w h ESPrf - Fill a rectangle.\n" 2001 "userdict/ESPrf/rectfill where{pop/rectfill load}\n" 2002 "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" 2003 "neg 0 rlineto closepath fill grestore}bind}ifelse put\n"); 2004 2005 doc_puts(doc, 2006 "% x y w h ESPrs - Stroke a rectangle.\n" 2007 "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n" 2008 "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" 2009 "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n"); 2010 2011 /* 2012 * Write the page and label prologs... 2013 */ 2014 2015 if (doc->number_up == 2 || doc->number_up == 6) 2016 { 2017 /* 2018 * For 2- and 6-up output, rotate the labels to match the orientation 2019 * of the pages... 2020 */ 2021 2022 if (Orientation & 1) 2023 write_label_prolog(doc, doc->page_label, PageBottom, 2024 PageWidth - PageLength + PageTop, PageLength); 2025 else 2026 write_label_prolog(doc, doc->page_label, PageLeft, PageRight, 2027 PageLength); 2028 } 2029 else 2030 write_label_prolog(doc, doc->page_label, PageBottom, PageTop, PageWidth); 2031} 2032 2033 2034/* 2035 * 'doc_printf()' - Send a formatted string to stdout and/or the temp file. 2036 * 2037 * This function should be used for all page-level output that is affected 2038 * by ordering, collation, etc. 2039 */ 2040 2041static void 2042doc_printf(pstops_doc_t *doc, /* I - Document information */ 2043 const char *format, /* I - Printf-style format string */ 2044 ...) /* I - Additional arguments as needed */ 2045{ 2046 va_list ap; /* Pointer to arguments */ 2047 char buffer[1024]; /* Output buffer */ 2048 size_t bytes; /* Number of bytes to write */ 2049 2050 2051 va_start(ap, format); 2052 bytes = vsnprintf(buffer, sizeof(buffer), format, ap); 2053 va_end(ap); 2054 2055 if (bytes > sizeof(buffer)) 2056 { 2057 _cupsLangPrintFilter(stderr, "ERROR", 2058 _("Buffer overflow detected, aborting.")); 2059 exit(1); 2060 } 2061 2062 doc_write(doc, buffer, bytes); 2063} 2064 2065 2066/* 2067 * 'doc_puts()' - Send a nul-terminated string to stdout and/or the temp file. 2068 * 2069 * This function should be used for all page-level output that is affected 2070 * by ordering, collation, etc. 2071 */ 2072 2073static void 2074doc_puts(pstops_doc_t *doc, /* I - Document information */ 2075 const char *s) /* I - String to send */ 2076{ 2077 doc_write(doc, s, strlen(s)); 2078} 2079 2080 2081/* 2082 * 'doc_write()' - Send data to stdout and/or the temp file. 2083 */ 2084 2085static void 2086doc_write(pstops_doc_t *doc, /* I - Document information */ 2087 const char *s, /* I - Data to send */ 2088 size_t len) /* I - Number of bytes to send */ 2089{ 2090 if (!doc->slow_order) 2091 fwrite(s, 1, len, stdout); 2092 2093 if (doc->temp) 2094 cupsFileWrite(doc->temp, s, len); 2095} 2096 2097 2098/* 2099 * 'end_nup()' - End processing for N-up printing. 2100 */ 2101 2102static void 2103end_nup(pstops_doc_t *doc, /* I - Document information */ 2104 int number) /* I - Page number */ 2105{ 2106 if (doc->number_up > 1) 2107 doc_puts(doc, "userdict/ESPsave get restore\n"); 2108 2109 switch (doc->number_up) 2110 { 2111 case 1 : 2112 if (doc->use_ESPshowpage) 2113 { 2114 write_labels(doc, Orientation); 2115 doc_puts(doc, "ESPshowpage\n"); 2116 } 2117 break; 2118 2119 case 2 : 2120 case 6 : 2121 if (is_last_page(number) && doc->use_ESPshowpage) 2122 { 2123 if (Orientation & 1) 2124 { 2125 /* 2126 * Rotate the labels back to portrait... 2127 */ 2128 2129 write_labels(doc, Orientation - 1); 2130 } 2131 else if (Orientation == 0) 2132 { 2133 /* 2134 * Rotate the labels to landscape... 2135 */ 2136 2137 write_labels(doc, doc->normal_landscape ? 1 : 3); 2138 } 2139 else 2140 { 2141 /* 2142 * Rotate the labels to landscape... 2143 */ 2144 2145 write_labels(doc, doc->normal_landscape ? 3 : 1); 2146 } 2147 2148 doc_puts(doc, "ESPshowpage\n"); 2149 } 2150 break; 2151 2152 default : 2153 if (is_last_page(number) && doc->use_ESPshowpage) 2154 { 2155 write_labels(doc, Orientation); 2156 doc_puts(doc, "ESPshowpage\n"); 2157 } 2158 break; 2159 } 2160 2161 fflush(stdout); 2162} 2163 2164 2165/* 2166 * 'include_feature()' - Include a printer option/feature command. 2167 */ 2168 2169static int /* O - New number of options */ 2170include_feature( 2171 ppd_file_t *ppd, /* I - PPD file */ 2172 const char *line, /* I - DSC line */ 2173 int num_options, /* I - Number of options */ 2174 cups_option_t **options) /* IO - Options */ 2175{ 2176 char name[255], /* Option name */ 2177 value[255]; /* Option value */ 2178 ppd_option_t *option; /* Option in file */ 2179 2180 2181 /* 2182 * Get the "%%IncludeFeature: *Keyword OptionKeyword" values... 2183 */ 2184 2185 if (sscanf(line + 17, "%254s%254s", name, value) != 2) 2186 { 2187 fputs("DEBUG: The %%IncludeFeature: comment is not valid.\n", stderr); 2188 return (num_options); 2189 } 2190 2191 /* 2192 * Find the option and choice... 2193 */ 2194 2195 if ((option = ppdFindOption(ppd, name + 1)) == NULL) 2196 { 2197 _cupsLangPrintFilter(stderr, "WARNING", _("Unknown option \"%s\"."), 2198 name + 1); 2199 return (num_options); 2200 } 2201 2202 if (option->section == PPD_ORDER_EXIT || 2203 option->section == PPD_ORDER_JCL) 2204 { 2205 _cupsLangPrintFilter(stderr, "WARNING", 2206 _("Option \"%s\" cannot be included via " 2207 "%%%%IncludeFeature."), name + 1); 2208 return (num_options); 2209 } 2210 2211 if (!ppdFindChoice(option, value)) 2212 { 2213 _cupsLangPrintFilter(stderr, "WARNING", 2214 _("Unknown choice \"%s\" for option \"%s\"."), 2215 value, name + 1); 2216 return (num_options); 2217 } 2218 2219 /* 2220 * Add the option to the option array and return... 2221 */ 2222 2223 return (cupsAddOption(name + 1, value, num_options, options)); 2224} 2225 2226 2227/* 2228 * 'parse_text()' - Parse a text value in a comment. 2229 * 2230 * This function parses a DSC text value as defined on page 36 of the 2231 * DSC specification. Text values are either surrounded by parenthesis 2232 * or whitespace-delimited. 2233 * 2234 * The value returned is the literal characters for the entire text 2235 * string, including any parenthesis and escape characters. 2236 */ 2237 2238static char * /* O - Value or NULL on error */ 2239parse_text(const char *start, /* I - Start of text value */ 2240 char **end, /* O - End of text value */ 2241 char *buffer, /* I - Buffer */ 2242 size_t bufsize) /* I - Size of buffer */ 2243{ 2244 char *bufptr, /* Pointer in buffer */ 2245 *bufend; /* End of buffer */ 2246 int level; /* Parenthesis level */ 2247 2248 2249 /* 2250 * Skip leading whitespace... 2251 */ 2252 2253 while (isspace(*start & 255)) 2254 start ++; 2255 2256 /* 2257 * Then copy the value... 2258 */ 2259 2260 level = 0; 2261 bufptr = buffer; 2262 bufend = buffer + bufsize - 1; 2263 2264 while (bufptr < bufend) 2265 { 2266 if (isspace(*start & 255) && !level) 2267 break; 2268 2269 *bufptr++ = *start; 2270 2271 if (*start == '(') 2272 level ++; 2273 else if (*start == ')') 2274 { 2275 if (!level) 2276 { 2277 start ++; 2278 break; 2279 } 2280 else 2281 level --; 2282 } 2283 else if (*start == '\\') 2284 { 2285 /* 2286 * Copy escaped character... 2287 */ 2288 2289 int i; /* Looping var */ 2290 2291 2292 for (i = 1; 2293 i <= 3 && isdigit(start[i] & 255) && bufptr < bufend; 2294 *bufptr++ = start[i], i ++); 2295 } 2296 2297 start ++; 2298 } 2299 2300 *bufptr = '\0'; 2301 2302 /* 2303 * Return the value and new pointer into the line... 2304 */ 2305 2306 if (end) 2307 *end = (char *)start; 2308 2309 if (bufptr == bufend) 2310 return (NULL); 2311 else 2312 return (buffer); 2313} 2314 2315 2316/* 2317 * 'set_pstops_options()' - Set pstops options. 2318 */ 2319 2320static void 2321set_pstops_options( 2322 pstops_doc_t *doc, /* I - Document information */ 2323 ppd_file_t *ppd, /* I - PPD file */ 2324 char *argv[], /* I - Command-line arguments */ 2325 int num_options, /* I - Number of options */ 2326 cups_option_t *options) /* I - Options */ 2327{ 2328 const char *val; /* Option value */ 2329 int intval; /* Integer option value */ 2330 ppd_attr_t *attr; /* PPD attribute */ 2331 ppd_option_t *option; /* PPD option */ 2332 ppd_choice_t *choice; /* PPD choice */ 2333 const char *content_type; /* Original content type */ 2334 int max_copies; /* Maximum number of copies supported */ 2335 2336 2337 /* 2338 * Initialize document information structure... 2339 */ 2340 2341 memset(doc, 0, sizeof(pstops_doc_t)); 2342 2343 doc->job_id = atoi(argv[1]); 2344 doc->user = argv[2]; 2345 doc->title = argv[3]; 2346 doc->copies = atoi(argv[4]); 2347 2348 if (ppd && ppd->landscape > 0) 2349 doc->normal_landscape = 1; 2350 2351 doc->bounding_box[0] = (int)PageLeft; 2352 doc->bounding_box[1] = (int)PageBottom; 2353 doc->bounding_box[2] = (int)PageRight; 2354 doc->bounding_box[3] = (int)PageTop; 2355 2356 doc->new_bounding_box[0] = INT_MAX; 2357 doc->new_bounding_box[1] = INT_MAX; 2358 doc->new_bounding_box[2] = INT_MIN; 2359 doc->new_bounding_box[3] = INT_MIN; 2360 2361 /* 2362 * AP_FIRSTPAGE_* and the corresponding non-first-page options. 2363 */ 2364 2365 doc->ap_input_slot = cupsGetOption("AP_FIRSTPAGE_InputSlot", num_options, 2366 options); 2367 doc->ap_manual_feed = cupsGetOption("AP_FIRSTPAGE_ManualFeed", num_options, 2368 options); 2369 doc->ap_media_color = cupsGetOption("AP_FIRSTPAGE_MediaColor", num_options, 2370 options); 2371 doc->ap_media_type = cupsGetOption("AP_FIRSTPAGE_MediaType", num_options, 2372 options); 2373 doc->ap_page_region = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options, 2374 options); 2375 doc->ap_page_size = cupsGetOption("AP_FIRSTPAGE_PageSize", num_options, 2376 options); 2377 2378 if ((choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL) 2379 doc->input_slot = choice->choice; 2380 if ((choice = ppdFindMarkedChoice(ppd, "ManualFeed")) != NULL) 2381 doc->manual_feed = choice->choice; 2382 if ((choice = ppdFindMarkedChoice(ppd, "MediaColor")) != NULL) 2383 doc->media_color = choice->choice; 2384 if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL) 2385 doc->media_type = choice->choice; 2386 if ((choice = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL) 2387 doc->page_region = choice->choice; 2388 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL) 2389 doc->page_size = choice->choice; 2390 2391 /* 2392 * collate, multiple-document-handling 2393 */ 2394 2395 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) 2396 { 2397 /* 2398 * This IPP attribute is unnecessarily complicated... 2399 * 2400 * single-document, separate-documents-collated-copies, and 2401 * single-document-new-sheet all require collated copies. 2402 * 2403 * separate-documents-uncollated-copies allows for uncollated copies. 2404 */ 2405 2406 doc->collate = _cups_strcasecmp(val, "separate-documents-uncollated-copies") != 0; 2407 } 2408 2409 if ((val = cupsGetOption("Collate", num_options, options)) != NULL && 2410 (!_cups_strcasecmp(val, "true") ||!_cups_strcasecmp(val, "on") || 2411 !_cups_strcasecmp(val, "yes"))) 2412 doc->collate = 1; 2413 2414 /* 2415 * emit-jcl 2416 */ 2417 2418 if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL && 2419 (!_cups_strcasecmp(val, "false") || !_cups_strcasecmp(val, "off") || 2420 !_cups_strcasecmp(val, "no") || !strcmp(val, "0"))) 2421 doc->emit_jcl = 0; 2422 else 2423 doc->emit_jcl = 1; 2424 2425 /* 2426 * fit-to-page/ipp-attribute-fidelity 2427 * 2428 * (Only for original PostScript content) 2429 */ 2430 2431 if ((content_type = getenv("CONTENT_TYPE")) == NULL) 2432 content_type = "application/postscript"; 2433 2434 if (!_cups_strcasecmp(content_type, "application/postscript")) 2435 { 2436 if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL && 2437 !_cups_strcasecmp(val, "true")) 2438 doc->fit_to_page = 1; 2439 else if ((val = cupsGetOption("ipp-attribute-fidelity", num_options, 2440 options)) != NULL && 2441 !_cups_strcasecmp(val, "true")) 2442 doc->fit_to_page = 1; 2443 } 2444 2445 /* 2446 * mirror/MirrorPrint 2447 */ 2448 2449 if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL) 2450 { 2451 val = choice->choice; 2452 choice->marked = 0; 2453 } 2454 else 2455 val = cupsGetOption("mirror", num_options, options); 2456 2457 if (val && (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") || 2458 !_cups_strcasecmp(val, "yes"))) 2459 doc->mirror = 1; 2460 2461 /* 2462 * number-up 2463 */ 2464 2465 if ((val = cupsGetOption("number-up", num_options, options)) != NULL) 2466 { 2467 switch (intval = atoi(val)) 2468 { 2469 case 1 : 2470 case 2 : 2471 case 4 : 2472 case 6 : 2473 case 9 : 2474 case 16 : 2475 doc->number_up = intval; 2476 break; 2477 default : 2478 _cupsLangPrintFilter(stderr, "ERROR", 2479 _("Unsupported number-up value %d, using " 2480 "number-up=1."), intval); 2481 doc->number_up = 1; 2482 break; 2483 } 2484 } 2485 else 2486 doc->number_up = 1; 2487 2488 /* 2489 * number-up-layout 2490 */ 2491 2492 if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL) 2493 { 2494 if (!_cups_strcasecmp(val, "lrtb")) 2495 doc->number_up_layout = PSTOPS_LAYOUT_LRTB; 2496 else if (!_cups_strcasecmp(val, "lrbt")) 2497 doc->number_up_layout = PSTOPS_LAYOUT_LRBT; 2498 else if (!_cups_strcasecmp(val, "rltb")) 2499 doc->number_up_layout = PSTOPS_LAYOUT_RLTB; 2500 else if (!_cups_strcasecmp(val, "rlbt")) 2501 doc->number_up_layout = PSTOPS_LAYOUT_RLBT; 2502 else if (!_cups_strcasecmp(val, "tblr")) 2503 doc->number_up_layout = PSTOPS_LAYOUT_TBLR; 2504 else if (!_cups_strcasecmp(val, "tbrl")) 2505 doc->number_up_layout = PSTOPS_LAYOUT_TBRL; 2506 else if (!_cups_strcasecmp(val, "btlr")) 2507 doc->number_up_layout = PSTOPS_LAYOUT_BTLR; 2508 else if (!_cups_strcasecmp(val, "btrl")) 2509 doc->number_up_layout = PSTOPS_LAYOUT_BTRL; 2510 else 2511 { 2512 _cupsLangPrintFilter(stderr, "ERROR", 2513 _("Unsupported number-up-layout value %s, using " 2514 "number-up-layout=lrtb."), val); 2515 doc->number_up_layout = PSTOPS_LAYOUT_LRTB; 2516 } 2517 } 2518 else 2519 doc->number_up_layout = PSTOPS_LAYOUT_LRTB; 2520 2521 /* 2522 * OutputOrder 2523 */ 2524 2525 if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL) 2526 { 2527 if (!_cups_strcasecmp(val, "Reverse")) 2528 doc->output_order = 1; 2529 } 2530 else if (ppd) 2531 { 2532 /* 2533 * Figure out the right default output order from the PPD file... 2534 */ 2535 2536 if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL && 2537 (attr = ppdFindAttr(ppd, "PageStackOrder", choice->choice)) != NULL && 2538 attr->value) 2539 doc->output_order = !_cups_strcasecmp(attr->value, "Reverse"); 2540 else if ((attr = ppdFindAttr(ppd, "DefaultOutputOrder", NULL)) != NULL && 2541 attr->value) 2542 doc->output_order = !_cups_strcasecmp(attr->value, "Reverse"); 2543 } 2544 2545 /* 2546 * page-border 2547 */ 2548 2549 if ((val = cupsGetOption("page-border", num_options, options)) != NULL) 2550 { 2551 if (!_cups_strcasecmp(val, "none")) 2552 doc->page_border = PSTOPS_BORDERNONE; 2553 else if (!_cups_strcasecmp(val, "single")) 2554 doc->page_border = PSTOPS_BORDERSINGLE; 2555 else if (!_cups_strcasecmp(val, "single-thick")) 2556 doc->page_border = PSTOPS_BORDERSINGLE2; 2557 else if (!_cups_strcasecmp(val, "double")) 2558 doc->page_border = PSTOPS_BORDERDOUBLE; 2559 else if (!_cups_strcasecmp(val, "double-thick")) 2560 doc->page_border = PSTOPS_BORDERDOUBLE2; 2561 else 2562 { 2563 _cupsLangPrintFilter(stderr, "ERROR", 2564 _("Unsupported page-border value %s, using " 2565 "page-border=none."), val); 2566 doc->page_border = PSTOPS_BORDERNONE; 2567 } 2568 } 2569 else 2570 doc->page_border = PSTOPS_BORDERNONE; 2571 2572 /* 2573 * page-label 2574 */ 2575 2576 doc->page_label = cupsGetOption("page-label", num_options, options); 2577 2578 /* 2579 * page-ranges 2580 */ 2581 2582 doc->page_ranges = cupsGetOption("page-ranges", num_options, options); 2583 2584 /* 2585 * page-set 2586 */ 2587 2588 doc->page_set = cupsGetOption("page-set", num_options, options); 2589 2590 /* 2591 * Now figure out if we have to force collated copies, etc. 2592 */ 2593 2594 if ((attr = ppdFindAttr(ppd, "cupsMaxCopies", NULL)) != NULL) 2595 max_copies = atoi(attr->value); 2596 else if (ppd && ppd->manual_copies) 2597 max_copies = 1; 2598 else 2599 max_copies = 9999; 2600 2601 if (doc->copies > max_copies) 2602 doc->collate = 1; 2603 else if (ppd && ppd->manual_copies && Duplex && doc->copies > 1) 2604 { 2605 /* 2606 * Force collated copies when printing a duplexed document to 2607 * a non-PS printer that doesn't do hardware copy generation. 2608 * Otherwise the copies will end up on the front/back side of 2609 * each page. 2610 */ 2611 2612 doc->collate = 1; 2613 } 2614 2615 /* 2616 * See if we have to filter the fast or slow way... 2617 */ 2618 2619 if (doc->collate && doc->copies > 1) 2620 { 2621 /* 2622 * See if we need to manually collate the pages... 2623 */ 2624 2625 doc->slow_collate = 1; 2626 2627 if (doc->copies <= max_copies && 2628 (choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL && 2629 !_cups_strcasecmp(choice->choice, "True")) 2630 { 2631 /* 2632 * Hardware collate option is selected, see if the option is 2633 * conflicting - if not, collate in hardware. Otherwise, 2634 * turn the hardware collate option off... 2635 */ 2636 2637 if ((option = ppdFindOption(ppd, "Collate")) != NULL && 2638 !option->conflicted) 2639 doc->slow_collate = 0; 2640 else 2641 ppdMarkOption(ppd, "Collate", "False"); 2642 } 2643 } 2644 else 2645 doc->slow_collate = 0; 2646 2647 if (!ppdFindOption(ppd, "OutputOrder") && doc->output_order) 2648 doc->slow_order = 1; 2649 else 2650 doc->slow_order = 0; 2651 2652 if (Duplex && 2653 (doc->slow_collate || doc->slow_order || 2654 ((attr = ppdFindAttr(ppd, "cupsEvenDuplex", NULL)) != NULL && 2655 attr->value && !_cups_strcasecmp(attr->value, "true")))) 2656 doc->slow_duplex = 1; 2657 else 2658 doc->slow_duplex = 0; 2659 2660 /* 2661 * Create a temporary file for page data if we need to filter slowly... 2662 */ 2663 2664 if (doc->slow_order || doc->slow_collate) 2665 { 2666 if ((doc->temp = cupsTempFile2(doc->tempfile, 2667 sizeof(doc->tempfile))) == NULL) 2668 { 2669 perror("DEBUG: Unable to create temporary file"); 2670 exit(1); 2671 } 2672 } 2673 2674 /* 2675 * Figure out if we should use ESPshowpage or not... 2676 */ 2677 2678 if (doc->page_label || getenv("CLASSIFICATION") || doc->number_up > 1 || 2679 doc->page_border) 2680 { 2681 /* 2682 * Yes, use ESPshowpage... 2683 */ 2684 2685 doc->use_ESPshowpage = 1; 2686 } 2687 2688 fprintf(stderr, "DEBUG: slow_collate=%d, slow_duplex=%d, slow_order=%d\n", 2689 doc->slow_collate, doc->slow_duplex, doc->slow_order); 2690} 2691 2692 2693/* 2694 * 'skip_page()' - Skip past a page that won't be printed. 2695 */ 2696 2697static ssize_t /* O - Length of next line */ 2698skip_page(cups_file_t *fp, /* I - File to read from */ 2699 char *line, /* I - Line buffer */ 2700 ssize_t linelen, /* I - Length of initial line */ 2701 size_t linesize) /* I - Size of line buffer */ 2702{ 2703 int level; /* Embedded document level */ 2704 2705 2706 level = 0; 2707 2708 while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0) 2709 { 2710 if (level == 0 && 2711 (!strncmp(line, "%%Page:", 7) || !strncmp(line, "%%Trailer", 9))) 2712 break; 2713 else if (!strncmp(line, "%%BeginDocument", 15) || 2714 !strncmp(line, "%ADO_BeginApplication", 21)) 2715 level ++; 2716 else if ((!strncmp(line, "%%EndDocument", 13) || 2717 !strncmp(line, "%ADO_EndApplication", 19)) && level > 0) 2718 level --; 2719 else if (!strncmp(line, "%%BeginBinary:", 14) || 2720 (!strncmp(line, "%%BeginData:", 12) && 2721 !strstr(line, "ASCII") && !strstr(line, "Hex"))) 2722 { 2723 /* 2724 * Skip binary data... 2725 */ 2726 2727 int bytes; /* Bytes of data */ 2728 2729 2730 bytes = atoi(strchr(line, ':') + 1); 2731 2732 while (bytes > 0) 2733 { 2734 if (bytes > linesize) 2735 linelen = cupsFileRead(fp, line, linesize); 2736 else 2737 linelen = cupsFileRead(fp, line, bytes); 2738 2739 if (linelen < 1) 2740 { 2741 line[0] = '\0'; 2742 perror("ERROR: Early end-of-file while reading binary data"); 2743 return (0); 2744 } 2745 2746 bytes -= linelen; 2747 } 2748 } 2749 } 2750 2751 return (linelen); 2752} 2753 2754 2755/* 2756 * 'start_nup()' - Start processing for N-up printing. 2757 */ 2758 2759static void 2760start_nup(pstops_doc_t *doc, /* I - Document information */ 2761 int number, /* I - Page number */ 2762 int show_border, /* I - Show the border? */ 2763 const int *bounding_box) /* I - BoundingBox value */ 2764{ 2765 int pos; /* Position on page */ 2766 int x, y; /* Relative position of subpage */ 2767 float w, l, /* Width and length of subpage */ 2768 tx, ty; /* Translation values for subpage */ 2769 float pagew, /* Printable width of page */ 2770 pagel; /* Printable height of page */ 2771 int bboxx, /* BoundingBox X origin */ 2772 bboxy, /* BoundingBox Y origin */ 2773 bboxw, /* BoundingBox width */ 2774 bboxl; /* BoundingBox height */ 2775 float margin = 0; /* Current margin for border */ 2776 2777 2778 if (doc->number_up > 1) 2779 doc_puts(doc, "userdict/ESPsave save put\n"); 2780 2781 pos = (number - 1) % doc->number_up; 2782 pagew = PageRight - PageLeft; 2783 pagel = PageTop - PageBottom; 2784 2785 if (doc->fit_to_page) 2786 { 2787 bboxx = bounding_box[0]; 2788 bboxy = bounding_box[1]; 2789 bboxw = bounding_box[2] - bounding_box[0]; 2790 bboxl = bounding_box[3] - bounding_box[1]; 2791 } 2792 else 2793 { 2794 bboxx = 0; 2795 bboxy = 0; 2796 bboxw = PageWidth; 2797 bboxl = PageLength; 2798 } 2799 2800 fprintf(stderr, "DEBUG: pagew = %.1f, pagel = %.1f\n", pagew, pagel); 2801 fprintf(stderr, "DEBUG: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d\n", 2802 bboxx, bboxy, bboxw, bboxl); 2803 fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", 2804 PageLeft, PageRight); 2805 fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", 2806 PageTop, PageBottom); 2807 fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", 2808 PageWidth, PageLength); 2809 2810 switch (Orientation) 2811 { 2812 case 1 : /* Landscape */ 2813 doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", PageLength); 2814 break; 2815 case 2 : /* Reverse Portrait */ 2816 doc_printf(doc, "%.1f %.1f translate 180 rotate\n", PageWidth, 2817 PageLength); 2818 break; 2819 case 3 : /* Reverse Landscape */ 2820 doc_printf(doc, "0.0 %.1f translate -90 rotate\n", PageWidth); 2821 break; 2822 } 2823 2824 /* 2825 * Mirror the page as needed... 2826 */ 2827 2828 if (doc->mirror) 2829 doc_printf(doc, "%.1f 0.0 translate -1 1 scale\n", PageWidth); 2830 2831 /* 2832 * Offset and scale as necessary for fit_to_page/fit-to-page/number-up... 2833 */ 2834 2835 if (Duplex && doc->number_up > 1 && ((number / doc->number_up) & 1)) 2836 doc_printf(doc, "%.1f %.1f translate\n", PageWidth - PageRight, PageBottom); 2837 else if (doc->number_up > 1 || doc->fit_to_page) 2838 doc_printf(doc, "%.1f %.1f translate\n", PageLeft, PageBottom); 2839 2840 switch (doc->number_up) 2841 { 2842 default : 2843 if (doc->fit_to_page) 2844 { 2845 w = pagew; 2846 l = w * bboxl / bboxw; 2847 2848 if (l > pagel) 2849 { 2850 l = pagel; 2851 w = l * bboxw / bboxl; 2852 } 2853 2854 tx = 0.5 * (pagew - w); 2855 ty = 0.5 * (pagel - l); 2856 2857 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", tx, ty, 2858 w / bboxw, l / bboxl); 2859 } 2860 else 2861 w = PageWidth; 2862 break; 2863 2864 case 2 : 2865 if (Orientation & 1) 2866 { 2867 x = pos & 1; 2868 2869 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 2870 x = 1 - x; 2871 2872 w = pagel; 2873 l = w * bboxl / bboxw; 2874 2875 if (l > (pagew * 0.5)) 2876 { 2877 l = pagew * 0.5; 2878 w = l * bboxw / bboxl; 2879 } 2880 2881 tx = 0.5 * (pagew * 0.5 - l); 2882 ty = 0.5 * (pagel - w); 2883 2884 if (doc->normal_landscape) 2885 doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel); 2886 else 2887 doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew); 2888 2889 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 2890 ty, tx + pagew * 0.5 * x, w / bboxw, l / bboxl); 2891 } 2892 else 2893 { 2894 x = pos & 1; 2895 2896 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 2897 x = 1 - x; 2898 2899 l = pagew; 2900 w = l * bboxw / bboxl; 2901 2902 if (w > (pagel * 0.5)) 2903 { 2904 w = pagel * 0.5; 2905 l = w * bboxl / bboxw; 2906 } 2907 2908 tx = 0.5 * (pagel * 0.5 - w); 2909 ty = 0.5 * (pagew - l); 2910 2911 if (doc->normal_landscape) 2912 doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew); 2913 else 2914 doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel); 2915 2916 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 2917 tx + pagel * 0.5 * x, ty, w / bboxw, l / bboxl); 2918 } 2919 break; 2920 2921 case 4 : 2922 if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL) 2923 { 2924 x = (pos / 2) & 1; 2925 y = pos & 1; 2926 } 2927 else 2928 { 2929 x = pos & 1; 2930 y = (pos / 2) & 1; 2931 } 2932 2933 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 2934 x = 1 - x; 2935 2936 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 2937 y = 1 - y; 2938 2939 w = pagew * 0.5; 2940 l = w * bboxl / bboxw; 2941 2942 if (l > (pagel * 0.5)) 2943 { 2944 l = pagel * 0.5; 2945 w = l * bboxw / bboxl; 2946 } 2947 2948 tx = 0.5 * (pagew * 0.5 - w); 2949 ty = 0.5 * (pagel * 0.5 - l); 2950 2951 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 2952 tx + x * pagew * 0.5, ty + y * pagel * 0.5, 2953 w / bboxw, l / bboxl); 2954 break; 2955 2956 case 6 : 2957 if (Orientation & 1) 2958 { 2959 if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL) 2960 { 2961 x = pos / 3; 2962 y = pos % 3; 2963 2964 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 2965 x = 1 - x; 2966 2967 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 2968 y = 2 - y; 2969 } 2970 else 2971 { 2972 x = pos & 1; 2973 y = pos / 2; 2974 2975 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 2976 x = 1 - x; 2977 2978 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 2979 y = 2 - y; 2980 } 2981 2982 w = pagel * 0.5; 2983 l = w * bboxl / bboxw; 2984 2985 if (l > (pagew * 0.333)) 2986 { 2987 l = pagew * 0.333; 2988 w = l * bboxw / bboxl; 2989 } 2990 2991 tx = 0.5 * (pagel - 2 * w); 2992 ty = 0.5 * (pagew - 3 * l); 2993 2994 if (doc->normal_landscape) 2995 doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel); 2996 else 2997 doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew); 2998 2999 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 3000 tx + x * w, ty + y * l, l / bboxl, w / bboxw); 3001 } 3002 else 3003 { 3004 if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL) 3005 { 3006 x = pos / 2; 3007 y = pos & 1; 3008 3009 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 3010 x = 2 - x; 3011 3012 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 3013 y = 1 - y; 3014 } 3015 else 3016 { 3017 x = pos % 3; 3018 y = pos / 3; 3019 3020 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 3021 x = 2 - x; 3022 3023 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 3024 y = 1 - y; 3025 } 3026 3027 l = pagew * 0.5; 3028 w = l * bboxw / bboxl; 3029 3030 if (w > (pagel * 0.333)) 3031 { 3032 w = pagel * 0.333; 3033 l = w * bboxl / bboxw; 3034 } 3035 3036 tx = 0.5 * (pagel - 3 * w); 3037 ty = 0.5 * (pagew - 2 * l); 3038 3039 if (doc->normal_landscape) 3040 doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew); 3041 else 3042 doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel); 3043 3044 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 3045 tx + w * x, ty + l * y, w / bboxw, l / bboxl); 3046 3047 } 3048 break; 3049 3050 case 9 : 3051 if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL) 3052 { 3053 x = (pos / 3) % 3; 3054 y = pos % 3; 3055 } 3056 else 3057 { 3058 x = pos % 3; 3059 y = (pos / 3) % 3; 3060 } 3061 3062 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 3063 x = 2 - x; 3064 3065 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 3066 y = 2 - y; 3067 3068 w = pagew * 0.333; 3069 l = w * bboxl / bboxw; 3070 3071 if (l > (pagel * 0.333)) 3072 { 3073 l = pagel * 0.333; 3074 w = l * bboxw / bboxl; 3075 } 3076 3077 tx = 0.5 * (pagew * 0.333 - w); 3078 ty = 0.5 * (pagel * 0.333 - l); 3079 3080 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 3081 tx + x * pagew * 0.333, ty + y * pagel * 0.333, 3082 w / bboxw, l / bboxl); 3083 break; 3084 3085 case 16 : 3086 if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL) 3087 { 3088 x = (pos / 4) & 3; 3089 y = pos & 3; 3090 } 3091 else 3092 { 3093 x = pos & 3; 3094 y = (pos / 4) & 3; 3095 } 3096 3097 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX) 3098 x = 3 - x; 3099 3100 if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY) 3101 y = 3 - y; 3102 3103 w = pagew * 0.25; 3104 l = w * bboxl / bboxw; 3105 3106 if (l > (pagel * 0.25)) 3107 { 3108 l = pagel * 0.25; 3109 w = l * bboxw / bboxl; 3110 } 3111 3112 tx = 0.5 * (pagew * 0.25 - w); 3113 ty = 0.5 * (pagel * 0.25 - l); 3114 3115 doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", 3116 tx + x * pagew * 0.25, ty + y * pagel * 0.25, 3117 w / bboxw, l / bboxl); 3118 break; 3119 } 3120 3121 /* 3122 * Draw borders as necessary... 3123 */ 3124 3125 if (doc->page_border && show_border) 3126 { 3127 int rects; /* Number of border rectangles */ 3128 float fscale; /* Scaling value for points */ 3129 3130 3131 rects = (doc->page_border & PSTOPS_BORDERDOUBLE) ? 2 : 1; 3132 fscale = PageWidth / w; 3133 margin = 2.25 * fscale; 3134 3135 /* 3136 * Set the line width and color... 3137 */ 3138 3139 doc_puts(doc, "gsave\n"); 3140 doc_printf(doc, "%.3f setlinewidth 0 setgray newpath\n", 3141 (doc->page_border & PSTOPS_BORDERTHICK) ? 0.5 * fscale : 3142 0.24 * fscale); 3143 3144 /* 3145 * Draw border boxes... 3146 */ 3147 3148 for (; rects > 0; rects --, margin += 2 * fscale) 3149 if (doc->number_up > 1) 3150 doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n", 3151 margin, 3152 margin, 3153 bboxw - 2 * margin, 3154 bboxl - 2 * margin); 3155 else 3156 doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n", 3157 PageLeft + margin, 3158 PageBottom + margin, 3159 PageRight - PageLeft - 2 * margin, 3160 PageTop - PageBottom - 2 * margin); 3161 3162 /* 3163 * Restore pen settings... 3164 */ 3165 3166 doc_puts(doc, "grestore\n"); 3167 } 3168 3169 if (doc->fit_to_page) 3170 { 3171 /* 3172 * Offset the page by its bounding box... 3173 */ 3174 3175 doc_printf(doc, "%d %d translate\n", -bounding_box[0], 3176 -bounding_box[1]); 3177 } 3178 3179 if (doc->fit_to_page || doc->number_up > 1) 3180 { 3181 /* 3182 * Clip the page to the page's bounding box... 3183 */ 3184 3185 doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrc\n", 3186 bboxx + margin, bboxy + margin, 3187 bboxw - 2 * margin, bboxl - 2 * margin); 3188 } 3189} 3190 3191 3192/* 3193 * 'write_label_prolog()' - Write the prolog with the classification 3194 * and page label. 3195 */ 3196 3197static void 3198write_label_prolog(pstops_doc_t *doc, /* I - Document info */ 3199 const char *label, /* I - Page label */ 3200 float bottom, /* I - Bottom position in points */ 3201 float top, /* I - Top position in points */ 3202 float width) /* I - Width in points */ 3203{ 3204 const char *classification; /* CLASSIFICATION environment variable */ 3205 const char *ptr; /* Temporary string pointer */ 3206 3207 3208 /* 3209 * First get the current classification... 3210 */ 3211 3212 if ((classification = getenv("CLASSIFICATION")) == NULL) 3213 classification = ""; 3214 if (strcmp(classification, "none") == 0) 3215 classification = ""; 3216 3217 /* 3218 * If there is nothing to show, bind an empty 'write labels' procedure 3219 * and return... 3220 */ 3221 3222 if (!classification[0] && (label == NULL || !label[0])) 3223 { 3224 doc_puts(doc, "userdict/ESPwl{}bind put\n"); 3225 return; 3226 } 3227 3228 /* 3229 * Set the classification + page label string... 3230 */ 3231 3232 doc_puts(doc, "userdict"); 3233 if (!strcmp(classification, "confidential")) 3234 doc_puts(doc, "/ESPpl(CONFIDENTIAL"); 3235 else if (!strcmp(classification, "classified")) 3236 doc_puts(doc, "/ESPpl(CLASSIFIED"); 3237 else if (!strcmp(classification, "secret")) 3238 doc_puts(doc, "/ESPpl(SECRET"); 3239 else if (!strcmp(classification, "topsecret")) 3240 doc_puts(doc, "/ESPpl(TOP SECRET"); 3241 else if (!strcmp(classification, "unclassified")) 3242 doc_puts(doc, "/ESPpl(UNCLASSIFIED"); 3243 else 3244 { 3245 doc_puts(doc, "/ESPpl("); 3246 3247 for (ptr = classification; *ptr; ptr ++) 3248 { 3249 if (*ptr < 32 || *ptr > 126) 3250 doc_printf(doc, "\\%03o", *ptr); 3251 else if (*ptr == '_') 3252 doc_puts(doc, " "); 3253 else if (*ptr == '(' || *ptr == ')' || *ptr == '\\') 3254 doc_printf(doc, "\\%c", *ptr); 3255 else 3256 doc_printf(doc, "%c", *ptr); 3257 } 3258 } 3259 3260 if (label) 3261 { 3262 if (classification[0]) 3263 doc_puts(doc, " - "); 3264 3265 /* 3266 * Quote the label string as needed... 3267 */ 3268 3269 for (ptr = label; *ptr; ptr ++) 3270 { 3271 if (*ptr < 32 || *ptr > 126) 3272 doc_printf(doc, "\\%03o", *ptr); 3273 else if (*ptr == '(' || *ptr == ')' || *ptr == '\\') 3274 doc_printf(doc, "\\%c", *ptr); 3275 else 3276 doc_printf(doc, "%c", *ptr); 3277 } 3278 } 3279 3280 doc_puts(doc, ")put\n"); 3281 3282 /* 3283 * Then get a 14 point Helvetica-Bold font... 3284 */ 3285 3286 doc_puts(doc, "userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put\n"); 3287 3288 /* 3289 * Finally, the procedure to write the labels on the page... 3290 */ 3291 3292 doc_puts(doc, "userdict/ESPwl{\n"); 3293 doc_puts(doc, " ESPpf setfont\n"); 3294 doc_printf(doc, " ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n", 3295 width * 0.5f); 3296 doc_puts(doc, " 1 setgray\n"); 3297 doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0); 3298 doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0); 3299 doc_puts(doc, " 0 setgray\n"); 3300 doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0); 3301 doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0); 3302 doc_printf(doc, " dup %.0f moveto ESPpl show\n", bottom + 2.0); 3303 doc_printf(doc, " %.0f moveto ESPpl show\n", top - 14.0); 3304 doc_puts(doc, "pop\n"); 3305 doc_puts(doc, "}bind put\n"); 3306} 3307 3308 3309/* 3310 * 'write_labels()' - Write the actual page labels. 3311 * 3312 * This function is a copy of the one in common.c since we need to 3313 * use doc_puts/doc_printf instead of puts/printf... 3314 */ 3315 3316static void 3317write_labels(pstops_doc_t *doc, /* I - Document information */ 3318 int orient) /* I - Orientation of the page */ 3319{ 3320 float width, /* Width of page */ 3321 length; /* Length of page */ 3322 3323 3324 doc_puts(doc, "gsave\n"); 3325 3326 if ((orient ^ Orientation) & 1) 3327 { 3328 width = PageLength; 3329 length = PageWidth; 3330 } 3331 else 3332 { 3333 width = PageWidth; 3334 length = PageLength; 3335 } 3336 3337 switch (orient & 3) 3338 { 3339 case 1 : /* Landscape */ 3340 doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", length); 3341 break; 3342 case 2 : /* Reverse Portrait */ 3343 doc_printf(doc, "%.1f %.1f translate 180 rotate\n", width, length); 3344 break; 3345 case 3 : /* Reverse Landscape */ 3346 doc_printf(doc, "0.0 %.1f translate -90 rotate\n", width); 3347 break; 3348 } 3349 3350 doc_puts(doc, "ESPwl\n"); 3351 doc_puts(doc, "grestore\n"); 3352} 3353 3354 3355/* 3356 * 'write_options()' - Write options provided via %%IncludeFeature. 3357 */ 3358 3359static void 3360write_options( 3361 pstops_doc_t *doc, /* I - Document */ 3362 ppd_file_t *ppd, /* I - PPD file */ 3363 int num_options, /* I - Number of options */ 3364 cups_option_t *options) /* I - Options */ 3365{ 3366 int i; /* Looping var */ 3367 ppd_option_t *option; /* PPD option */ 3368 int min_order; /* Minimum OrderDependency value */ 3369 char *doc_setup, /* DocumentSetup commands to send */ 3370 *any_setup; /* AnySetup commands to send */ 3371 3372 3373 /* 3374 * Figure out the minimum OrderDependency value... 3375 */ 3376 3377 if ((option = ppdFindOption(ppd, "PageRegion")) != NULL) 3378 min_order = option->order; 3379 else 3380 min_order = 999.0f; 3381 3382 for (i = 0; i < num_options; i ++) 3383 if ((option = ppdFindOption(ppd, options[i].name)) != NULL && 3384 option->order < min_order) 3385 min_order = option->order; 3386 3387 /* 3388 * Mark and extract them... 3389 */ 3390 3391 cupsMarkOptions(ppd, num_options, options); 3392 3393 doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order); 3394 any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order); 3395 3396 /* 3397 * Then send them out... 3398 */ 3399 3400 if (doc->number_up > 1) 3401 { 3402 /* 3403 * Temporarily restore setpagedevice so we can set the options... 3404 */ 3405 3406 doc_puts(doc, "userdict/setpagedevice/CUPSsetpagedevice load put\n"); 3407 } 3408 3409 if (doc_setup) 3410 { 3411 doc_puts(doc, doc_setup); 3412 free(doc_setup); 3413 } 3414 3415 if (any_setup) 3416 { 3417 doc_puts(doc, any_setup); 3418 free(any_setup); 3419 } 3420 3421 if (doc->number_up > 1) 3422 { 3423 /* 3424 * Disable setpagedevice again... 3425 */ 3426 3427 doc_puts(doc, "userdict/setpagedevice{pop}bind put\n"); 3428 } 3429} 3430 3431 3432/* 3433 * End of "$Id: pstops.c 11093 2013-07-03 20:48:42Z msweet $". 3434 */ 3435