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