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