Home | History | Annotate | Download | only in filter
      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