2 * "$Id: interpret.c 6282 2007-02-14 16:33:54Z mike $"
4 * PPD command interpreter for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-2007 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header.
29 * _cupsRasterExecPS() - Execute PostScript code to initialize a page
31 * cleartomark_stack() - Clear to the last mark ([) on the stack.
32 * copy_stack() - Copy the top N stack objects.
33 * delete_stack() - Free memory used by a stack.
34 * index_stack() - Copy the Nth value on the stack.
35 * new_stack() - Create a new stack.
36 * pop_stock() - Pop the top object off the stack.
37 * push_stack() - Push an object on the stack.
38 * roll_stack() - Rotate stack objects.
39 * scan_ps() - Scan a string for the next PS object.
40 * setpagedevice() - Simulate the PostScript setpagedevice operator.
41 * DEBUG_object() - Print an object value.
42 * DEBUG_stack() - Print a stack.
46 * Include necessary headers...
49 #include <cups/string.h>
50 #include "image-private.h"
55 * Stack values for the PostScript mini-interpreter...
77 CUPS_PS_SETPAGEDEVICE
,
84 _cups_ps_type_t type
; /* Object type */
87 int boolean
; /* Boolean value */
88 char name
[64]; /* Name value */
89 double number
; /* Number value */
90 char other
[64]; /* Other operator */
91 char string
[64]; /* Sring value */
97 int num_objs
, /* Number of objects on stack */
98 alloc_objs
; /* Number of allocated objects */
99 _cups_ps_obj_t
*objs
; /* Objects in stack */
107 static int cleartomark_stack(_cups_ps_stack_t
*st
);
108 static int copy_stack(_cups_ps_stack_t
*st
, int count
);
109 static void delete_stack(_cups_ps_stack_t
*st
);
110 static _cups_ps_obj_t
*index_stack(_cups_ps_stack_t
*st
, int n
);
111 static _cups_ps_stack_t
*new_stack(void);
112 static _cups_ps_obj_t
*pop_stack(_cups_ps_stack_t
*st
);
113 static _cups_ps_obj_t
*push_stack(_cups_ps_stack_t
*st
,
114 _cups_ps_obj_t
*obj
);
115 static int roll_stack(_cups_ps_stack_t
*st
, int c
, int s
);
116 static _cups_ps_obj_t
*scan_ps(_cups_ps_stack_t
*st
, char **ptr
);
117 static int setpagedevice(_cups_ps_stack_t
*st
,
118 cups_page_header2_t
*h
,
119 int *preferred_bits
);
121 static void DEBUG_object(_cups_ps_obj_t
*obj
);
122 static void DEBUG_stack(_cups_ps_stack_t
*st
);
127 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
129 * This function does not mark the options in the PPD using the "num_options"
130 * and "options" arguments. Instead, mark the options prior to calling
131 * cupsRasterInterpretPPD() - this allows you to do per-page options
132 * without manipulating the options array.
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 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.
140 * cupsRasterInterpretPPD() supports a subset of the PostScript language.
141 * Currently only the [, ], <<, >>, {, }, cleartomark, copy, dup, index,
142 * pop, roll, setpagedevice, and stopped operators are supported.
147 int /* O - 0 on success, -1 on failure */
148 cupsRasterInterpretPPD(
149 cups_page_header2_t
*h
, /* O - Page header */
150 ppd_file_t
*ppd
, /* I - PPD file */
151 int num_options
, /* I - Number of options */
152 cups_option_t
*options
, /* I - Options */
153 cups_interpret_cb_t func
) /* I - Optional page header callback */
155 int status
; /* Cummulative status */
156 char *code
; /* Code to run */
157 const char *val
; /* Option value */
158 ppd_size_t
*size
; /* Current size */
159 float left
, /* Left position */
160 bottom
, /* Bottom position */
161 right
, /* Right position */
162 top
; /* Top position */
163 int preferred_bits
; /* Preferred bits per color */
167 * Range check input...
174 * Reset the page header to the defaults...
177 memset(h
, 0, sizeof(cups_page_header2_t
));
180 h
->PageSize
[0] = 612;
181 h
->PageSize
[1] = 792;
182 h
->HWResolution
[0] = 100;
183 h
->HWResolution
[1] = 100;
184 h
->cupsBitsPerColor
= 1;
185 h
->cupsColorOrder
= CUPS_ORDER_CHUNKED
;
186 h
->cupsColorSpace
= CUPS_CSPACE_K
;
187 h
->cupsBorderlessScalingFactor
= 1.0f
;
188 h
->cupsPageSize
[0] = 612.0f
;
189 h
->cupsPageSize
[1] = 792.0f
;
190 h
->cupsImagingBBox
[0] = 0.0f
;
191 h
->cupsImagingBBox
[1] = 0.0f
;
192 h
->cupsImagingBBox
[2] = 612.0f
;
193 h
->cupsImagingBBox
[3] = 792.0f
;
195 strcpy(h
->cupsPageSizeName
, "Letter");
198 * Apply patches and options to the page header...
207 * Apply any patch code (used to override the defaults...)
211 status
|= _cupsRasterExecPS(h
, &preferred_bits
, ppd
->patches
);
214 * Then apply printer options in the proper order...
217 if ((code
= ppdEmitString(ppd
, PPD_ORDER_DOCUMENT
, 0.0)) != NULL
)
219 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
223 if ((code
= ppdEmitString(ppd
, PPD_ORDER_ANY
, 0.0)) != NULL
)
225 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
229 if ((code
= ppdEmitString(ppd
, PPD_ORDER_PROLOG
, 0.0)) != NULL
)
231 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
235 if ((code
= ppdEmitString(ppd
, PPD_ORDER_PAGE
, 0.0)) != NULL
)
237 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
243 * Allow option override for page scaling...
246 if ((val
= cupsGetOption("cupsBorderlessScalingFactor", num_options
,
249 float sc
= atof(val
);
251 if (sc
>= 0.9 && sc
<= 1.1)
252 h
->cupsBorderlessScalingFactor
= sc
;
256 * Get the margins for the current size...
259 if ((size
= ppdPageSize(ppd
, NULL
)) != NULL
)
262 * Use the margins from the PPD file...
266 bottom
= size
->bottom
;
270 strlcpy(h
->cupsPageSizeName
, size
->name
, sizeof(h
->cupsPageSizeName
));
272 h
->cupsPageSize
[0] = size
->width
;
273 h
->cupsPageSize
[1] = size
->length
;
278 * Use the default margins...
287 h
->PageSize
[0] = h
->cupsPageSize
[0] *
288 h
->cupsBorderlessScalingFactor
;
289 h
->PageSize
[1] = h
->cupsPageSize
[1] *
290 h
->cupsBorderlessScalingFactor
;
291 h
->Margins
[0] = left
* h
->cupsBorderlessScalingFactor
;
292 h
->Margins
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
293 h
->ImagingBoundingBox
[0] = left
* h
->cupsBorderlessScalingFactor
;
294 h
->ImagingBoundingBox
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
295 h
->ImagingBoundingBox
[2] = right
* h
->cupsBorderlessScalingFactor
;
296 h
->ImagingBoundingBox
[3] = top
* h
->cupsBorderlessScalingFactor
;
297 h
->cupsImagingBBox
[0] = left
;
298 h
->cupsImagingBBox
[1] = bottom
;
299 h
->cupsImagingBBox
[2] = right
;
300 h
->cupsImagingBBox
[3] = top
;
303 * Use the callback to validate the page header...
306 if (func
&& (*func
)(h
, preferred_bits
))
310 * Check parameters...
313 if (!h
->HWResolution
[0] || !h
->HWResolution
[1] ||
314 !h
->PageSize
[0] || !h
->PageSize
[1] ||
315 (h
->cupsBitsPerColor
!= 1 && h
->cupsBitsPerColor
!= 2 &&
316 h
->cupsBitsPerColor
!= 4 && h
->cupsBitsPerColor
!= 8 &&
317 h
->cupsBitsPerColor
!= 16) ||
318 h
->cupsBorderlessScalingFactor
< 0.5 ||
319 h
->cupsBorderlessScalingFactor
> 2.0)
323 * Compute the bitmap parameters...
326 h
->cupsWidth
= (int)((right
- left
) * h
->cupsBorderlessScalingFactor
*
327 h
->HWResolution
[0] / 72.0f
+ 0.5f
);
328 h
->cupsHeight
= (int)((top
- bottom
) * h
->cupsBorderlessScalingFactor
*
329 h
->HWResolution
[1] / 72.0f
+ 0.5f
);
331 switch (h
->cupsColorSpace
)
335 case CUPS_CSPACE_WHITE
:
336 case CUPS_CSPACE_GOLD
:
337 case CUPS_CSPACE_SILVER
:
338 h
->cupsNumColors
= 1;
339 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
344 * Ensure that colorimetric colorspaces use at least 8 bits per
348 if (h
->cupsColorSpace
>= CUPS_CSPACE_CIEXYZ
&&
349 h
->cupsBitsPerColor
< 8)
350 h
->cupsBitsPerColor
= 8;
353 * Figure out the number of bits per pixel...
356 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
358 if (h
->cupsBitsPerColor
>= 8)
359 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 3;
361 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
364 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
366 h
->cupsNumColors
= 3;
369 case CUPS_CSPACE_KCMYcm
:
370 if (h
->cupsBitsPerColor
== 1)
372 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
373 h
->cupsBitsPerPixel
= 8;
375 h
->cupsBitsPerPixel
= 1;
377 h
->cupsNumColors
= 6;
382 * Fall through to CMYK code...
385 case CUPS_CSPACE_RGBA
:
386 case CUPS_CSPACE_RGBW
:
387 case CUPS_CSPACE_CMYK
:
388 case CUPS_CSPACE_YMCK
:
389 case CUPS_CSPACE_KCMY
:
390 case CUPS_CSPACE_GMCK
:
391 case CUPS_CSPACE_GMCS
:
392 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
393 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
395 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
397 h
->cupsNumColors
= 4;
401 h
->cupsBytesPerLine
= (h
->cupsBitsPerPixel
* h
->cupsWidth
+ 7) / 8;
403 if (h
->cupsColorOrder
== CUPS_ORDER_BANDED
)
404 h
->cupsBytesPerLine
*= h
->cupsNumColors
;
411 * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header.
414 int /* O - 0 on success, -1 on error */
416 cups_page_header2_t
*h
, /* O - Page header */
417 int *preferred_bits
,/* O - Preferred bits per color */
418 const char *code
) /* I - PS code to execute */
420 _cups_ps_stack_t
*st
; /* PostScript value stack */
421 _cups_ps_obj_t
*obj
; /* Object from top of stack */
422 char *codecopy
, /* Copy of code */
423 *codeptr
; /* Pointer into copy of code */
426 DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n",
427 h
, preferred_bits
, code
? code
: "(null)"));
430 * Copy the PostScript code and create a stack...
433 if ((codecopy
= strdup(code
)) == NULL
)
436 if ((st
= new_stack()) == NULL
)
443 * Parse the PS string until we run out of data...
448 while ((obj
= scan_ps(st
, &codeptr
)) != NULL
)
451 printf(" (%d): ", st
->num_objs
);
459 /* Do nothing for regular values */
462 case CUPS_PS_CLEARTOMARK
:
465 cleartomark_stack(st
);
468 fputs(" dup: ", stdout
);
475 if ((obj
= pop_stack(st
)) != NULL
)
477 copy_stack(st
, (int)obj
->value
.number
);
480 fputs(" copy: ", stdout
);
491 fputs(" dup: ", stdout
);
498 if ((obj
= pop_stack(st
)) != NULL
)
500 index_stack(st
, (int)obj
->value
.number
);
503 fputs(" index: ", stdout
);
514 fputs(" pop: ", stdout
);
521 if ((obj
= pop_stack(st
)) != NULL
)
526 c
= (int)obj
->value
.number
;
528 if ((obj
= pop_stack(st
)) != NULL
)
530 roll_stack(st
, (int)obj
->value
.number
, c
);
533 fputs(" roll:", stdout
);
540 case CUPS_PS_SETPAGEDEVICE
:
542 setpagedevice(st
, h
, preferred_bits
);
545 fputs(" setpagedevice: ", stdout
);
550 case CUPS_PS_START_PROC
:
551 case CUPS_PS_END_PROC
:
552 case CUPS_PS_STOPPED
:
557 DEBUG_printf((" Unknown operator \"%s\"!\n", obj
->value
.other
));
561 if (obj
->type
== CUPS_PS_OTHER
)
571 if (st
->num_objs
> 0)
574 fputs(" Stack not empty:", stdout
);
594 * 'cleartomark_stack()' - Clear to the last mark ([) on the stack.
597 static int /* O - 0 on success, -1 on error */
598 cleartomark_stack(_cups_ps_stack_t
*st
) /* I - Stack */
600 _cups_ps_obj_t
*obj
; /* Current object on stack */
603 while ((obj
= pop_stack(st
)) != NULL
)
604 if (obj
->type
== CUPS_PS_START_ARRAY
)
607 return (obj
? 0 : -1);
612 * 'copy_stack()' - Copy the top N stack objects.
615 static int /* O - 0 on success, -1 on error */
616 copy_stack(_cups_ps_stack_t
*st
, /* I - Stack */
617 int c
) /* I - Number of objects to copy */
627 if ((n
= st
->num_objs
- c
) < 0)
632 if (!push_stack(st
, st
->objs
+ n
))
644 * 'delete_stack()' - Free memory used by a stack.
648 delete_stack(_cups_ps_stack_t
*st
) /* I - Stack */
656 * 'index_stack()' - Copy the Nth value on the stack.
659 static _cups_ps_obj_t
* /* O - New object */
660 index_stack(_cups_ps_stack_t
*st
, /* I - Stack */
661 int n
) /* I - Object index */
663 if (n
< 0 || (n
= st
->num_objs
- n
- 1) < 0)
666 return (push_stack(st
, st
->objs
+ n
));
671 * 'new_stack()' - Create a new stack.
674 static _cups_ps_stack_t
* /* O - New stack */
677 _cups_ps_stack_t
*st
; /* New stack */
680 if ((st
= calloc(1, sizeof(_cups_ps_stack_t
))) == NULL
)
685 if ((st
->objs
= calloc(32, sizeof(_cups_ps_obj_t
))) == NULL
)
696 * 'pop_stock()' - Pop the top object off the stack.
699 static _cups_ps_obj_t
* /* O - Object */
700 pop_stack(_cups_ps_stack_t
*st
) /* I - Stack */
702 if (st
->num_objs
> 0)
706 return (st
->objs
+ st
->num_objs
);
714 * 'push_stack()' - Push an object on the stack.
717 static _cups_ps_obj_t
* /* O - New object */
718 push_stack(_cups_ps_stack_t
*st
, /* I - Stack */
719 _cups_ps_obj_t
*obj
) /* I - Object */
721 _cups_ps_obj_t
*temp
; /* New object */
724 if (st
->num_objs
>= st
->alloc_objs
)
728 st
->alloc_objs
+= 32;
730 if ((temp
= realloc(st
->objs
, st
->alloc_objs
*
731 sizeof(_cups_ps_obj_t
))) == NULL
)
735 memset(temp
+ st
->num_objs
, 0, 32 * sizeof(_cups_ps_obj_t
));
738 temp
= st
->objs
+ st
->num_objs
;
741 memcpy(temp
, obj
, sizeof(_cups_ps_obj_t
));
748 * 'roll_stack()' - Rotate stack objects.
751 static int /* O - 0 on success, -1 on error */
752 roll_stack(_cups_ps_stack_t
*st
, /* I - Stack */
753 int c
, /* I - Number of objects */
754 int s
) /* I - Amount to shift */
756 _cups_ps_obj_t
*temp
; /* Temporary array of objects */
757 int n
; /* Index into array */
760 DEBUG_printf((" roll_stack(st=%p, s=%d, c=%d)\n", st
, s
, c
));
763 * Range check input...
771 if ((n
= st
->num_objs
- c
) < 0)
780 * Copy N objects and move things around...
791 if ((temp
= calloc(s
, sizeof(_cups_ps_obj_t
))) == NULL
)
794 memcpy(temp
, st
->objs
+ n
, s
* sizeof(_cups_ps_obj_t
));
795 memmove(st
->objs
+ n
, st
->objs
+ n
+ s
, (c
- s
) * sizeof(_cups_ps_obj_t
));
796 memcpy(st
->objs
+ n
+ c
- s
, temp
, s
* sizeof(_cups_ps_obj_t
));
804 if ((temp
= calloc(s
, sizeof(_cups_ps_obj_t
))) == NULL
)
807 memcpy(temp
, st
->objs
+ n
+ c
- s
, s
* sizeof(_cups_ps_obj_t
));
808 memmove(st
->objs
+ n
+ s
, st
->objs
+ n
,
809 (c
- s
) * sizeof(_cups_ps_obj_t
));
810 memcpy(st
->objs
+ n
, temp
, s
* sizeof(_cups_ps_obj_t
));
820 * 'scan_ps()' - Scan a string for the next PS object.
823 static _cups_ps_obj_t
* /* O - New object or NULL on EOF */
824 scan_ps(_cups_ps_stack_t
*st
, /* I - Stack */
825 char **ptr
) /* IO - String pointer */
827 _cups_ps_obj_t obj
; /* Current object */
828 char *start
, /* Start of object */
829 *cur
, /* Current position */
830 *valptr
, /* Pointer into value string */
831 *valend
; /* End of value string */
832 int parens
; /* Parenthesis nesting level */
836 * Skip leading whitespace...
839 for (cur
= *ptr
; *cur
; cur
++)
844 * Comment, skip to end of line...
847 for (cur
++; *cur
&& *cur
!= '\n' && *cur
!= '\r'; cur
++);
849 else if (!isspace(*cur
& 255))
861 * See what we have...
864 memset(&obj
, 0, sizeof(obj
));
868 case '(' : /* (string) */
869 obj
.type
= CUPS_PS_STRING
;
872 for (cur
++, parens
= 1, valptr
= obj
.value
.string
,
873 valend
= obj
.value
.string
+ sizeof(obj
.value
.string
) - 1;
877 if (*cur
== ')' && parens
== 1)
882 else if (*cur
== ')')
885 if (valptr
>= valend
)
895 * Decode escaped character...
902 else if (*cur
== 'f')
904 else if (*cur
== 'n')
906 else if (*cur
== 'r')
908 else if (*cur
== 't')
910 else if (*cur
>= '0' && *cur
<= '7')
914 if (cur
[1] >= '0' && cur
[1] <= '7')
917 ch
= (ch
<< 3) + *cur
- '0';
920 if (cur
[1] >= '0' && cur
[1] <= '7')
923 ch
= (ch
<< 3) + *cur
- '0';
928 else if (*cur
== '\r')
933 else if (*cur
!= '\n')
950 case '[' : /* Start array */
951 obj
.type
= CUPS_PS_START_ARRAY
;
955 case ']' : /* End array */
956 obj
.type
= CUPS_PS_END_ARRAY
;
960 case '<' : /* Start dictionary or hex string */
963 obj
.type
= CUPS_PS_START_DICT
;
968 obj
.type
= CUPS_PS_STRING
;
971 for (cur
++, valptr
= obj
.value
.string
,
972 valend
= obj
.value
.string
+ sizeof(obj
.value
.string
) - 1;
976 int ch
; /* Current character */
982 else if (valptr
>= valend
|| !isxdigit(*cur
& 255))
988 if (*cur
>= '0' && *cur
<= '9')
989 ch
= (*cur
- '0') << 4;
991 ch
= (tolower(*cur
) - 'a' + 10) << 4;
993 if (isxdigit(cur
[1] & 255))
997 if (*cur
>= '0' && *cur
<= '9')
1000 ch
|= tolower(*cur
) - 'a' + 10;
1016 case '>' : /* End dictionary? */
1019 obj
.type
= CUPS_PS_END_DICT
;
1024 obj
.type
= CUPS_PS_OTHER
;
1025 obj
.value
.other
[0] = *cur
;
1031 case '{' : /* Start procedure */
1032 obj
.type
= CUPS_PS_START_PROC
;
1036 case '}' : /* End procedure */
1037 obj
.type
= CUPS_PS_END_PROC
;
1041 case '-' : /* Possible number */
1043 if (!isdigit(cur
[1] & 255) && cur
[1] != '.')
1045 obj
.type
= CUPS_PS_OTHER
;
1046 obj
.value
.other
[0] = *cur
;
1052 case '0' : /* Number */
1063 obj
.type
= CUPS_PS_NUMBER
;
1066 for (cur
++; *cur
; cur
++)
1067 if (!isdigit(*cur
& 255))
1073 * Integer with radix...
1076 obj
.value
.number
= strtol(cur
+ 1, &cur
, atoi(start
));
1079 else if (strchr(".Ee()<>[]{}/%", *cur
) || isspace(*cur
& 255))
1082 * Integer or real number...
1085 obj
.value
.number
= _cupsStrScand(start
, &cur
, localeconv());
1091 default : /* Operator/variable name */
1096 obj
.type
= CUPS_PS_NAME
;
1097 valptr
= obj
.value
.name
;
1098 valend
= obj
.value
.name
+ sizeof(obj
.value
.name
) - 1;
1103 obj
.type
= CUPS_PS_OTHER
;
1104 valptr
= obj
.value
.other
;
1105 valend
= obj
.value
.other
+ sizeof(obj
.value
.other
) - 1;
1110 if (strchr("()<>[]{}/%", *cur
) || isspace(*cur
& 255))
1112 else if (valptr
< valend
)
1121 if (obj
.type
== CUPS_PS_OTHER
)
1123 if (!strcmp(obj
.value
.other
, "true"))
1125 obj
.type
= CUPS_PS_BOOLEAN
;
1126 obj
.value
.boolean
= 1;
1128 else if (!strcmp(obj
.value
.other
, "false"))
1130 obj
.type
= CUPS_PS_BOOLEAN
;
1131 obj
.value
.boolean
= 0;
1133 else if (!strcmp(obj
.value
.other
, "null"))
1134 obj
.type
= CUPS_PS_NULL
;
1135 else if (!strcmp(obj
.value
.other
, "cleartomark"))
1136 obj
.type
= CUPS_PS_CLEARTOMARK
;
1137 else if (!strcmp(obj
.value
.other
, "copy"))
1138 obj
.type
= CUPS_PS_COPY
;
1139 else if (!strcmp(obj
.value
.other
, "dup"))
1140 obj
.type
= CUPS_PS_DUP
;
1141 else if (!strcmp(obj
.value
.other
, "index"))
1142 obj
.type
= CUPS_PS_INDEX
;
1143 else if (!strcmp(obj
.value
.other
, "pop"))
1144 obj
.type
= CUPS_PS_POP
;
1145 else if (!strcmp(obj
.value
.other
, "roll"))
1146 obj
.type
= CUPS_PS_ROLL
;
1147 else if (!strcmp(obj
.value
.other
, "setpagedevice"))
1148 obj
.type
= CUPS_PS_SETPAGEDEVICE
;
1149 else if (!strcmp(obj
.value
.other
, "stopped"))
1150 obj
.type
= CUPS_PS_STOPPED
;
1156 * Save the current position in the string and return the new object...
1161 return (push_stack(st
, &obj
));
1166 * 'setpagedevice()' - Simulate the PostScript setpagedevice operator.
1169 static int /* O - 0 on success, -1 on error */
1171 _cups_ps_stack_t
*st
, /* I - Stack */
1172 cups_page_header2_t
*h
, /* O - Page header */
1173 int *preferred_bits
)/* O - Preferred bits per color */
1175 int i
; /* Index into array */
1176 _cups_ps_obj_t
*obj
, /* Current object */
1177 *end
; /* End of dictionary */
1178 const char *name
; /* Attribute name */
1182 * Make sure we have a dictionary on the stack...
1185 if (st
->num_objs
== 0)
1188 obj
= end
= st
->objs
+ st
->num_objs
- 1;
1190 if (obj
->type
!= CUPS_PS_END_DICT
)
1195 while (obj
> st
->objs
)
1197 if (obj
->type
== CUPS_PS_START_DICT
)
1207 * Found the start of the dictionary, empty the stack to this point...
1210 st
->num_objs
= obj
- st
->objs
;
1213 * Now pull /name and value pairs from the dictionary...
1216 DEBUG_puts(" Dictionary:");
1218 for (obj
++; obj
< end
; obj
++)
1224 if (obj
->type
!= CUPS_PS_NAME
)
1227 name
= obj
->value
.name
;
1231 printf(" /%s ", name
);
1237 * Then grab the value...
1240 if (!strcmp(name
, "MediaClass") && obj
->type
== CUPS_PS_STRING
)
1241 strlcpy(h
->MediaClass
, obj
->value
.string
, sizeof(h
->MediaClass
));
1242 else if (!strcmp(name
, "MediaColor") && obj
->type
== CUPS_PS_STRING
)
1243 strlcpy(h
->MediaColor
, obj
->value
.string
, sizeof(h
->MediaColor
));
1244 else if (!strcmp(name
, "MediaType") && obj
->type
== CUPS_PS_STRING
)
1245 strlcpy(h
->MediaType
, obj
->value
.string
, sizeof(h
->MediaType
));
1246 else if (!strcmp(name
, "OutputType") && obj
->type
== CUPS_PS_STRING
)
1247 strlcpy(h
->OutputType
, obj
->value
.string
, sizeof(h
->OutputType
));
1248 else if (!strcmp(name
, "AdvanceDistance") && obj
->type
== CUPS_PS_NUMBER
)
1249 h
->AdvanceDistance
= (unsigned)obj
->value
.number
;
1250 else if (!strcmp(name
, "AdvanceMedia") && obj
->type
== CUPS_PS_NUMBER
)
1251 h
->AdvanceMedia
= (unsigned)obj
->value
.number
;
1252 else if (!strcmp(name
, "Collate") && obj
->type
== CUPS_PS_BOOLEAN
)
1253 h
->Collate
= (unsigned)obj
->value
.boolean
;
1254 else if (!strcmp(name
, "CutMedia") && obj
->type
== CUPS_PS_NUMBER
)
1255 h
->CutMedia
= (cups_cut_t
)(unsigned)obj
->value
.number
;
1256 else if (!strcmp(name
, "Duplex") && obj
->type
== CUPS_PS_BOOLEAN
)
1257 h
->Duplex
= (unsigned)obj
->value
.boolean
;
1258 else if (!strcmp(name
, "HWResolution") && obj
->type
== CUPS_PS_START_ARRAY
)
1260 if (obj
[1].type
== CUPS_PS_NUMBER
&& obj
[2].type
== CUPS_PS_NUMBER
&&
1261 obj
[3].type
== CUPS_PS_END_ARRAY
)
1263 h
->HWResolution
[0] = (unsigned)obj
[1].value
.number
;
1264 h
->HWResolution
[1] = (unsigned)obj
[2].value
.number
;
1270 else if (!strcmp(name
, "InsertSheet") && obj
->type
== CUPS_PS_BOOLEAN
)
1271 h
->InsertSheet
= (unsigned)obj
->value
.boolean
;
1272 else if (!strcmp(name
, "Jog") && obj
->type
== CUPS_PS_NUMBER
)
1273 h
->Jog
= (unsigned)obj
->value
.number
;
1274 else if (!strcmp(name
, "LeadingEdge") && obj
->type
== CUPS_PS_NUMBER
)
1275 h
->LeadingEdge
= (unsigned)obj
->value
.number
;
1276 else if (!strcmp(name
, "ManualFeed") && obj
->type
== CUPS_PS_BOOLEAN
)
1277 h
->ManualFeed
= (unsigned)obj
->value
.boolean
;
1278 else if ((!strcmp(name
, "cupsMediaPosition") || /* Compatibility */
1279 !strcmp(name
, "MediaPosition")) && obj
->type
== CUPS_PS_NUMBER
)
1280 h
->MediaPosition
= (unsigned)obj
->value
.number
;
1281 else if (!strcmp(name
, "MediaWeight") && obj
->type
== CUPS_PS_NUMBER
)
1282 h
->MediaWeight
= (unsigned)obj
->value
.number
;
1283 else if (!strcmp(name
, "MirrorPrint") && obj
->type
== CUPS_PS_BOOLEAN
)
1284 h
->MirrorPrint
= (unsigned)obj
->value
.boolean
;
1285 else if (!strcmp(name
, "NegativePrint") && obj
->type
== CUPS_PS_BOOLEAN
)
1286 h
->NegativePrint
= (unsigned)obj
->value
.boolean
;
1287 else if (!strcmp(name
, "NumCopies") && obj
->type
== CUPS_PS_NUMBER
)
1288 h
->NumCopies
= (unsigned)obj
->value
.number
;
1289 else if (!strcmp(name
, "Orientation") && obj
->type
== CUPS_PS_NUMBER
)
1290 h
->Orientation
= (unsigned)obj
->value
.number
;
1291 else if (!strcmp(name
, "OutputFaceUp") && obj
->type
== CUPS_PS_BOOLEAN
)
1292 h
->OutputFaceUp
= (unsigned)obj
->value
.boolean
;
1293 else if (!strcmp(name
, "PageSize") && obj
->type
== CUPS_PS_START_ARRAY
)
1295 if (obj
[1].type
== CUPS_PS_NUMBER
&& obj
[2].type
== CUPS_PS_NUMBER
&&
1296 obj
[3].type
== CUPS_PS_END_ARRAY
)
1298 h
->cupsPageSize
[0] = obj
[1].value
.number
;
1299 h
->cupsPageSize
[1] = obj
[2].value
.number
;
1301 h
->PageSize
[0] = (unsigned)obj
[1].value
.number
;
1302 h
->PageSize
[1] = (unsigned)obj
[2].value
.number
;
1309 else if (!strcmp(name
, "Separations") && obj
->type
== CUPS_PS_BOOLEAN
)
1310 h
->Separations
= (unsigned)obj
->value
.boolean
;
1311 else if (!strcmp(name
, "TraySwitch") && obj
->type
== CUPS_PS_BOOLEAN
)
1312 h
->TraySwitch
= (unsigned)obj
->value
.boolean
;
1313 else if (!strcmp(name
, "Tumble") && obj
->type
== CUPS_PS_BOOLEAN
)
1314 h
->Tumble
= (unsigned)obj
->value
.boolean
;
1315 else if (!strcmp(name
, "cupsMediaType") && obj
->type
== CUPS_PS_NUMBER
)
1316 h
->cupsMediaType
= (unsigned)obj
->value
.number
;
1317 else if (!strcmp(name
, "cupsBitsPerColor") && obj
->type
== CUPS_PS_NUMBER
)
1318 h
->cupsBitsPerColor
= (unsigned)obj
->value
.number
;
1319 else if (!strcmp(name
, "cupsPreferredBitsPerColor") &&
1320 obj
->type
== CUPS_PS_NUMBER
)
1321 *preferred_bits
= (int)obj
->value
.number
;
1322 else if (!strcmp(name
, "cupsColorOrder") && obj
->type
== CUPS_PS_NUMBER
)
1323 h
->cupsColorOrder
= (cups_order_t
)(unsigned)obj
->value
.number
;
1324 else if (!strcmp(name
, "cupsColorSpace") && obj
->type
== CUPS_PS_NUMBER
)
1325 h
->cupsColorSpace
= (cups_cspace_t
)(unsigned)obj
->value
.number
;
1326 else if (!strcmp(name
, "cupsCompression") && obj
->type
== CUPS_PS_NUMBER
)
1327 h
->cupsCompression
= (unsigned)obj
->value
.number
;
1328 else if (!strcmp(name
, "cupsRowCount") && obj
->type
== CUPS_PS_NUMBER
)
1329 h
->cupsRowCount
= (unsigned)obj
->value
.number
;
1330 else if (!strcmp(name
, "cupsRowFeed") && obj
->type
== CUPS_PS_NUMBER
)
1331 h
->cupsRowFeed
= (unsigned)obj
->value
.number
;
1332 else if (!strcmp(name
, "cupsRowStep") && obj
->type
== CUPS_PS_NUMBER
)
1333 h
->cupsRowStep
= (unsigned)obj
->value
.number
;
1334 else if (!strcmp(name
, "cupsBorderlessScalingFactor") &&
1335 obj
->type
== CUPS_PS_NUMBER
)
1336 h
->cupsBorderlessScalingFactor
= obj
->value
.number
;
1337 else if (!strncmp(name
, "cupsInteger", 11) && obj
->type
== CUPS_PS_NUMBER
)
1339 if ((i
= atoi(name
+ 11)) < 0 || i
> 15)
1342 h
->cupsInteger
[i
] = (unsigned)obj
->value
.number
;
1344 else if (!strncmp(name
, "cupsReal", 8) && obj
->type
== CUPS_PS_NUMBER
)
1346 if ((i
= atoi(name
+ 8)) < 0 || i
> 15)
1349 h
->cupsReal
[i
] = obj
->value
.number
;
1351 else if (!strncmp(name
, "cupsString", 10) && obj
->type
== CUPS_PS_STRING
)
1353 if ((i
= atoi(name
+ 10)) < 0 || i
> 15)
1356 strlcpy(h
->cupsString
[i
], obj
->value
.string
, sizeof(h
->cupsString
[i
]));
1358 else if (!strcmp(name
, "cupsMarkerType") && obj
->type
== CUPS_PS_STRING
)
1359 strlcpy(h
->cupsMarkerType
, obj
->value
.string
, sizeof(h
->cupsMarkerType
));
1360 else if (!strcmp(name
, "cupsPageSizeName") && obj
->type
== CUPS_PS_STRING
)
1361 strlcpy(h
->cupsPageSizeName
, obj
->value
.string
,
1362 sizeof(h
->cupsPageSizeName
));
1363 else if (!strcmp(name
, "cupsRenderingIntent") &&
1364 obj
->type
== CUPS_PS_STRING
)
1365 strlcpy(h
->cupsRenderingIntent
, obj
->value
.string
,
1366 sizeof(h
->cupsRenderingIntent
));
1370 * Ignore unknown name+value...
1373 DEBUG_printf((" Unknown name (\"%s\") or value...\n", name
));
1375 while (obj
[1].type
!= CUPS_PS_NAME
&& obj
< end
)
1386 * 'DEBUG_object()' - Print an object's value...
1390 DEBUG_object(_cups_ps_obj_t
*obj
) /* I - Object to print */
1395 printf("/%s", obj
->value
.name
);
1398 case CUPS_PS_NUMBER
:
1399 printf("%g", obj
->value
.number
);
1402 case CUPS_PS_STRING
:
1403 printf("(%s)", obj
->value
.string
);
1406 case CUPS_PS_BOOLEAN
:
1407 if (obj
->value
.boolean
)
1408 fputs("true", stdout
);
1410 fputs("false", stdout
);
1414 fputs("null", stdout
);
1417 case CUPS_PS_START_ARRAY
:
1421 case CUPS_PS_END_ARRAY
:
1425 case CUPS_PS_START_DICT
:
1426 fputs("<<", stdout
);
1429 case CUPS_PS_END_DICT
:
1430 fputs(">>", stdout
);
1433 case CUPS_PS_START_PROC
:
1437 case CUPS_PS_END_PROC
:
1441 case CUPS_PS_CLEARTOMARK
:
1442 fputs("--cleartomark--", stdout
);
1446 fputs("--copy--", stdout
);
1450 fputs("--dup--", stdout
);
1453 case CUPS_PS_INDEX
:
1454 fputs("--index--", stdout
);
1458 fputs("--pop--", stdout
);
1462 fputs("--roll--", stdout
);
1465 case CUPS_PS_SETPAGEDEVICE
:
1466 fputs("--setpagedevice--", stdout
);
1469 case CUPS_PS_STOPPED
:
1470 fputs("--stopped--", stdout
);
1473 case CUPS_PS_OTHER
:
1474 printf("--%s--", obj
->value
.other
);
1481 * 'DEBUG_stack()' - Print a stack...
1485 DEBUG_stack(_cups_ps_stack_t
*st
) /* I - Stack */
1487 int c
; /* Looping var */
1488 _cups_ps_obj_t
*obj
; /* Current object on stack */
1491 for (obj
= st
->objs
, c
= st
->num_objs
; c
> 0; c
--, obj
++)
1503 * End of "$Id: interpret.c 6282 2007-02-14 16:33:54Z mike $".