• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
cupsRasterInterpretPPD(cups_page_header2_t * h,ppd_file_t * ppd,int num_options,cups_option_t * options,cups_interpret_cb_t func)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 */
_cupsRasterExecPS(cups_page_header2_t * h,int * preferred_bits,const char * code)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 */
cleartomark_stack(_cups_ps_stack_t * st)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 */
copy_stack(_cups_ps_stack_t * st,int c)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
delete_stack(_cups_ps_stack_t * st)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
error_object(_cups_ps_obj_t * obj)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
error_stack(_cups_ps_stack_t * st,const char * title)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 */
index_stack(_cups_ps_stack_t * st,int n)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 */
new_stack(void)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 */
pop_stack(_cups_ps_stack_t * st)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 */
push_stack(_cups_ps_stack_t * st,_cups_ps_obj_t * obj)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 */
roll_stack(_cups_ps_stack_t * st,int c,int s)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 */
scan_ps(_cups_ps_stack_t * st,char ** ptr)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 */
setpagedevice(_cups_ps_stack_t * st,cups_page_header2_t * h,int * preferred_bits)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
DEBUG_object(const char * prefix,_cups_ps_obj_t * obj)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
DEBUG_stack(const char * prefix,_cups_ps_stack_t * st)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