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