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