2 * "$Id: interpret.c 6649 2007-07-11 21:46:42Z mike $"
4 * PPD command interpreter for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1993-2007 by Easy Software Products.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header.
20 * _cupsRasterExecPS() - Execute PostScript code to initialize a page
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
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.
40 * Include necessary headers...
43 #include <cups/string.h>
44 #include "image-private.h"
49 * Stack values for the PostScript mini-interpreter...
71 CUPS_PS_SETPAGEDEVICE
,
78 _cups_ps_type_t type
; /* Object type */
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 */
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 */
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
);
117 static void DEBUG_object(_cups_ps_obj_t
*obj
);
118 static void DEBUG_stack(_cups_ps_stack_t
*st
);
123 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
125 * This function does not mark the options in the PPD using the "num_options"
126 * and "options" arguments. Instead, mark the options prior to calling
127 * cupsRasterInterpretPPD() - this allows you to do per-page options
128 * without manipulating the options array.
130 * The "func" argument specifies an optional callback function that is
131 * called prior to the computation of the final raster data. The function
132 * can make changes to the cups_page_header2_t data as needed to use a
133 * supported raster format and then returns 0 on success and -1 if the
134 * requested attributes cannot be supported.
136 * cupsRasterInterpretPPD() supports a subset of the PostScript language.
137 * Currently only the [, ], <<, >>, {, }, cleartomark, copy, dup, index,
138 * pop, roll, setpagedevice, and stopped operators are supported.
143 int /* O - 0 on success, -1 on failure */
144 cupsRasterInterpretPPD(
145 cups_page_header2_t
*h
, /* O - Page header */
146 ppd_file_t
*ppd
, /* I - PPD file */
147 int num_options
, /* I - Number of options */
148 cups_option_t
*options
, /* I - Options */
149 cups_interpret_cb_t func
) /* I - Optional page header callback */
151 int status
; /* Cummulative status */
152 char *code
; /* Code to run */
153 const char *val
; /* Option value */
154 ppd_size_t
*size
; /* Current size */
155 float left
, /* Left position */
156 bottom
, /* Bottom position */
157 right
, /* Right position */
158 top
; /* Top position */
159 int preferred_bits
; /* Preferred bits per color */
163 * Range check input...
166 _cupsRasterClearError();
170 _cupsRasterAddError("Page header cannot be NULL!\n");
175 * Reset the page header to the defaults...
178 memset(h
, 0, sizeof(cups_page_header2_t
));
181 h
->PageSize
[0] = 612;
182 h
->PageSize
[1] = 792;
183 h
->HWResolution
[0] = 100;
184 h
->HWResolution
[1] = 100;
185 h
->cupsBitsPerColor
= 1;
186 h
->cupsColorOrder
= CUPS_ORDER_CHUNKED
;
187 h
->cupsColorSpace
= CUPS_CSPACE_K
;
188 h
->cupsBorderlessScalingFactor
= 1.0f
;
189 h
->cupsPageSize
[0] = 612.0f
;
190 h
->cupsPageSize
[1] = 792.0f
;
191 h
->cupsImagingBBox
[0] = 0.0f
;
192 h
->cupsImagingBBox
[1] = 0.0f
;
193 h
->cupsImagingBBox
[2] = 612.0f
;
194 h
->cupsImagingBBox
[3] = 792.0f
;
196 strcpy(h
->cupsPageSizeName
, "Letter");
199 * Apply patches and options to the page header...
208 * Apply any patch code (used to override the defaults...)
212 status
|= _cupsRasterExecPS(h
, &preferred_bits
, ppd
->patches
);
215 * Then apply printer options in the proper order...
218 if ((code
= ppdEmitString(ppd
, PPD_ORDER_DOCUMENT
, 0.0)) != NULL
)
220 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
224 if ((code
= ppdEmitString(ppd
, PPD_ORDER_ANY
, 0.0)) != NULL
)
226 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
230 if ((code
= ppdEmitString(ppd
, PPD_ORDER_PROLOG
, 0.0)) != NULL
)
232 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
236 if ((code
= ppdEmitString(ppd
, PPD_ORDER_PAGE
, 0.0)) != NULL
)
238 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
244 * Allow option override for page scaling...
247 if ((val
= cupsGetOption("cupsBorderlessScalingFactor", num_options
,
250 float sc
= atof(val
);
252 if (sc
>= 0.5 && sc
<= 2.0)
253 h
->cupsBorderlessScalingFactor
= sc
;
257 * Get the margins for the current size...
260 if ((size
= ppdPageSize(ppd
, NULL
)) != NULL
)
263 * Use the margins from the PPD file...
267 bottom
= size
->bottom
;
271 strlcpy(h
->cupsPageSizeName
, size
->name
, sizeof(h
->cupsPageSizeName
));
273 h
->cupsPageSize
[0] = size
->width
;
274 h
->cupsPageSize
[1] = size
->length
;
279 * Use the default margins...
288 h
->PageSize
[0] = h
->cupsPageSize
[0] *
289 h
->cupsBorderlessScalingFactor
;
290 h
->PageSize
[1] = h
->cupsPageSize
[1] *
291 h
->cupsBorderlessScalingFactor
;
292 h
->Margins
[0] = left
* h
->cupsBorderlessScalingFactor
;
293 h
->Margins
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
294 h
->ImagingBoundingBox
[0] = left
* h
->cupsBorderlessScalingFactor
;
295 h
->ImagingBoundingBox
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
296 h
->ImagingBoundingBox
[2] = right
* h
->cupsBorderlessScalingFactor
;
297 h
->ImagingBoundingBox
[3] = top
* h
->cupsBorderlessScalingFactor
;
298 h
->cupsImagingBBox
[0] = left
;
299 h
->cupsImagingBBox
[1] = bottom
;
300 h
->cupsImagingBBox
[2] = right
;
301 h
->cupsImagingBBox
[3] = top
;
304 * Use the callback to validate the page header...
307 if (func
&& (*func
)(h
, preferred_bits
))
309 _cupsRasterAddError("Page header callback returned error.\n");
314 * Check parameters...
317 if (!h
->HWResolution
[0] || !h
->HWResolution
[1] ||
318 !h
->PageSize
[0] || !h
->PageSize
[1] ||
319 (h
->cupsBitsPerColor
!= 1 && h
->cupsBitsPerColor
!= 2 &&
320 h
->cupsBitsPerColor
!= 4 && h
->cupsBitsPerColor
!= 8 &&
321 h
->cupsBitsPerColor
!= 16) ||
322 h
->cupsBorderlessScalingFactor
< 0.5 ||
323 h
->cupsBorderlessScalingFactor
> 2.0)
325 _cupsRasterAddError("Page header uses unsupported values.\n");
330 * Compute the bitmap parameters...
333 h
->cupsWidth
= (int)((right
- left
) * h
->cupsBorderlessScalingFactor
*
334 h
->HWResolution
[0] / 72.0f
+ 0.5f
);
335 h
->cupsHeight
= (int)((top
- bottom
) * h
->cupsBorderlessScalingFactor
*
336 h
->HWResolution
[1] / 72.0f
+ 0.5f
);
338 switch (h
->cupsColorSpace
)
342 case CUPS_CSPACE_WHITE
:
343 case CUPS_CSPACE_GOLD
:
344 case CUPS_CSPACE_SILVER
:
345 h
->cupsNumColors
= 1;
346 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
351 * Ensure that colorimetric colorspaces use at least 8 bits per
355 if (h
->cupsColorSpace
>= CUPS_CSPACE_CIEXYZ
&&
356 h
->cupsBitsPerColor
< 8)
357 h
->cupsBitsPerColor
= 8;
360 * Figure out the number of bits per pixel...
363 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
365 if (h
->cupsBitsPerColor
>= 8)
366 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 3;
368 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
371 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
373 h
->cupsNumColors
= 3;
376 case CUPS_CSPACE_KCMYcm
:
377 if (h
->cupsBitsPerColor
== 1)
379 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
380 h
->cupsBitsPerPixel
= 8;
382 h
->cupsBitsPerPixel
= 1;
384 h
->cupsNumColors
= 6;
389 * Fall through to CMYK code...
392 case CUPS_CSPACE_RGBA
:
393 case CUPS_CSPACE_RGBW
:
394 case CUPS_CSPACE_CMYK
:
395 case CUPS_CSPACE_YMCK
:
396 case CUPS_CSPACE_KCMY
:
397 case CUPS_CSPACE_GMCK
:
398 case CUPS_CSPACE_GMCS
:
399 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
400 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
402 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
404 h
->cupsNumColors
= 4;
408 h
->cupsBytesPerLine
= (h
->cupsBitsPerPixel
* h
->cupsWidth
+ 7) / 8;
410 if (h
->cupsColorOrder
== CUPS_ORDER_BANDED
)
411 h
->cupsBytesPerLine
*= h
->cupsNumColors
;
418 * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header.
421 int /* O - 0 on success, -1 on error */
423 cups_page_header2_t
*h
, /* O - Page header */
424 int *preferred_bits
,/* O - Preferred bits per color */
425 const char *code
) /* I - PS code to execute */
427 _cups_ps_stack_t
*st
; /* PostScript value stack */
428 _cups_ps_obj_t
*obj
; /* Object from top of stack */
429 char *codecopy
, /* Copy of code */
430 *codeptr
; /* Pointer into copy of code */
433 DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n",
434 h
, preferred_bits
, code
? code
: "(null)"));
437 * Copy the PostScript code and create a stack...
440 if ((codecopy
= strdup(code
)) == NULL
)
442 _cupsRasterAddError("Unable to duplicate code string.\n");
446 if ((st
= new_stack()) == NULL
)
448 _cupsRasterAddError("Unable to create stack.\n");
454 * Parse the PS string until we run out of data...
459 while ((obj
= scan_ps(st
, &codeptr
)) != NULL
)
462 printf(" (%d): ", st
->num_objs
);
470 /* Do nothing for regular values */
473 case CUPS_PS_CLEARTOMARK
:
476 if (cleartomark_stack(st
))
477 _cupsRasterAddError("cleartomark: Stack underflow!\n");
480 fputs(" dup: ", stdout
);
487 if ((obj
= pop_stack(st
)) != NULL
)
489 copy_stack(st
, (int)obj
->value
.number
);
492 fputs(" copy: ", stdout
);
503 fputs(" dup: ", stdout
);
510 if ((obj
= pop_stack(st
)) != NULL
)
512 index_stack(st
, (int)obj
->value
.number
);
515 fputs(" index: ", stdout
);
526 fputs(" pop: ", stdout
);
533 if ((obj
= pop_stack(st
)) != NULL
)
538 c
= (int)obj
->value
.number
;
540 if ((obj
= pop_stack(st
)) != NULL
)
542 roll_stack(st
, (int)obj
->value
.number
, c
);
545 fputs(" roll:", stdout
);
552 case CUPS_PS_SETPAGEDEVICE
:
554 setpagedevice(st
, h
, preferred_bits
);
557 fputs(" setpagedevice: ", stdout
);
562 case CUPS_PS_START_PROC
:
563 case CUPS_PS_END_PROC
:
564 case CUPS_PS_STOPPED
:
569 _cupsRasterAddError("Unknown operator \"%s\"!\n", obj
->value
.other
);
570 DEBUG_printf((" Unknown operator \"%s\"!\n", obj
->value
.other
));
574 if (obj
->type
== CUPS_PS_OTHER
)
584 if (st
->num_objs
> 0)
586 error_stack(st
, "Stack not empty:");
589 fputs(" Stack not empty:", stdout
);
609 * 'cleartomark_stack()' - Clear to the last mark ([) on the stack.
612 static int /* O - 0 on success, -1 on error */
613 cleartomark_stack(_cups_ps_stack_t
*st
) /* I - Stack */
615 _cups_ps_obj_t
*obj
; /* Current object on stack */
618 while ((obj
= pop_stack(st
)) != NULL
)
619 if (obj
->type
== CUPS_PS_START_ARRAY
)
622 return (obj
? 0 : -1);
627 * 'copy_stack()' - Copy the top N stack objects.
630 static int /* O - 0 on success, -1 on error */
631 copy_stack(_cups_ps_stack_t
*st
, /* I - Stack */
632 int c
) /* I - Number of objects to copy */
642 if ((n
= st
->num_objs
- c
) < 0)
647 if (!push_stack(st
, st
->objs
+ n
))
659 * 'delete_stack()' - Free memory used by a stack.
663 delete_stack(_cups_ps_stack_t
*st
) /* I - Stack */
671 * 'error_object()' - Add an object's value to the current error message.
675 error_object(_cups_ps_obj_t
*obj
) /* I - Object to add */
680 _cupsRasterAddError(" /%s", obj
->value
.name
);
683 case CUPS_PS_NUMBER
:
684 _cupsRasterAddError(" %g", obj
->value
.number
);
687 case CUPS_PS_STRING
:
688 _cupsRasterAddError(" (%s)", obj
->value
.string
);
691 case CUPS_PS_BOOLEAN
:
692 if (obj
->value
.boolean
)
693 _cupsRasterAddError(" true");
695 _cupsRasterAddError(" false");
699 _cupsRasterAddError(" null");
702 case CUPS_PS_START_ARRAY
:
703 _cupsRasterAddError(" [");
706 case CUPS_PS_END_ARRAY
:
707 _cupsRasterAddError(" ]");
710 case CUPS_PS_START_DICT
:
711 _cupsRasterAddError(" <<");
714 case CUPS_PS_END_DICT
:
715 _cupsRasterAddError(" >>");
718 case CUPS_PS_START_PROC
:
719 _cupsRasterAddError(" {");
722 case CUPS_PS_END_PROC
:
723 _cupsRasterAddError(" }");
727 _cupsRasterAddError(" --copy--");
730 case CUPS_PS_CLEARTOMARK
:
731 _cupsRasterAddError(" --cleartomark--");
735 _cupsRasterAddError(" --dup--");
739 _cupsRasterAddError(" --index--");
743 _cupsRasterAddError(" --pop--");
747 _cupsRasterAddError(" --roll--");
750 case CUPS_PS_SETPAGEDEVICE
:
751 _cupsRasterAddError(" --setpagedevice--");
754 case CUPS_PS_STOPPED
:
755 _cupsRasterAddError(" --stopped--");
759 _cupsRasterAddError(" --%s--", obj
->value
.other
);
766 * 'error_stack()' - Add a stack to the current error message...
770 error_stack(_cups_ps_stack_t
*st
, /* I - Stack */
771 const char *title
) /* I - Title string */
773 int c
; /* Looping var */
774 _cups_ps_obj_t
*obj
; /* Current object on stack */
777 _cupsRasterAddError(title
);
779 for (obj
= st
->objs
, c
= st
->num_objs
; c
> 0; c
--, obj
++)
782 _cupsRasterAddError("\n");
787 * 'index_stack()' - Copy the Nth value on the stack.
790 static _cups_ps_obj_t
* /* O - New object */
791 index_stack(_cups_ps_stack_t
*st
, /* I - Stack */
792 int n
) /* I - Object index */
794 if (n
< 0 || (n
= st
->num_objs
- n
- 1) < 0)
797 return (push_stack(st
, st
->objs
+ n
));
802 * 'new_stack()' - Create a new stack.
805 static _cups_ps_stack_t
* /* O - New stack */
808 _cups_ps_stack_t
*st
; /* New stack */
811 if ((st
= calloc(1, sizeof(_cups_ps_stack_t
))) == NULL
)
816 if ((st
->objs
= calloc(32, sizeof(_cups_ps_obj_t
))) == NULL
)
827 * 'pop_stock()' - Pop the top object off the stack.
830 static _cups_ps_obj_t
* /* O - Object */
831 pop_stack(_cups_ps_stack_t
*st
) /* I - Stack */
833 if (st
->num_objs
> 0)
837 return (st
->objs
+ st
->num_objs
);
845 * 'push_stack()' - Push an object on the stack.
848 static _cups_ps_obj_t
* /* O - New object */
849 push_stack(_cups_ps_stack_t
*st
, /* I - Stack */
850 _cups_ps_obj_t
*obj
) /* I - Object */
852 _cups_ps_obj_t
*temp
; /* New object */
855 if (st
->num_objs
>= st
->alloc_objs
)
859 st
->alloc_objs
+= 32;
861 if ((temp
= realloc(st
->objs
, st
->alloc_objs
*
862 sizeof(_cups_ps_obj_t
))) == NULL
)
866 memset(temp
+ st
->num_objs
, 0, 32 * sizeof(_cups_ps_obj_t
));
869 temp
= st
->objs
+ st
->num_objs
;
872 memcpy(temp
, obj
, sizeof(_cups_ps_obj_t
));
879 * 'roll_stack()' - Rotate stack objects.
882 static int /* O - 0 on success, -1 on error */
883 roll_stack(_cups_ps_stack_t
*st
, /* I - Stack */
884 int c
, /* I - Number of objects */
885 int s
) /* I - Amount to shift */
887 _cups_ps_obj_t
*temp
; /* Temporary array of objects */
888 int n
; /* Index into array */
891 DEBUG_printf((" roll_stack(st=%p, s=%d, c=%d)\n", st
, s
, c
));
894 * Range check input...
902 if ((n
= st
->num_objs
- c
) < 0)
911 * Copy N objects and move things around...
922 if ((temp
= calloc(s
, sizeof(_cups_ps_obj_t
))) == NULL
)
925 memcpy(temp
, st
->objs
+ n
, s
* sizeof(_cups_ps_obj_t
));
926 memmove(st
->objs
+ n
, st
->objs
+ n
+ s
, (c
- s
) * sizeof(_cups_ps_obj_t
));
927 memcpy(st
->objs
+ n
+ c
- s
, temp
, s
* sizeof(_cups_ps_obj_t
));
935 if ((temp
= calloc(s
, sizeof(_cups_ps_obj_t
))) == NULL
)
938 memcpy(temp
, st
->objs
+ n
+ c
- s
, s
* sizeof(_cups_ps_obj_t
));
939 memmove(st
->objs
+ n
+ s
, st
->objs
+ n
,
940 (c
- s
) * sizeof(_cups_ps_obj_t
));
941 memcpy(st
->objs
+ n
, temp
, s
* sizeof(_cups_ps_obj_t
));
951 * 'scan_ps()' - Scan a string for the next PS object.
954 static _cups_ps_obj_t
* /* O - New object or NULL on EOF */
955 scan_ps(_cups_ps_stack_t
*st
, /* I - Stack */
956 char **ptr
) /* IO - String pointer */
958 _cups_ps_obj_t obj
; /* Current object */
959 char *start
, /* Start of object */
960 *cur
, /* Current position */
961 *valptr
, /* Pointer into value string */
962 *valend
; /* End of value string */
963 int parens
; /* Parenthesis nesting level */
967 * Skip leading whitespace...
970 for (cur
= *ptr
; *cur
; cur
++)
975 * Comment, skip to end of line...
978 for (cur
++; *cur
&& *cur
!= '\n' && *cur
!= '\r'; cur
++);
980 else if (!isspace(*cur
& 255))
992 * See what we have...
995 memset(&obj
, 0, sizeof(obj
));
999 case '(' : /* (string) */
1000 obj
.type
= CUPS_PS_STRING
;
1003 for (cur
++, parens
= 1, valptr
= obj
.value
.string
,
1004 valend
= obj
.value
.string
+ sizeof(obj
.value
.string
) - 1;
1008 if (*cur
== ')' && parens
== 1)
1013 else if (*cur
== ')')
1016 if (valptr
>= valend
)
1026 * Decode escaped character...
1033 else if (*cur
== 'f')
1035 else if (*cur
== 'n')
1037 else if (*cur
== 'r')
1039 else if (*cur
== 't')
1041 else if (*cur
>= '0' && *cur
<= '7')
1043 int ch
= *cur
- '0';
1045 if (cur
[1] >= '0' && cur
[1] <= '7')
1048 ch
= (ch
<< 3) + *cur
- '0';
1051 if (cur
[1] >= '0' && cur
[1] <= '7')
1054 ch
= (ch
<< 3) + *cur
- '0';
1059 else if (*cur
== '\r')
1064 else if (*cur
!= '\n')
1081 case '[' : /* Start array */
1082 obj
.type
= CUPS_PS_START_ARRAY
;
1086 case ']' : /* End array */
1087 obj
.type
= CUPS_PS_END_ARRAY
;
1091 case '<' : /* Start dictionary or hex string */
1094 obj
.type
= CUPS_PS_START_DICT
;
1099 obj
.type
= CUPS_PS_STRING
;
1102 for (cur
++, valptr
= obj
.value
.string
,
1103 valend
= obj
.value
.string
+ sizeof(obj
.value
.string
) - 1;
1107 int ch
; /* Current character */
1113 else if (valptr
>= valend
|| !isxdigit(*cur
& 255))
1119 if (*cur
>= '0' && *cur
<= '9')
1120 ch
= (*cur
- '0') << 4;
1122 ch
= (tolower(*cur
) - 'a' + 10) << 4;
1124 if (isxdigit(cur
[1] & 255))
1128 if (*cur
>= '0' && *cur
<= '9')
1131 ch
|= tolower(*cur
) - 'a' + 10;
1147 case '>' : /* End dictionary? */
1150 obj
.type
= CUPS_PS_END_DICT
;
1155 obj
.type
= CUPS_PS_OTHER
;
1156 obj
.value
.other
[0] = *cur
;
1162 case '{' : /* Start procedure */
1163 obj
.type
= CUPS_PS_START_PROC
;
1167 case '}' : /* End procedure */
1168 obj
.type
= CUPS_PS_END_PROC
;
1172 case '-' : /* Possible number */
1174 if (!isdigit(cur
[1] & 255) && cur
[1] != '.')
1176 obj
.type
= CUPS_PS_OTHER
;
1177 obj
.value
.other
[0] = *cur
;
1183 case '0' : /* Number */
1194 obj
.type
= CUPS_PS_NUMBER
;
1197 for (cur
++; *cur
; cur
++)
1198 if (!isdigit(*cur
& 255))
1204 * Integer with radix...
1207 obj
.value
.number
= strtol(cur
+ 1, &cur
, atoi(start
));
1210 else if (strchr(".Ee()<>[]{}/%", *cur
) || isspace(*cur
& 255))
1213 * Integer or real number...
1216 obj
.value
.number
= _cupsStrScand(start
, &cur
, localeconv());
1222 default : /* Operator/variable name */
1227 obj
.type
= CUPS_PS_NAME
;
1228 valptr
= obj
.value
.name
;
1229 valend
= obj
.value
.name
+ sizeof(obj
.value
.name
) - 1;
1234 obj
.type
= CUPS_PS_OTHER
;
1235 valptr
= obj
.value
.other
;
1236 valend
= obj
.value
.other
+ sizeof(obj
.value
.other
) - 1;
1241 if (strchr("()<>[]{}/%", *cur
) || isspace(*cur
& 255))
1243 else if (valptr
< valend
)
1252 if (obj
.type
== CUPS_PS_OTHER
)
1254 if (!strcmp(obj
.value
.other
, "true"))
1256 obj
.type
= CUPS_PS_BOOLEAN
;
1257 obj
.value
.boolean
= 1;
1259 else if (!strcmp(obj
.value
.other
, "false"))
1261 obj
.type
= CUPS_PS_BOOLEAN
;
1262 obj
.value
.boolean
= 0;
1264 else if (!strcmp(obj
.value
.other
, "null"))
1265 obj
.type
= CUPS_PS_NULL
;
1266 else if (!strcmp(obj
.value
.other
, "cleartomark"))
1267 obj
.type
= CUPS_PS_CLEARTOMARK
;
1268 else if (!strcmp(obj
.value
.other
, "copy"))
1269 obj
.type
= CUPS_PS_COPY
;
1270 else if (!strcmp(obj
.value
.other
, "dup"))
1271 obj
.type
= CUPS_PS_DUP
;
1272 else if (!strcmp(obj
.value
.other
, "index"))
1273 obj
.type
= CUPS_PS_INDEX
;
1274 else if (!strcmp(obj
.value
.other
, "pop"))
1275 obj
.type
= CUPS_PS_POP
;
1276 else if (!strcmp(obj
.value
.other
, "roll"))
1277 obj
.type
= CUPS_PS_ROLL
;
1278 else if (!strcmp(obj
.value
.other
, "setpagedevice"))
1279 obj
.type
= CUPS_PS_SETPAGEDEVICE
;
1280 else if (!strcmp(obj
.value
.other
, "stopped"))
1281 obj
.type
= CUPS_PS_STOPPED
;
1287 * Save the current position in the string and return the new object...
1292 return (push_stack(st
, &obj
));
1297 * 'setpagedevice()' - Simulate the PostScript setpagedevice operator.
1300 static int /* O - 0 on success, -1 on error */
1302 _cups_ps_stack_t
*st
, /* I - Stack */
1303 cups_page_header2_t
*h
, /* O - Page header */
1304 int *preferred_bits
)/* O - Preferred bits per color */
1306 int i
; /* Index into array */
1307 _cups_ps_obj_t
*obj
, /* Current object */
1308 *end
; /* End of dictionary */
1309 const char *name
; /* Attribute name */
1313 * Make sure we have a dictionary on the stack...
1316 if (st
->num_objs
== 0)
1319 obj
= end
= st
->objs
+ st
->num_objs
- 1;
1321 if (obj
->type
!= CUPS_PS_END_DICT
)
1326 while (obj
> st
->objs
)
1328 if (obj
->type
== CUPS_PS_START_DICT
)
1338 * Found the start of the dictionary, empty the stack to this point...
1341 st
->num_objs
= obj
- st
->objs
;
1344 * Now pull /name and value pairs from the dictionary...
1347 DEBUG_puts(" Dictionary:");
1349 for (obj
++; obj
< end
; obj
++)
1355 if (obj
->type
!= CUPS_PS_NAME
)
1358 name
= obj
->value
.name
;
1362 printf(" /%s ", name
);
1368 * Then grab the value...
1371 if (!strcmp(name
, "MediaClass") && obj
->type
== CUPS_PS_STRING
)
1372 strlcpy(h
->MediaClass
, obj
->value
.string
, sizeof(h
->MediaClass
));
1373 else if (!strcmp(name
, "MediaColor") && obj
->type
== CUPS_PS_STRING
)
1374 strlcpy(h
->MediaColor
, obj
->value
.string
, sizeof(h
->MediaColor
));
1375 else if (!strcmp(name
, "MediaType") && obj
->type
== CUPS_PS_STRING
)
1376 strlcpy(h
->MediaType
, obj
->value
.string
, sizeof(h
->MediaType
));
1377 else if (!strcmp(name
, "OutputType") && obj
->type
== CUPS_PS_STRING
)
1378 strlcpy(h
->OutputType
, obj
->value
.string
, sizeof(h
->OutputType
));
1379 else if (!strcmp(name
, "AdvanceDistance") && obj
->type
== CUPS_PS_NUMBER
)
1380 h
->AdvanceDistance
= (unsigned)obj
->value
.number
;
1381 else if (!strcmp(name
, "AdvanceMedia") && obj
->type
== CUPS_PS_NUMBER
)
1382 h
->AdvanceMedia
= (unsigned)obj
->value
.number
;
1383 else if (!strcmp(name
, "Collate") && obj
->type
== CUPS_PS_BOOLEAN
)
1384 h
->Collate
= (unsigned)obj
->value
.boolean
;
1385 else if (!strcmp(name
, "CutMedia") && obj
->type
== CUPS_PS_NUMBER
)
1386 h
->CutMedia
= (cups_cut_t
)(unsigned)obj
->value
.number
;
1387 else if (!strcmp(name
, "Duplex") && obj
->type
== CUPS_PS_BOOLEAN
)
1388 h
->Duplex
= (unsigned)obj
->value
.boolean
;
1389 else if (!strcmp(name
, "HWResolution") && obj
->type
== CUPS_PS_START_ARRAY
)
1391 if (obj
[1].type
== CUPS_PS_NUMBER
&& obj
[2].type
== CUPS_PS_NUMBER
&&
1392 obj
[3].type
== CUPS_PS_END_ARRAY
)
1394 h
->HWResolution
[0] = (unsigned)obj
[1].value
.number
;
1395 h
->HWResolution
[1] = (unsigned)obj
[2].value
.number
;
1401 else if (!strcmp(name
, "InsertSheet") && obj
->type
== CUPS_PS_BOOLEAN
)
1402 h
->InsertSheet
= (unsigned)obj
->value
.boolean
;
1403 else if (!strcmp(name
, "Jog") && obj
->type
== CUPS_PS_NUMBER
)
1404 h
->Jog
= (unsigned)obj
->value
.number
;
1405 else if (!strcmp(name
, "LeadingEdge") && obj
->type
== CUPS_PS_NUMBER
)
1406 h
->LeadingEdge
= (unsigned)obj
->value
.number
;
1407 else if (!strcmp(name
, "ManualFeed") && obj
->type
== CUPS_PS_BOOLEAN
)
1408 h
->ManualFeed
= (unsigned)obj
->value
.boolean
;
1409 else if ((!strcmp(name
, "cupsMediaPosition") ||
1410 !strcmp(name
, "MediaPosition")) && obj
->type
== CUPS_PS_NUMBER
)
1413 * cupsMediaPosition is supported for backwards compatibility only.
1414 * We added it back in the Ghostscript 5.50 days to work around a
1415 * bug in Ghostscript WRT handling of MediaPosition and setpagedevice.
1417 * All new development should set MediaPosition...
1420 h
->MediaPosition
= (unsigned)obj
->value
.number
;
1422 else if (!strcmp(name
, "MediaWeight") && obj
->type
== CUPS_PS_NUMBER
)
1423 h
->MediaWeight
= (unsigned)obj
->value
.number
;
1424 else if (!strcmp(name
, "MirrorPrint") && obj
->type
== CUPS_PS_BOOLEAN
)
1425 h
->MirrorPrint
= (unsigned)obj
->value
.boolean
;
1426 else if (!strcmp(name
, "NegativePrint") && obj
->type
== CUPS_PS_BOOLEAN
)
1427 h
->NegativePrint
= (unsigned)obj
->value
.boolean
;
1428 else if (!strcmp(name
, "NumCopies") && obj
->type
== CUPS_PS_NUMBER
)
1429 h
->NumCopies
= (unsigned)obj
->value
.number
;
1430 else if (!strcmp(name
, "Orientation") && obj
->type
== CUPS_PS_NUMBER
)
1431 h
->Orientation
= (unsigned)obj
->value
.number
;
1432 else if (!strcmp(name
, "OutputFaceUp") && obj
->type
== CUPS_PS_BOOLEAN
)
1433 h
->OutputFaceUp
= (unsigned)obj
->value
.boolean
;
1434 else if (!strcmp(name
, "PageSize") && obj
->type
== CUPS_PS_START_ARRAY
)
1436 if (obj
[1].type
== CUPS_PS_NUMBER
&& obj
[2].type
== CUPS_PS_NUMBER
&&
1437 obj
[3].type
== CUPS_PS_END_ARRAY
)
1439 h
->cupsPageSize
[0] = obj
[1].value
.number
;
1440 h
->cupsPageSize
[1] = obj
[2].value
.number
;
1442 h
->PageSize
[0] = (unsigned)obj
[1].value
.number
;
1443 h
->PageSize
[1] = (unsigned)obj
[2].value
.number
;
1450 else if (!strcmp(name
, "Separations") && obj
->type
== CUPS_PS_BOOLEAN
)
1451 h
->Separations
= (unsigned)obj
->value
.boolean
;
1452 else if (!strcmp(name
, "TraySwitch") && obj
->type
== CUPS_PS_BOOLEAN
)
1453 h
->TraySwitch
= (unsigned)obj
->value
.boolean
;
1454 else if (!strcmp(name
, "Tumble") && obj
->type
== CUPS_PS_BOOLEAN
)
1455 h
->Tumble
= (unsigned)obj
->value
.boolean
;
1456 else if (!strcmp(name
, "cupsMediaType") && obj
->type
== CUPS_PS_NUMBER
)
1457 h
->cupsMediaType
= (unsigned)obj
->value
.number
;
1458 else if (!strcmp(name
, "cupsBitsPerColor") && obj
->type
== CUPS_PS_NUMBER
)
1459 h
->cupsBitsPerColor
= (unsigned)obj
->value
.number
;
1460 else if (!strcmp(name
, "cupsPreferredBitsPerColor") &&
1461 obj
->type
== CUPS_PS_NUMBER
)
1462 *preferred_bits
= (int)obj
->value
.number
;
1463 else if (!strcmp(name
, "cupsColorOrder") && obj
->type
== CUPS_PS_NUMBER
)
1464 h
->cupsColorOrder
= (cups_order_t
)(unsigned)obj
->value
.number
;
1465 else if (!strcmp(name
, "cupsColorSpace") && obj
->type
== CUPS_PS_NUMBER
)
1466 h
->cupsColorSpace
= (cups_cspace_t
)(unsigned)obj
->value
.number
;
1467 else if (!strcmp(name
, "cupsCompression") && obj
->type
== CUPS_PS_NUMBER
)
1468 h
->cupsCompression
= (unsigned)obj
->value
.number
;
1469 else if (!strcmp(name
, "cupsRowCount") && obj
->type
== CUPS_PS_NUMBER
)
1470 h
->cupsRowCount
= (unsigned)obj
->value
.number
;
1471 else if (!strcmp(name
, "cupsRowFeed") && obj
->type
== CUPS_PS_NUMBER
)
1472 h
->cupsRowFeed
= (unsigned)obj
->value
.number
;
1473 else if (!strcmp(name
, "cupsRowStep") && obj
->type
== CUPS_PS_NUMBER
)
1474 h
->cupsRowStep
= (unsigned)obj
->value
.number
;
1475 else if (!strcmp(name
, "cupsBorderlessScalingFactor") &&
1476 obj
->type
== CUPS_PS_NUMBER
)
1477 h
->cupsBorderlessScalingFactor
= obj
->value
.number
;
1478 else if (!strncmp(name
, "cupsInteger", 11) && obj
->type
== CUPS_PS_NUMBER
)
1480 if ((i
= atoi(name
+ 11)) < 0 || i
> 15)
1483 h
->cupsInteger
[i
] = (unsigned)obj
->value
.number
;
1485 else if (!strncmp(name
, "cupsReal", 8) && obj
->type
== CUPS_PS_NUMBER
)
1487 if ((i
= atoi(name
+ 8)) < 0 || i
> 15)
1490 h
->cupsReal
[i
] = obj
->value
.number
;
1492 else if (!strncmp(name
, "cupsString", 10) && obj
->type
== CUPS_PS_STRING
)
1494 if ((i
= atoi(name
+ 10)) < 0 || i
> 15)
1497 strlcpy(h
->cupsString
[i
], obj
->value
.string
, sizeof(h
->cupsString
[i
]));
1499 else if (!strcmp(name
, "cupsMarkerType") && obj
->type
== CUPS_PS_STRING
)
1500 strlcpy(h
->cupsMarkerType
, obj
->value
.string
, sizeof(h
->cupsMarkerType
));
1501 else if (!strcmp(name
, "cupsPageSizeName") && obj
->type
== CUPS_PS_STRING
)
1502 strlcpy(h
->cupsPageSizeName
, obj
->value
.string
,
1503 sizeof(h
->cupsPageSizeName
));
1504 else if (!strcmp(name
, "cupsRenderingIntent") &&
1505 obj
->type
== CUPS_PS_STRING
)
1506 strlcpy(h
->cupsRenderingIntent
, obj
->value
.string
,
1507 sizeof(h
->cupsRenderingIntent
));
1511 * Ignore unknown name+value...
1514 DEBUG_printf((" Unknown name (\"%s\") or value...\n", name
));
1516 while (obj
[1].type
!= CUPS_PS_NAME
&& obj
< end
)
1527 * 'DEBUG_object()' - Print an object's value...
1531 DEBUG_object(_cups_ps_obj_t
*obj
) /* I - Object to print */
1536 printf("/%s", obj
->value
.name
);
1539 case CUPS_PS_NUMBER
:
1540 printf("%g", obj
->value
.number
);
1543 case CUPS_PS_STRING
:
1544 printf("(%s)", obj
->value
.string
);
1547 case CUPS_PS_BOOLEAN
:
1548 if (obj
->value
.boolean
)
1549 fputs("true", stdout
);
1551 fputs("false", stdout
);
1555 fputs("null", stdout
);
1558 case CUPS_PS_START_ARRAY
:
1562 case CUPS_PS_END_ARRAY
:
1566 case CUPS_PS_START_DICT
:
1567 fputs("<<", stdout
);
1570 case CUPS_PS_END_DICT
:
1571 fputs(">>", stdout
);
1574 case CUPS_PS_START_PROC
:
1578 case CUPS_PS_END_PROC
:
1582 case CUPS_PS_CLEARTOMARK
:
1583 fputs("--cleartomark--", stdout
);
1587 fputs("--copy--", stdout
);
1591 fputs("--dup--", stdout
);
1594 case CUPS_PS_INDEX
:
1595 fputs("--index--", stdout
);
1599 fputs("--pop--", stdout
);
1603 fputs("--roll--", stdout
);
1606 case CUPS_PS_SETPAGEDEVICE
:
1607 fputs("--setpagedevice--", stdout
);
1610 case CUPS_PS_STOPPED
:
1611 fputs("--stopped--", stdout
);
1614 case CUPS_PS_OTHER
:
1615 printf("--%s--", obj
->value
.other
);
1622 * 'DEBUG_stack()' - Print a stack...
1626 DEBUG_stack(_cups_ps_stack_t
*st
) /* I - Stack */
1628 int c
; /* Looping var */
1629 _cups_ps_obj_t
*obj
; /* Current object on stack */
1632 for (obj
= st
->objs
, c
= st
->num_objs
; c
> 0; c
--, obj
++)
1644 * End of "$Id: interpret.c 6649 2007-07-11 21:46:42Z mike $".