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