1 /* 2 * PPD command interpreter for CUPS. 3 * 4 * Copyright 2007-2015 by Apple Inc. 5 * Copyright 1993-2007 by Easy Software Products. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers... 18 */ 19 20 #include <cups/raster-private.h> 21 #include <cups/ppd.h> 22 23 24 /* 25 * Stack values for the PostScript mini-interpreter... 26 */ 27 28 typedef enum 29 { 30 CUPS_PS_NAME, 31 CUPS_PS_NUMBER, 32 CUPS_PS_STRING, 33 CUPS_PS_BOOLEAN, 34 CUPS_PS_NULL, 35 CUPS_PS_START_ARRAY, 36 CUPS_PS_END_ARRAY, 37 CUPS_PS_START_DICT, 38 CUPS_PS_END_DICT, 39 CUPS_PS_START_PROC, 40 CUPS_PS_END_PROC, 41 CUPS_PS_CLEARTOMARK, 42 CUPS_PS_COPY, 43 CUPS_PS_DUP, 44 CUPS_PS_INDEX, 45 CUPS_PS_POP, 46 CUPS_PS_ROLL, 47 CUPS_PS_SETPAGEDEVICE, 48 CUPS_PS_STOPPED, 49 CUPS_PS_OTHER 50 } _cups_ps_type_t; 51 52 typedef struct 53 { 54 _cups_ps_type_t type; /* Object type */ 55 union 56 { 57 int boolean; /* Boolean value */ 58 char name[64]; /* Name value */ 59 double number; /* Number value */ 60 char other[64]; /* Other operator */ 61 char string[64]; /* Sring value */ 62 } value; /* Value */ 63 } _cups_ps_obj_t; 64 65 typedef struct 66 { 67 int num_objs, /* Number of objects on stack */ 68 alloc_objs; /* Number of allocated objects */ 69 _cups_ps_obj_t *objs; /* Objects in stack */ 70 } _cups_ps_stack_t; 71 72 73 /* 74 * Local functions... 75 */ 76 77 static int cleartomark_stack(_cups_ps_stack_t *st); 78 static int copy_stack(_cups_ps_stack_t *st, int count); 79 static void delete_stack(_cups_ps_stack_t *st); 80 static void error_object(_cups_ps_obj_t *obj); 81 static void error_stack(_cups_ps_stack_t *st, const char *title); 82 static _cups_ps_obj_t *index_stack(_cups_ps_stack_t *st, int n); 83 static _cups_ps_stack_t *new_stack(void); 84 static _cups_ps_obj_t *pop_stack(_cups_ps_stack_t *st); 85 static _cups_ps_obj_t *push_stack(_cups_ps_stack_t *st, 86 _cups_ps_obj_t *obj); 87 static int roll_stack(_cups_ps_stack_t *st, int c, int s); 88 static _cups_ps_obj_t *scan_ps(_cups_ps_stack_t *st, char **ptr); 89 static int setpagedevice(_cups_ps_stack_t *st, 90 cups_page_header2_t *h, 91 int *preferred_bits); 92 #ifdef DEBUG 93 static void DEBUG_object(const char *prefix, _cups_ps_obj_t *obj); 94 static void DEBUG_stack(const char *prefix, _cups_ps_stack_t *st); 95 #endif /* DEBUG */ 96 97 98 /* 99 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header. 100 * 101 * This function is used by raster image processing (RIP) filters like 102 * cgpdftoraster and imagetoraster when writing CUPS raster data for a page. 103 * It is not used by raster printer driver filters which only read CUPS 104 * raster data. 105 * 106 * 107 * @code cupsRasterInterpretPPD@ does not mark the options in the PPD using 108 * the "num_options" and "options" arguments. Instead, mark the options with 109 * @code cupsMarkOptions@ and @code ppdMarkOption@ prior to calling it - 110 * this allows for per-page options without manipulating the options array. 111 * 112 * The "func" argument specifies an optional callback function that is 113 * called prior to the computation of the final raster data. The function 114 * can make changes to the @link cups_page_header2_t@ data as needed to use a 115 * supported raster format and then returns 0 on success and -1 if the 116 * requested attributes cannot be supported. 117 * 118 * 119 * @code cupsRasterInterpretPPD@ supports a subset of the PostScript language. 120 * Currently only the @code [@, @code ]@, @code <<@, @code >>@, @code {@, 121 * @code }@, @code cleartomark@, @code copy@, @code dup@, @code index@, 122 * @code pop@, @code roll@, @code setpagedevice@, and @code stopped@ operators 123 * are supported. 124 * 125 * @since CUPS 1.2/macOS 10.5@ 126 */ 127 128 int /* O - 0 on success, -1 on failure */ 129 cupsRasterInterpretPPD( 130 cups_page_header2_t *h, /* O - Page header to create */ 131 ppd_file_t *ppd, /* I - PPD file */ 132 int num_options, /* I - Number of options */ 133 cups_option_t *options, /* I - Options */ 134 cups_interpret_cb_t func) /* I - Optional page header callback (@code NULL@ for none) */ 135 { 136 int status; /* Cummulative status */ 137 char *code; /* Code to run */ 138 const char *val; /* Option value */ 139 ppd_size_t *size; /* Current size */ 140 float left, /* Left position */ 141 bottom, /* Bottom position */ 142 right, /* Right position */ 143 top, /* Top position */ 144 temp1, temp2; /* Temporary variables for swapping */ 145 int preferred_bits; /* Preferred bits per color */ 146 147 148 /* 149 * Range check input... 150 */ 151 152 _cupsRasterClearError(); 153 154 if (!h) 155 { 156 _cupsRasterAddError("Page header cannot be NULL!\n"); 157 return (-1); 158 } 159 160 /* 161 * Reset the page header to the defaults... 162 */ 163 164 memset(h, 0, sizeof(cups_page_header2_t)); 165 166 h->NumCopies = 1; 167 h->PageSize[0] = 612; 168 h->PageSize[1] = 792; 169 h->HWResolution[0] = 100; 170 h->HWResolution[1] = 100; 171 h->cupsBitsPerColor = 1; 172 h->cupsColorOrder = CUPS_ORDER_CHUNKED; 173 h->cupsColorSpace = CUPS_CSPACE_K; 174 h->cupsBorderlessScalingFactor = 1.0f; 175 h->cupsPageSize[0] = 612.0f; 176 h->cupsPageSize[1] = 792.0f; 177 h->cupsImagingBBox[0] = 0.0f; 178 h->cupsImagingBBox[1] = 0.0f; 179 h->cupsImagingBBox[2] = 612.0f; 180 h->cupsImagingBBox[3] = 792.0f; 181 182 strlcpy(h->cupsPageSizeName, "Letter", sizeof(h->cupsPageSizeName)); 183 184 #ifdef __APPLE__ 185 /* 186 * cupsInteger0 is also used for the total page count on macOS; set an 187 * uncommon default value so we can tell if the driver is using cupsInteger0. 188 */ 189 190 h->cupsInteger[0] = 0x80000000; 191 #endif /* __APPLE__ */ 192 193 /* 194 * Apply patches and options to the page header... 195 */ 196 197 status = 0; 198 preferred_bits = 0; 199 200 if (ppd) 201 { 202 /* 203 * Apply any patch code (used to override the defaults...) 204 */ 205 206 if (ppd->patches) 207 status |= _cupsRasterExecPS(h, &preferred_bits, ppd->patches); 208 209 /* 210 * Then apply printer options in the proper order... 211 */ 212 213 if ((code = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL) 214 { 215 status |= _cupsRasterExecPS(h, &preferred_bits, code); 216 free(code); 217 } 218 219 if ((code = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL) 220 { 221 status |= _cupsRasterExecPS(h, &preferred_bits, code); 222 free(code); 223 } 224 225 if ((code = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL) 226 { 227 status |= _cupsRasterExecPS(h, &preferred_bits, code); 228 free(code); 229 } 230 231 if ((code = ppdEmitString(ppd, PPD_ORDER_PAGE, 0.0)) != NULL) 232 { 233 status |= _cupsRasterExecPS(h, &preferred_bits, code); 234 free(code); 235 } 236 } 237 238 /* 239 * Allow option override for page scaling... 240 */ 241 242 if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options, 243 options)) != NULL) 244 { 245 double sc = atof(val); /* Scale factor */ 246 247 if (sc >= 0.1 && sc <= 2.0) 248 h->cupsBorderlessScalingFactor = (float)sc; 249 } 250 251 /* 252 * Get the margins for the current size... 253 */ 254 255 if ((size = ppdPageSize(ppd, NULL)) != NULL) 256 { 257 /* 258 * Use the margins from the PPD file... 259 */ 260 261 left = size->left; 262 bottom = size->bottom; 263 right = size->right; 264 top = size->top; 265 266 strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName)); 267 268 h->cupsPageSize[0] = size->width; 269 h->cupsPageSize[1] = size->length; 270 } 271 else 272 { 273 /* 274 * Use the default margins... 275 */ 276 277 left = 0.0f; 278 bottom = 0.0f; 279 right = 612.0f; 280 top = 792.0f; 281 } 282 283 /* 284 * Handle orientation... 285 */ 286 287 switch (h->Orientation) 288 { 289 case CUPS_ORIENT_0 : 290 default : 291 /* Do nothing */ 292 break; 293 294 case CUPS_ORIENT_90 : 295 temp1 = h->cupsPageSize[0]; 296 h->cupsPageSize[0] = h->cupsPageSize[1]; 297 h->cupsPageSize[1] = temp1; 298 299 temp1 = left; 300 temp2 = right; 301 left = h->cupsPageSize[0] - top; 302 right = h->cupsPageSize[0] - bottom; 303 bottom = h->cupsPageSize[1] - temp1; 304 top = h->cupsPageSize[1] - temp2; 305 break; 306 307 case CUPS_ORIENT_180 : 308 temp1 = left; 309 temp2 = bottom; 310 left = h->cupsPageSize[0] - right; 311 right = h->cupsPageSize[0] - temp1; 312 bottom = h->cupsPageSize[1] - top; 313 top = h->cupsPageSize[1] - temp2; 314 break; 315 316 case CUPS_ORIENT_270 : 317 temp1 = h->cupsPageSize[0]; 318 h->cupsPageSize[0] = h->cupsPageSize[1]; 319 h->cupsPageSize[1] = temp1; 320 321 temp1 = left; 322 temp2 = right; 323 left = bottom; 324 right = top; 325 bottom = h->cupsPageSize[1] - temp2; 326 top = h->cupsPageSize[1] - temp1; 327 break; 328 } 329 330 if (left > right) 331 { 332 temp1 = left; 333 left = right; 334 right = temp1; 335 } 336 337 if (bottom > top) 338 { 339 temp1 = bottom; 340 bottom = top; 341 top = temp1; 342 } 343 344 h->PageSize[0] = (unsigned)(h->cupsPageSize[0] * 345 h->cupsBorderlessScalingFactor); 346 h->PageSize[1] = (unsigned)(h->cupsPageSize[1] * 347 h->cupsBorderlessScalingFactor); 348 h->Margins[0] = (unsigned)(left * 349 h->cupsBorderlessScalingFactor); 350 h->Margins[1] = (unsigned)(bottom * 351 h->cupsBorderlessScalingFactor); 352 h->ImagingBoundingBox[0] = (unsigned)(left * 353 h->cupsBorderlessScalingFactor); 354 h->ImagingBoundingBox[1] = (unsigned)(bottom * 355 h->cupsBorderlessScalingFactor); 356 h->ImagingBoundingBox[2] = (unsigned)(right * 357 h->cupsBorderlessScalingFactor); 358 h->ImagingBoundingBox[3] = (unsigned)(top * 359 h->cupsBorderlessScalingFactor); 360 h->cupsImagingBBox[0] = (float)left; 361 h->cupsImagingBBox[1] = (float)bottom; 362 h->cupsImagingBBox[2] = (float)right; 363 h->cupsImagingBBox[3] = (float)top; 364 365 /* 366 * Use the callback to validate the page header... 367 */ 368 369 if (func && (*func)(h, preferred_bits)) 370 { 371 _cupsRasterAddError("Page header callback returned error.\n"); 372 return (-1); 373 } 374 375 /* 376 * Check parameters... 377 */ 378 379 if (!h->HWResolution[0] || !h->HWResolution[1] || 380 !h->PageSize[0] || !h->PageSize[1] || 381 (h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 && 382 h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8 && 383 h->cupsBitsPerColor != 16) || 384 h->cupsBorderlessScalingFactor < 0.1 || 385 h->cupsBorderlessScalingFactor > 2.0) 386 { 387 _cupsRasterAddError("Page header uses unsupported values.\n"); 388 return (-1); 389 } 390 391 /* 392 * Compute the bitmap parameters... 393 */ 394 395 h->cupsWidth = (unsigned)((right - left) * h->cupsBorderlessScalingFactor * 396 h->HWResolution[0] / 72.0f + 0.5f); 397 h->cupsHeight = (unsigned)((top - bottom) * h->cupsBorderlessScalingFactor * 398 h->HWResolution[1] / 72.0f + 0.5f); 399 400 switch (h->cupsColorSpace) 401 { 402 case CUPS_CSPACE_W : 403 case CUPS_CSPACE_K : 404 case CUPS_CSPACE_WHITE : 405 case CUPS_CSPACE_GOLD : 406 case CUPS_CSPACE_SILVER : 407 case CUPS_CSPACE_SW : 408 h->cupsNumColors = 1; 409 h->cupsBitsPerPixel = h->cupsBitsPerColor; 410 break; 411 412 default : 413 /* 414 * Ensure that colorimetric colorspaces use at least 8 bits per 415 * component... 416 */ 417 418 if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ && 419 h->cupsBitsPerColor < 8) 420 h->cupsBitsPerColor = 8; 421 422 /* 423 * Figure out the number of bits per pixel... 424 */ 425 426 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) 427 { 428 if (h->cupsBitsPerColor >= 8) 429 h->cupsBitsPerPixel = h->cupsBitsPerColor * 3; 430 else 431 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4; 432 } 433 else 434 h->cupsBitsPerPixel = h->cupsBitsPerColor; 435 436 h->cupsNumColors = 3; 437 break; 438 439 case CUPS_CSPACE_KCMYcm : 440 if (h->cupsBitsPerColor == 1) 441 { 442 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) 443 h->cupsBitsPerPixel = 8; 444 else 445 h->cupsBitsPerPixel = 1; 446 447 h->cupsNumColors = 6; 448 break; 449 } 450 451 /* 452 * Fall through to CMYK code... 453 */ 454 455 case CUPS_CSPACE_RGBA : 456 case CUPS_CSPACE_RGBW : 457 case CUPS_CSPACE_CMYK : 458 case CUPS_CSPACE_YMCK : 459 case CUPS_CSPACE_KCMY : 460 case CUPS_CSPACE_GMCK : 461 case CUPS_CSPACE_GMCS : 462 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) 463 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4; 464 else 465 h->cupsBitsPerPixel = h->cupsBitsPerColor; 466 467 h->cupsNumColors = 4; 468 break; 469 470 case CUPS_CSPACE_DEVICE1 : 471 case CUPS_CSPACE_DEVICE2 : 472 case CUPS_CSPACE_DEVICE3 : 473 case CUPS_CSPACE_DEVICE4 : 474 case CUPS_CSPACE_DEVICE5 : 475 case CUPS_CSPACE_DEVICE6 : 476 case CUPS_CSPACE_DEVICE7 : 477 case CUPS_CSPACE_DEVICE8 : 478 case CUPS_CSPACE_DEVICE9 : 479 case CUPS_CSPACE_DEVICEA : 480 case CUPS_CSPACE_DEVICEB : 481 case CUPS_CSPACE_DEVICEC : 482 case CUPS_CSPACE_DEVICED : 483 case CUPS_CSPACE_DEVICEE : 484 case CUPS_CSPACE_DEVICEF : 485 h->cupsNumColors = h->cupsColorSpace - CUPS_CSPACE_DEVICE1 + 1; 486 487 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) 488 h->cupsBitsPerPixel = h->cupsBitsPerColor * h->cupsNumColors; 489 else 490 h->cupsBitsPerPixel = h->cupsBitsPerColor; 491 break; 492 } 493 494 h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8; 495 496 if (h->cupsColorOrder == CUPS_ORDER_BANDED) 497 h->cupsBytesPerLine *= h->cupsNumColors; 498 499 return (status); 500 } 501 502 503 /* 504 * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header. 505 */ 506 507 int /* O - 0 on success, -1 on error */ 508 _cupsRasterExecPS( 509 cups_page_header2_t *h, /* O - Page header */ 510 int *preferred_bits,/* O - Preferred bits per color */ 511 const char *code) /* I - PS code to execute */ 512 { 513 int error = 0; /* Error condition? */ 514 _cups_ps_stack_t *st; /* PostScript value stack */ 515 _cups_ps_obj_t *obj; /* Object from top of stack */ 516 char *codecopy, /* Copy of code */ 517 *codeptr; /* Pointer into copy of code */ 518 519 520 DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n", 521 h, preferred_bits, code)); 522 523 /* 524 * Copy the PostScript code and create a stack... 525 */ 526 527 if ((codecopy = strdup(code)) == NULL) 528 { 529 _cupsRasterAddError("Unable to duplicate code string.\n"); 530 return (-1); 531 } 532 533 if ((st = new_stack()) == NULL) 534 { 535 _cupsRasterAddError("Unable to create stack.\n"); 536 free(codecopy); 537 return (-1); 538 } 539 540 /* 541 * Parse the PS string until we run out of data... 542 */ 543 544 codeptr = codecopy; 545 546 while ((obj = scan_ps(st, &codeptr)) != NULL) 547 { 548 #ifdef DEBUG 549 DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)", st->num_objs)); 550 DEBUG_object("_cupsRasterExecPS", obj); 551 #endif /* DEBUG */ 552 553 switch (obj->type) 554 { 555 default : 556 /* Do nothing for regular values */ 557 break; 558 559 case CUPS_PS_CLEARTOMARK : 560 pop_stack(st); 561 562 if (cleartomark_stack(st)) 563 _cupsRasterAddError("cleartomark: Stack underflow.\n"); 564 565 #ifdef DEBUG 566 DEBUG_puts("1_cupsRasterExecPS: dup"); 567 DEBUG_stack("_cupsRasterExecPS", st); 568 #endif /* DEBUG */ 569 break; 570 571 case CUPS_PS_COPY : 572 pop_stack(st); 573 if ((obj = pop_stack(st)) != NULL) 574 { 575 copy_stack(st, (int)obj->value.number); 576 577 #ifdef DEBUG 578 DEBUG_puts("_cupsRasterExecPS: copy"); 579 DEBUG_stack("_cupsRasterExecPS", st); 580 #endif /* DEBUG */ 581 } 582 break; 583 584 case CUPS_PS_DUP : 585 pop_stack(st); 586 copy_stack(st, 1); 587 588 #ifdef DEBUG 589 DEBUG_puts("_cupsRasterExecPS: dup"); 590 DEBUG_stack("_cupsRasterExecPS", st); 591 #endif /* DEBUG */ 592 break; 593 594 case CUPS_PS_INDEX : 595 pop_stack(st); 596 if ((obj = pop_stack(st)) != NULL) 597 { 598 index_stack(st, (int)obj->value.number); 599 600 #ifdef DEBUG 601 DEBUG_puts("_cupsRasterExecPS: index"); 602 DEBUG_stack("_cupsRasterExecPS", st); 603 #endif /* DEBUG */ 604 } 605 break; 606 607 case CUPS_PS_POP : 608 pop_stack(st); 609 pop_stack(st); 610 611 #ifdef DEBUG 612 DEBUG_puts("_cupsRasterExecPS: pop"); 613 DEBUG_stack("_cupsRasterExecPS", st); 614 #endif /* DEBUG */ 615 break; 616 617 case CUPS_PS_ROLL : 618 pop_stack(st); 619 if ((obj = pop_stack(st)) != NULL) 620 { 621 int c; /* Count */ 622 623 624 c = (int)obj->value.number; 625 626 if ((obj = pop_stack(st)) != NULL) 627 { 628 roll_stack(st, (int)obj->value.number, c); 629 630 #ifdef DEBUG 631 DEBUG_puts("_cupsRasterExecPS: roll"); 632 DEBUG_stack("_cupsRasterExecPS", st); 633 #endif /* DEBUG */ 634 } 635 } 636 break; 637 638 case CUPS_PS_SETPAGEDEVICE : 639 pop_stack(st); 640 setpagedevice(st, h, preferred_bits); 641 642 #ifdef DEBUG 643 DEBUG_puts("_cupsRasterExecPS: setpagedevice"); 644 DEBUG_stack("_cupsRasterExecPS", st); 645 #endif /* DEBUG */ 646 break; 647 648 case CUPS_PS_START_PROC : 649 case CUPS_PS_END_PROC : 650 case CUPS_PS_STOPPED : 651 pop_stack(st); 652 break; 653 654 case CUPS_PS_OTHER : 655 _cupsRasterAddError("Unknown operator \"%s\".\n", obj->value.other); 656 error = 1; 657 DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\".", obj->value.other)); 658 break; 659 } 660 661 if (error) 662 break; 663 } 664 665 /* 666 * Cleanup... 667 */ 668 669 free(codecopy); 670 671 if (st->num_objs > 0) 672 { 673 error_stack(st, "Stack not empty:"); 674 675 #ifdef DEBUG 676 DEBUG_puts("_cupsRasterExecPS: Stack not empty"); 677 DEBUG_stack("_cupsRasterExecPS", st); 678 #endif /* DEBUG */ 679 680 delete_stack(st); 681 682 return (-1); 683 } 684 685 delete_stack(st); 686 687 /* 688 * Return success... 689 */ 690 691 return (0); 692 } 693 694 695 /* 696 * 'cleartomark_stack()' - Clear to the last mark ([) on the stack. 697 */ 698 699 static int /* O - 0 on success, -1 on error */ 700 cleartomark_stack(_cups_ps_stack_t *st) /* I - Stack */ 701 { 702 _cups_ps_obj_t *obj; /* Current object on stack */ 703 704 705 while ((obj = pop_stack(st)) != NULL) 706 if (obj->type == CUPS_PS_START_ARRAY) 707 break; 708 709 return (obj ? 0 : -1); 710 } 711 712 713 /* 714 * 'copy_stack()' - Copy the top N stack objects. 715 */ 716 717 static int /* O - 0 on success, -1 on error */ 718 copy_stack(_cups_ps_stack_t *st, /* I - Stack */ 719 int c) /* I - Number of objects to copy */ 720 { 721 int n; /* Index */ 722 723 724 if (c < 0) 725 return (-1); 726 else if (c == 0) 727 return (0); 728 729 if ((n = st->num_objs - c) < 0) 730 return (-1); 731 732 while (c > 0) 733 { 734 if (!push_stack(st, st->objs + n)) 735 return (-1); 736 737 n ++; 738 c --; 739 } 740 741 return (0); 742 } 743 744 745 /* 746 * 'delete_stack()' - Free memory used by a stack. 747 */ 748 749 static void 750 delete_stack(_cups_ps_stack_t *st) /* I - Stack */ 751 { 752 free(st->objs); 753 free(st); 754 } 755 756 757 /* 758 * 'error_object()' - Add an object's value to the current error message. 759 */ 760 761 static void 762 error_object(_cups_ps_obj_t *obj) /* I - Object to add */ 763 { 764 switch (obj->type) 765 { 766 case CUPS_PS_NAME : 767 _cupsRasterAddError(" /%s", obj->value.name); 768 break; 769 770 case CUPS_PS_NUMBER : 771 _cupsRasterAddError(" %g", obj->value.number); 772 break; 773 774 case CUPS_PS_STRING : 775 _cupsRasterAddError(" (%s)", obj->value.string); 776 break; 777 778 case CUPS_PS_BOOLEAN : 779 if (obj->value.boolean) 780 _cupsRasterAddError(" true"); 781 else 782 _cupsRasterAddError(" false"); 783 break; 784 785 case CUPS_PS_NULL : 786 _cupsRasterAddError(" null"); 787 break; 788 789 case CUPS_PS_START_ARRAY : 790 _cupsRasterAddError(" ["); 791 break; 792 793 case CUPS_PS_END_ARRAY : 794 _cupsRasterAddError(" ]"); 795 break; 796 797 case CUPS_PS_START_DICT : 798 _cupsRasterAddError(" <<"); 799 break; 800 801 case CUPS_PS_END_DICT : 802 _cupsRasterAddError(" >>"); 803 break; 804 805 case CUPS_PS_START_PROC : 806 _cupsRasterAddError(" {"); 807 break; 808 809 case CUPS_PS_END_PROC : 810 _cupsRasterAddError(" }"); 811 break; 812 813 case CUPS_PS_COPY : 814 _cupsRasterAddError(" --copy--"); 815 break; 816 817 case CUPS_PS_CLEARTOMARK : 818 _cupsRasterAddError(" --cleartomark--"); 819 break; 820 821 case CUPS_PS_DUP : 822 _cupsRasterAddError(" --dup--"); 823 break; 824 825 case CUPS_PS_INDEX : 826 _cupsRasterAddError(" --index--"); 827 break; 828 829 case CUPS_PS_POP : 830 _cupsRasterAddError(" --pop--"); 831 break; 832 833 case CUPS_PS_ROLL : 834 _cupsRasterAddError(" --roll--"); 835 break; 836 837 case CUPS_PS_SETPAGEDEVICE : 838 _cupsRasterAddError(" --setpagedevice--"); 839 break; 840 841 case CUPS_PS_STOPPED : 842 _cupsRasterAddError(" --stopped--"); 843 break; 844 845 case CUPS_PS_OTHER : 846 _cupsRasterAddError(" --%s--", obj->value.other); 847 break; 848 } 849 } 850 851 852 /* 853 * 'error_stack()' - Add a stack to the current error message... 854 */ 855 856 static void 857 error_stack(_cups_ps_stack_t *st, /* I - Stack */ 858 const char *title) /* I - Title string */ 859 { 860 int c; /* Looping var */ 861 _cups_ps_obj_t *obj; /* Current object on stack */ 862 863 864 _cupsRasterAddError("%s", title); 865 866 for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++) 867 error_object(obj); 868 869 _cupsRasterAddError("\n"); 870 } 871 872 873 /* 874 * 'index_stack()' - Copy the Nth value on the stack. 875 */ 876 877 static _cups_ps_obj_t * /* O - New object */ 878 index_stack(_cups_ps_stack_t *st, /* I - Stack */ 879 int n) /* I - Object index */ 880 { 881 if (n < 0 || (n = st->num_objs - n - 1) < 0) 882 return (NULL); 883 884 return (push_stack(st, st->objs + n)); 885 } 886 887 888 /* 889 * 'new_stack()' - Create a new stack. 890 */ 891 892 static _cups_ps_stack_t * /* O - New stack */ 893 new_stack(void) 894 { 895 _cups_ps_stack_t *st; /* New stack */ 896 897 898 if ((st = calloc(1, sizeof(_cups_ps_stack_t))) == NULL) 899 return (NULL); 900 901 st->alloc_objs = 32; 902 903 if ((st->objs = calloc(32, sizeof(_cups_ps_obj_t))) == NULL) 904 { 905 free(st); 906 return (NULL); 907 } 908 else 909 return (st); 910 } 911 912 913 /* 914 * 'pop_stock()' - Pop the top object off the stack. 915 */ 916 917 static _cups_ps_obj_t * /* O - Object */ 918 pop_stack(_cups_ps_stack_t *st) /* I - Stack */ 919 { 920 if (st->num_objs > 0) 921 { 922 st->num_objs --; 923 924 return (st->objs + st->num_objs); 925 } 926 else 927 return (NULL); 928 } 929 930 931 /* 932 * 'push_stack()' - Push an object on the stack. 933 */ 934 935 static _cups_ps_obj_t * /* O - New object */ 936 push_stack(_cups_ps_stack_t *st, /* I - Stack */ 937 _cups_ps_obj_t *obj) /* I - Object */ 938 { 939 _cups_ps_obj_t *temp; /* New object */ 940 941 942 if (st->num_objs >= st->alloc_objs) 943 { 944 945 946 st->alloc_objs += 32; 947 948 if ((temp = realloc(st->objs, (size_t)st->alloc_objs * 949 sizeof(_cups_ps_obj_t))) == NULL) 950 return (NULL); 951 952 st->objs = temp; 953 memset(temp + st->num_objs, 0, 32 * sizeof(_cups_ps_obj_t)); 954 } 955 956 temp = st->objs + st->num_objs; 957 st->num_objs ++; 958 959 memcpy(temp, obj, sizeof(_cups_ps_obj_t)); 960 961 return (temp); 962 } 963 964 965 /* 966 * 'roll_stack()' - Rotate stack objects. 967 */ 968 969 static int /* O - 0 on success, -1 on error */ 970 roll_stack(_cups_ps_stack_t *st, /* I - Stack */ 971 int c, /* I - Number of objects */ 972 int s) /* I - Amount to shift */ 973 { 974 _cups_ps_obj_t *temp; /* Temporary array of objects */ 975 int n; /* Index into array */ 976 977 978 DEBUG_printf(("3roll_stack(st=%p, s=%d, c=%d)", st, s, c)); 979 980 /* 981 * Range check input... 982 */ 983 984 if (c < 0) 985 return (-1); 986 else if (c == 0) 987 return (0); 988 989 if ((n = st->num_objs - c) < 0) 990 return (-1); 991 992 s %= c; 993 994 if (s == 0) 995 return (0); 996 997 /* 998 * Copy N objects and move things around... 999 */ 1000 1001 if (s < 0) 1002 { 1003 /* 1004 * Shift down... 1005 */ 1006 1007 s = -s; 1008 1009 if ((temp = calloc((size_t)s, sizeof(_cups_ps_obj_t))) == NULL) 1010 return (-1); 1011 1012 memcpy(temp, st->objs + n, (size_t)s * sizeof(_cups_ps_obj_t)); 1013 memmove(st->objs + n, st->objs + n + s, (size_t)(c - s) * sizeof(_cups_ps_obj_t)); 1014 memcpy(st->objs + n + c - s, temp, (size_t)s * sizeof(_cups_ps_obj_t)); 1015 } 1016 else 1017 { 1018 /* 1019 * Shift up... 1020 */ 1021 1022 if ((temp = calloc((size_t)s, sizeof(_cups_ps_obj_t))) == NULL) 1023 return (-1); 1024 1025 memcpy(temp, st->objs + n + c - s, (size_t)s * sizeof(_cups_ps_obj_t)); 1026 memmove(st->objs + n + s, st->objs + n, (size_t)(c - s) * sizeof(_cups_ps_obj_t)); 1027 memcpy(st->objs + n, temp, (size_t)s * sizeof(_cups_ps_obj_t)); 1028 } 1029 1030 free(temp); 1031 1032 return (0); 1033 } 1034 1035 1036 /* 1037 * 'scan_ps()' - Scan a string for the next PS object. 1038 */ 1039 1040 static _cups_ps_obj_t * /* O - New object or NULL on EOF */ 1041 scan_ps(_cups_ps_stack_t *st, /* I - Stack */ 1042 char **ptr) /* IO - String pointer */ 1043 { 1044 _cups_ps_obj_t obj; /* Current object */ 1045 char *start, /* Start of object */ 1046 *cur, /* Current position */ 1047 *valptr, /* Pointer into value string */ 1048 *valend; /* End of value string */ 1049 int parens; /* Parenthesis nesting level */ 1050 1051 1052 /* 1053 * Skip leading whitespace... 1054 */ 1055 1056 for (cur = *ptr; *cur; cur ++) 1057 { 1058 if (*cur == '%') 1059 { 1060 /* 1061 * Comment, skip to end of line... 1062 */ 1063 1064 for (cur ++; *cur && *cur != '\n' && *cur != '\r'; cur ++); 1065 1066 if (!*cur) 1067 cur --; 1068 } 1069 else if (!isspace(*cur & 255)) 1070 break; 1071 } 1072 1073 if (!*cur) 1074 { 1075 *ptr = NULL; 1076 1077 return (NULL); 1078 } 1079 1080 /* 1081 * See what we have... 1082 */ 1083 1084 memset(&obj, 0, sizeof(obj)); 1085 1086 switch (*cur) 1087 { 1088 case '(' : /* (string) */ 1089 obj.type = CUPS_PS_STRING; 1090 start = cur; 1091 1092 for (cur ++, parens = 1, valptr = obj.value.string, 1093 valend = obj.value.string + sizeof(obj.value.string) - 1; 1094 *cur; 1095 cur ++) 1096 { 1097 if (*cur == ')' && parens == 1) 1098 break; 1099 1100 if (*cur == '(') 1101 parens ++; 1102 else if (*cur == ')') 1103 parens --; 1104 1105 if (valptr >= valend) 1106 { 1107 *ptr = start; 1108 1109 return (NULL); 1110 } 1111 1112 if (*cur == '\\') 1113 { 1114 /* 1115 * Decode escaped character... 1116 */ 1117 1118 cur ++; 1119 1120 if (*cur == 'b') 1121 *valptr++ = '\b'; 1122 else if (*cur == 'f') 1123 *valptr++ = '\f'; 1124 else if (*cur == 'n') 1125 *valptr++ = '\n'; 1126 else if (*cur == 'r') 1127 *valptr++ = '\r'; 1128 else if (*cur == 't') 1129 *valptr++ = '\t'; 1130 else if (*cur >= '0' && *cur <= '7') 1131 { 1132 int ch = *cur - '0'; 1133 1134 if (cur[1] >= '0' && cur[1] <= '7') 1135 { 1136 cur ++; 1137 ch = (ch << 3) + *cur - '0'; 1138 } 1139 1140 if (cur[1] >= '0' && cur[1] <= '7') 1141 { 1142 cur ++; 1143 ch = (ch << 3) + *cur - '0'; 1144 } 1145 1146 *valptr++ = (char)ch; 1147 } 1148 else if (*cur == '\r') 1149 { 1150 if (cur[1] == '\n') 1151 cur ++; 1152 } 1153 else if (*cur != '\n') 1154 *valptr++ = *cur; 1155 } 1156 else 1157 *valptr++ = *cur; 1158 } 1159 1160 if (*cur != ')') 1161 { 1162 *ptr = start; 1163 1164 return (NULL); 1165 } 1166 1167 cur ++; 1168 break; 1169 1170 case '[' : /* Start array */ 1171 obj.type = CUPS_PS_START_ARRAY; 1172 cur ++; 1173 break; 1174 1175 case ']' : /* End array */ 1176 obj.type = CUPS_PS_END_ARRAY; 1177 cur ++; 1178 break; 1179 1180 case '<' : /* Start dictionary or hex string */ 1181 if (cur[1] == '<') 1182 { 1183 obj.type = CUPS_PS_START_DICT; 1184 cur += 2; 1185 } 1186 else 1187 { 1188 obj.type = CUPS_PS_STRING; 1189 start = cur; 1190 1191 for (cur ++, valptr = obj.value.string, 1192 valend = obj.value.string + sizeof(obj.value.string) - 1; 1193 *cur; 1194 cur ++) 1195 { 1196 int ch; /* Current character */ 1197 1198 1199 1200 if (*cur == '>') 1201 break; 1202 else if (valptr >= valend || !isxdigit(*cur & 255)) 1203 { 1204 *ptr = start; 1205 return (NULL); 1206 } 1207 1208 if (*cur >= '0' && *cur <= '9') 1209 ch = (*cur - '0') << 4; 1210 else 1211 ch = (tolower(*cur) - 'a' + 10) << 4; 1212 1213 if (isxdigit(cur[1] & 255)) 1214 { 1215 cur ++; 1216 1217 if (*cur >= '0' && *cur <= '9') 1218 ch |= *cur - '0'; 1219 else 1220 ch |= tolower(*cur) - 'a' + 10; 1221 } 1222 1223 *valptr++ = (char)ch; 1224 } 1225 1226 if (*cur != '>') 1227 { 1228 *ptr = start; 1229 return (NULL); 1230 } 1231 1232 cur ++; 1233 } 1234 break; 1235 1236 case '>' : /* End dictionary? */ 1237 if (cur[1] == '>') 1238 { 1239 obj.type = CUPS_PS_END_DICT; 1240 cur += 2; 1241 } 1242 else 1243 { 1244 obj.type = CUPS_PS_OTHER; 1245 obj.value.other[0] = *cur; 1246 1247 cur ++; 1248 } 1249 break; 1250 1251 case '{' : /* Start procedure */ 1252 obj.type = CUPS_PS_START_PROC; 1253 cur ++; 1254 break; 1255 1256 case '}' : /* End procedure */ 1257 obj.type = CUPS_PS_END_PROC; 1258 cur ++; 1259 break; 1260 1261 case '-' : /* Possible number */ 1262 case '+' : 1263 if (!isdigit(cur[1] & 255) && cur[1] != '.') 1264 { 1265 obj.type = CUPS_PS_OTHER; 1266 obj.value.other[0] = *cur; 1267 1268 cur ++; 1269 break; 1270 } 1271 1272 case '0' : /* Number */ 1273 case '1' : 1274 case '2' : 1275 case '3' : 1276 case '4' : 1277 case '5' : 1278 case '6' : 1279 case '7' : 1280 case '8' : 1281 case '9' : 1282 case '.' : 1283 obj.type = CUPS_PS_NUMBER; 1284 1285 start = cur; 1286 for (cur ++; *cur; cur ++) 1287 if (!isdigit(*cur & 255)) 1288 break; 1289 1290 if (*cur == '#') 1291 { 1292 /* 1293 * Integer with radix... 1294 */ 1295 1296 obj.value.number = strtol(cur + 1, &cur, atoi(start)); 1297 break; 1298 } 1299 else if (strchr(".Ee()<>[]{}/%", *cur) || isspace(*cur & 255)) 1300 { 1301 /* 1302 * Integer or real number... 1303 */ 1304 1305 obj.value.number = _cupsStrScand(start, &cur, localeconv()); 1306 break; 1307 } 1308 else 1309 cur = start; 1310 1311 default : /* Operator/variable name */ 1312 start = cur; 1313 1314 if (*cur == '/') 1315 { 1316 obj.type = CUPS_PS_NAME; 1317 valptr = obj.value.name; 1318 valend = obj.value.name + sizeof(obj.value.name) - 1; 1319 cur ++; 1320 } 1321 else 1322 { 1323 obj.type = CUPS_PS_OTHER; 1324 valptr = obj.value.other; 1325 valend = obj.value.other + sizeof(obj.value.other) - 1; 1326 } 1327 1328 while (*cur) 1329 { 1330 if (strchr("()<>[]{}/%", *cur) || isspace(*cur & 255)) 1331 break; 1332 else if (valptr < valend) 1333 *valptr++ = *cur++; 1334 else 1335 { 1336 *ptr = start; 1337 return (NULL); 1338 } 1339 } 1340 1341 if (obj.type == CUPS_PS_OTHER) 1342 { 1343 if (!strcmp(obj.value.other, "true")) 1344 { 1345 obj.type = CUPS_PS_BOOLEAN; 1346 obj.value.boolean = 1; 1347 } 1348 else if (!strcmp(obj.value.other, "false")) 1349 { 1350 obj.type = CUPS_PS_BOOLEAN; 1351 obj.value.boolean = 0; 1352 } 1353 else if (!strcmp(obj.value.other, "null")) 1354 obj.type = CUPS_PS_NULL; 1355 else if (!strcmp(obj.value.other, "cleartomark")) 1356 obj.type = CUPS_PS_CLEARTOMARK; 1357 else if (!strcmp(obj.value.other, "copy")) 1358 obj.type = CUPS_PS_COPY; 1359 else if (!strcmp(obj.value.other, "dup")) 1360 obj.type = CUPS_PS_DUP; 1361 else if (!strcmp(obj.value.other, "index")) 1362 obj.type = CUPS_PS_INDEX; 1363 else if (!strcmp(obj.value.other, "pop")) 1364 obj.type = CUPS_PS_POP; 1365 else if (!strcmp(obj.value.other, "roll")) 1366 obj.type = CUPS_PS_ROLL; 1367 else if (!strcmp(obj.value.other, "setpagedevice")) 1368 obj.type = CUPS_PS_SETPAGEDEVICE; 1369 else if (!strcmp(obj.value.other, "stopped")) 1370 obj.type = CUPS_PS_STOPPED; 1371 } 1372 break; 1373 } 1374 1375 /* 1376 * Save the current position in the string and return the new object... 1377 */ 1378 1379 *ptr = cur; 1380 1381 return (push_stack(st, &obj)); 1382 } 1383 1384 1385 /* 1386 * 'setpagedevice()' - Simulate the PostScript setpagedevice operator. 1387 */ 1388 1389 static int /* O - 0 on success, -1 on error */ 1390 setpagedevice( 1391 _cups_ps_stack_t *st, /* I - Stack */ 1392 cups_page_header2_t *h, /* O - Page header */ 1393 int *preferred_bits)/* O - Preferred bits per color */ 1394 { 1395 int i; /* Index into array */ 1396 _cups_ps_obj_t *obj, /* Current object */ 1397 *end; /* End of dictionary */ 1398 const char *name; /* Attribute name */ 1399 1400 1401 /* 1402 * Make sure we have a dictionary on the stack... 1403 */ 1404 1405 if (st->num_objs == 0) 1406 return (-1); 1407 1408 obj = end = st->objs + st->num_objs - 1; 1409 1410 if (obj->type != CUPS_PS_END_DICT) 1411 return (-1); 1412 1413 obj --; 1414 1415 while (obj > st->objs) 1416 { 1417 if (obj->type == CUPS_PS_START_DICT) 1418 break; 1419 1420 obj --; 1421 } 1422 1423 if (obj < st->objs) 1424 return (-1); 1425 1426 /* 1427 * Found the start of the dictionary, empty the stack to this point... 1428 */ 1429 1430 st->num_objs = (int)(obj - st->objs); 1431 1432 /* 1433 * Now pull /name and value pairs from the dictionary... 1434 */ 1435 1436 DEBUG_puts("3setpagedevice: Dictionary:"); 1437 1438 for (obj ++; obj < end; obj ++) 1439 { 1440 /* 1441 * Grab the name... 1442 */ 1443 1444 if (obj->type != CUPS_PS_NAME) 1445 return (-1); 1446 1447 name = obj->value.name; 1448 obj ++; 1449 1450 #ifdef DEBUG 1451 DEBUG_printf(("4setpagedevice: /%s ", name)); 1452 DEBUG_object("setpagedevice", obj); 1453 #endif /* DEBUG */ 1454 1455 /* 1456 * Then grab the value... 1457 */ 1458 1459 if (!strcmp(name, "MediaClass") && obj->type == CUPS_PS_STRING) 1460 strlcpy(h->MediaClass, obj->value.string, sizeof(h->MediaClass)); 1461 else if (!strcmp(name, "MediaColor") && obj->type == CUPS_PS_STRING) 1462 strlcpy(h->MediaColor, obj->value.string, sizeof(h->MediaColor)); 1463 else if (!strcmp(name, "MediaType") && obj->type == CUPS_PS_STRING) 1464 strlcpy(h->MediaType, obj->value.string, sizeof(h->MediaType)); 1465 else if (!strcmp(name, "OutputType") && obj->type == CUPS_PS_STRING) 1466 strlcpy(h->OutputType, obj->value.string, sizeof(h->OutputType)); 1467 else if (!strcmp(name, "AdvanceDistance") && obj->type == CUPS_PS_NUMBER) 1468 h->AdvanceDistance = (unsigned)obj->value.number; 1469 else if (!strcmp(name, "AdvanceMedia") && obj->type == CUPS_PS_NUMBER) 1470 h->AdvanceMedia = (unsigned)obj->value.number; 1471 else if (!strcmp(name, "Collate") && obj->type == CUPS_PS_BOOLEAN) 1472 h->Collate = (unsigned)obj->value.boolean; 1473 else if (!strcmp(name, "CutMedia") && obj->type == CUPS_PS_NUMBER) 1474 h->CutMedia = (cups_cut_t)(unsigned)obj->value.number; 1475 else if (!strcmp(name, "Duplex") && obj->type == CUPS_PS_BOOLEAN) 1476 h->Duplex = (unsigned)obj->value.boolean; 1477 else if (!strcmp(name, "HWResolution") && obj->type == CUPS_PS_START_ARRAY) 1478 { 1479 if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER && 1480 obj[3].type == CUPS_PS_END_ARRAY) 1481 { 1482 h->HWResolution[0] = (unsigned)obj[1].value.number; 1483 h->HWResolution[1] = (unsigned)obj[2].value.number; 1484 obj += 3; 1485 } 1486 else 1487 return (-1); 1488 } 1489 else if (!strcmp(name, "InsertSheet") && obj->type == CUPS_PS_BOOLEAN) 1490 h->InsertSheet = (unsigned)obj->value.boolean; 1491 else if (!strcmp(name, "Jog") && obj->type == CUPS_PS_NUMBER) 1492 h->Jog = (unsigned)obj->value.number; 1493 else if (!strcmp(name, "LeadingEdge") && obj->type == CUPS_PS_NUMBER) 1494 h->LeadingEdge = (unsigned)obj->value.number; 1495 else if (!strcmp(name, "ManualFeed") && obj->type == CUPS_PS_BOOLEAN) 1496 h->ManualFeed = (unsigned)obj->value.boolean; 1497 else if ((!strcmp(name, "cupsMediaPosition") || 1498 !strcmp(name, "MediaPosition")) && obj->type == CUPS_PS_NUMBER) 1499 { 1500 /* 1501 * cupsMediaPosition is supported for backwards compatibility only. 1502 * We added it back in the Ghostscript 5.50 days to work around a 1503 * bug in Ghostscript WRT handling of MediaPosition and setpagedevice. 1504 * 1505 * All new development should set MediaPosition... 1506 */ 1507 1508 h->MediaPosition = (unsigned)obj->value.number; 1509 } 1510 else if (!strcmp(name, "MediaWeight") && obj->type == CUPS_PS_NUMBER) 1511 h->MediaWeight = (unsigned)obj->value.number; 1512 else if (!strcmp(name, "MirrorPrint") && obj->type == CUPS_PS_BOOLEAN) 1513 h->MirrorPrint = (unsigned)obj->value.boolean; 1514 else if (!strcmp(name, "NegativePrint") && obj->type == CUPS_PS_BOOLEAN) 1515 h->NegativePrint = (unsigned)obj->value.boolean; 1516 else if (!strcmp(name, "NumCopies") && obj->type == CUPS_PS_NUMBER) 1517 h->NumCopies = (unsigned)obj->value.number; 1518 else if (!strcmp(name, "Orientation") && obj->type == CUPS_PS_NUMBER) 1519 h->Orientation = (unsigned)obj->value.number; 1520 else if (!strcmp(name, "OutputFaceUp") && obj->type == CUPS_PS_BOOLEAN) 1521 h->OutputFaceUp = (unsigned)obj->value.boolean; 1522 else if (!strcmp(name, "PageSize") && obj->type == CUPS_PS_START_ARRAY) 1523 { 1524 if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER && 1525 obj[3].type == CUPS_PS_END_ARRAY) 1526 { 1527 h->cupsPageSize[0] = (float)obj[1].value.number; 1528 h->cupsPageSize[1] = (float)obj[2].value.number; 1529 1530 h->PageSize[0] = (unsigned)obj[1].value.number; 1531 h->PageSize[1] = (unsigned)obj[2].value.number; 1532 1533 obj += 3; 1534 } 1535 else 1536 return (-1); 1537 } 1538 else if (!strcmp(name, "Separations") && obj->type == CUPS_PS_BOOLEAN) 1539 h->Separations = (unsigned)obj->value.boolean; 1540 else if (!strcmp(name, "TraySwitch") && obj->type == CUPS_PS_BOOLEAN) 1541 h->TraySwitch = (unsigned)obj->value.boolean; 1542 else if (!strcmp(name, "Tumble") && obj->type == CUPS_PS_BOOLEAN) 1543 h->Tumble = (unsigned)obj->value.boolean; 1544 else if (!strcmp(name, "cupsMediaType") && obj->type == CUPS_PS_NUMBER) 1545 h->cupsMediaType = (unsigned)obj->value.number; 1546 else if (!strcmp(name, "cupsBitsPerColor") && obj->type == CUPS_PS_NUMBER) 1547 h->cupsBitsPerColor = (unsigned)obj->value.number; 1548 else if (!strcmp(name, "cupsPreferredBitsPerColor") && 1549 obj->type == CUPS_PS_NUMBER) 1550 *preferred_bits = (int)obj->value.number; 1551 else if (!strcmp(name, "cupsColorOrder") && obj->type == CUPS_PS_NUMBER) 1552 h->cupsColorOrder = (cups_order_t)(unsigned)obj->value.number; 1553 else if (!strcmp(name, "cupsColorSpace") && obj->type == CUPS_PS_NUMBER) 1554 h->cupsColorSpace = (cups_cspace_t)(unsigned)obj->value.number; 1555 else if (!strcmp(name, "cupsCompression") && obj->type == CUPS_PS_NUMBER) 1556 h->cupsCompression = (unsigned)obj->value.number; 1557 else if (!strcmp(name, "cupsRowCount") && obj->type == CUPS_PS_NUMBER) 1558 h->cupsRowCount = (unsigned)obj->value.number; 1559 else if (!strcmp(name, "cupsRowFeed") && obj->type == CUPS_PS_NUMBER) 1560 h->cupsRowFeed = (unsigned)obj->value.number; 1561 else if (!strcmp(name, "cupsRowStep") && obj->type == CUPS_PS_NUMBER) 1562 h->cupsRowStep = (unsigned)obj->value.number; 1563 else if (!strcmp(name, "cupsBorderlessScalingFactor") && 1564 obj->type == CUPS_PS_NUMBER) 1565 h->cupsBorderlessScalingFactor = (float)obj->value.number; 1566 else if (!strncmp(name, "cupsInteger", 11) && obj->type == CUPS_PS_NUMBER) 1567 { 1568 if ((i = atoi(name + 11)) < 0 || i > 15) 1569 return (-1); 1570 1571 h->cupsInteger[i] = (unsigned)obj->value.number; 1572 } 1573 else if (!strncmp(name, "cupsReal", 8) && obj->type == CUPS_PS_NUMBER) 1574 { 1575 if ((i = atoi(name + 8)) < 0 || i > 15) 1576 return (-1); 1577 1578 h->cupsReal[i] = (float)obj->value.number; 1579 } 1580 else if (!strncmp(name, "cupsString", 10) && obj->type == CUPS_PS_STRING) 1581 { 1582 if ((i = atoi(name + 10)) < 0 || i > 15) 1583 return (-1); 1584 1585 strlcpy(h->cupsString[i], obj->value.string, sizeof(h->cupsString[i])); 1586 } 1587 else if (!strcmp(name, "cupsMarkerType") && obj->type == CUPS_PS_STRING) 1588 strlcpy(h->cupsMarkerType, obj->value.string, sizeof(h->cupsMarkerType)); 1589 else if (!strcmp(name, "cupsPageSizeName") && obj->type == CUPS_PS_STRING) 1590 strlcpy(h->cupsPageSizeName, obj->value.string, 1591 sizeof(h->cupsPageSizeName)); 1592 else if (!strcmp(name, "cupsRenderingIntent") && 1593 obj->type == CUPS_PS_STRING) 1594 strlcpy(h->cupsRenderingIntent, obj->value.string, 1595 sizeof(h->cupsRenderingIntent)); 1596 else 1597 { 1598 /* 1599 * Ignore unknown name+value... 1600 */ 1601 1602 DEBUG_printf(("4setpagedevice: Unknown name (\"%s\") or value...\n", name)); 1603 1604 while (obj[1].type != CUPS_PS_NAME && obj < end) 1605 obj ++; 1606 } 1607 } 1608 1609 return (0); 1610 } 1611 1612 1613 #ifdef DEBUG 1614 /* 1615 * 'DEBUG_object()' - Print an object's value... 1616 */ 1617 1618 static void 1619 DEBUG_object(const char *prefix, /* I - Prefix string */ 1620 _cups_ps_obj_t *obj) /* I - Object to print */ 1621 { 1622 switch (obj->type) 1623 { 1624 case CUPS_PS_NAME : 1625 DEBUG_printf(("4%s: /%s\n", prefix, obj->value.name)); 1626 break; 1627 1628 case CUPS_PS_NUMBER : 1629 DEBUG_printf(("4%s: %g\n", prefix, obj->value.number)); 1630 break; 1631 1632 case CUPS_PS_STRING : 1633 DEBUG_printf(("4%s: (%s)\n", prefix, obj->value.string)); 1634 break; 1635 1636 case CUPS_PS_BOOLEAN : 1637 if (obj->value.boolean) 1638 DEBUG_printf(("4%s: true", prefix)); 1639 else 1640 DEBUG_printf(("4%s: false", prefix)); 1641 break; 1642 1643 case CUPS_PS_NULL : 1644 DEBUG_printf(("4%s: null", prefix)); 1645 break; 1646 1647 case CUPS_PS_START_ARRAY : 1648 DEBUG_printf(("4%s: [", prefix)); 1649 break; 1650 1651 case CUPS_PS_END_ARRAY : 1652 DEBUG_printf(("4%s: ]", prefix)); 1653 break; 1654 1655 case CUPS_PS_START_DICT : 1656 DEBUG_printf(("4%s: <<", prefix)); 1657 break; 1658 1659 case CUPS_PS_END_DICT : 1660 DEBUG_printf(("4%s: >>", prefix)); 1661 break; 1662 1663 case CUPS_PS_START_PROC : 1664 DEBUG_printf(("4%s: {", prefix)); 1665 break; 1666 1667 case CUPS_PS_END_PROC : 1668 DEBUG_printf(("4%s: }", prefix)); 1669 break; 1670 1671 case CUPS_PS_CLEARTOMARK : 1672 DEBUG_printf(("4%s: --cleartomark--", prefix)); 1673 break; 1674 1675 case CUPS_PS_COPY : 1676 DEBUG_printf(("4%s: --copy--", prefix)); 1677 break; 1678 1679 case CUPS_PS_DUP : 1680 DEBUG_printf(("4%s: --dup--", prefix)); 1681 break; 1682 1683 case CUPS_PS_INDEX : 1684 DEBUG_printf(("4%s: --index--", prefix)); 1685 break; 1686 1687 case CUPS_PS_POP : 1688 DEBUG_printf(("4%s: --pop--", prefix)); 1689 break; 1690 1691 case CUPS_PS_ROLL : 1692 DEBUG_printf(("4%s: --roll--", prefix)); 1693 break; 1694 1695 case CUPS_PS_SETPAGEDEVICE : 1696 DEBUG_printf(("4%s: --setpagedevice--", prefix)); 1697 break; 1698 1699 case CUPS_PS_STOPPED : 1700 DEBUG_printf(("4%s: --stopped--", prefix)); 1701 break; 1702 1703 case CUPS_PS_OTHER : 1704 DEBUG_printf(("4%s: --%s--", prefix, obj->value.other)); 1705 break; 1706 } 1707 } 1708 1709 1710 /* 1711 * 'DEBUG_stack()' - Print a stack... 1712 */ 1713 1714 static void 1715 DEBUG_stack(const char *prefix, /* I - Prefix string */ 1716 _cups_ps_stack_t *st) /* I - Stack */ 1717 { 1718 int c; /* Looping var */ 1719 _cups_ps_obj_t *obj; /* Current object on stack */ 1720 1721 1722 for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++) 1723 DEBUG_object(prefix, obj); 1724 } 1725 #endif /* DEBUG */ 1726