4 * PPD command interpreter for CUPS.
6 * Copyright 2007-2015 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 * Include necessary headers...
22 #include <cups/raster-private.h>
27 * Stack values for the PostScript mini-interpreter...
49 CUPS_PS_SETPAGEDEVICE
,
56 _cups_ps_type_t type
; /* Object type */
59 int boolean
; /* Boolean value */
60 char name
[64]; /* Name value */
61 double number
; /* Number value */
62 char other
[64]; /* Other operator */
63 char string
[64]; /* Sring value */
69 int num_objs
, /* Number of objects on stack */
70 alloc_objs
; /* Number of allocated objects */
71 _cups_ps_obj_t
*objs
; /* Objects in stack */
79 static int cleartomark_stack(_cups_ps_stack_t
*st
);
80 static int copy_stack(_cups_ps_stack_t
*st
, int count
);
81 static void delete_stack(_cups_ps_stack_t
*st
);
82 static void error_object(_cups_ps_obj_t
*obj
);
83 static void error_stack(_cups_ps_stack_t
*st
, const char *title
);
84 static _cups_ps_obj_t
*index_stack(_cups_ps_stack_t
*st
, int n
);
85 static _cups_ps_stack_t
*new_stack(void);
86 static _cups_ps_obj_t
*pop_stack(_cups_ps_stack_t
*st
);
87 static _cups_ps_obj_t
*push_stack(_cups_ps_stack_t
*st
,
89 static int roll_stack(_cups_ps_stack_t
*st
, int c
, int s
);
90 static _cups_ps_obj_t
*scan_ps(_cups_ps_stack_t
*st
, char **ptr
);
91 static int setpagedevice(_cups_ps_stack_t
*st
,
92 cups_page_header2_t
*h
,
95 static void DEBUG_object(const char *prefix
, _cups_ps_obj_t
*obj
);
96 static void DEBUG_stack(const char *prefix
, _cups_ps_stack_t
*st
);
101 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
103 * This function is used by raster image processing (RIP) filters like
104 * cgpdftoraster and imagetoraster when writing CUPS raster data for a page.
105 * It is not used by raster printer driver filters which only read CUPS
109 * @code cupsRasterInterpretPPD@ does not mark the options in the PPD using
110 * the "num_options" and "options" arguments. Instead, mark the options with
111 * @code cupsMarkOptions@ and @code ppdMarkOption@ prior to calling it -
112 * this allows for per-page options without manipulating the options array.
114 * The "func" argument specifies an optional callback function that is
115 * called prior to the computation of the final raster data. The function
116 * can make changes to the @link cups_page_header2_t@ data as needed to use a
117 * supported raster format and then returns 0 on success and -1 if the
118 * requested attributes cannot be supported.
121 * @code cupsRasterInterpretPPD@ supports a subset of the PostScript language.
122 * Currently only the @code [@, @code ]@, @code <<@, @code >>@, @code {@,
123 * @code }@, @code cleartomark@, @code copy@, @code dup@, @code index@,
124 * @code pop@, @code roll@, @code setpagedevice@, and @code stopped@ operators
127 * @since CUPS 1.2/OS X 10.5@
130 int /* O - 0 on success, -1 on failure */
131 cupsRasterInterpretPPD(
132 cups_page_header2_t
*h
, /* O - Page header to create */
133 ppd_file_t
*ppd
, /* I - PPD file */
134 int num_options
, /* I - Number of options */
135 cups_option_t
*options
, /* I - Options */
136 cups_interpret_cb_t func
) /* I - Optional page header callback (@code NULL@ for none) */
138 int status
; /* Cummulative status */
139 char *code
; /* Code to run */
140 const char *val
; /* Option value */
141 ppd_size_t
*size
; /* Current size */
142 float left
, /* Left position */
143 bottom
, /* Bottom position */
144 right
, /* Right position */
145 top
, /* Top position */
146 temp1
, temp2
; /* Temporary variables for swapping */
147 int preferred_bits
; /* Preferred bits per color */
151 * Range check input...
154 _cupsRasterClearError();
158 _cupsRasterAddError("Page header cannot be NULL!\n");
163 * Reset the page header to the defaults...
166 memset(h
, 0, sizeof(cups_page_header2_t
));
169 h
->PageSize
[0] = 612;
170 h
->PageSize
[1] = 792;
171 h
->HWResolution
[0] = 100;
172 h
->HWResolution
[1] = 100;
173 h
->cupsBitsPerColor
= 1;
174 h
->cupsColorOrder
= CUPS_ORDER_CHUNKED
;
175 h
->cupsColorSpace
= CUPS_CSPACE_K
;
176 h
->cupsBorderlessScalingFactor
= 1.0f
;
177 h
->cupsPageSize
[0] = 612.0f
;
178 h
->cupsPageSize
[1] = 792.0f
;
179 h
->cupsImagingBBox
[0] = 0.0f
;
180 h
->cupsImagingBBox
[1] = 0.0f
;
181 h
->cupsImagingBBox
[2] = 612.0f
;
182 h
->cupsImagingBBox
[3] = 792.0f
;
184 strlcpy(h
->cupsPageSizeName
, "Letter", sizeof(h
->cupsPageSizeName
));
188 * cupsInteger0 is also used for the total page count on OS X; set an
189 * uncommon default value so we can tell if the driver is using cupsInteger0.
192 h
->cupsInteger
[0] = 0x80000000;
193 #endif /* __APPLE__ */
196 * Apply patches and options to the page header...
205 * Apply any patch code (used to override the defaults...)
209 status
|= _cupsRasterExecPS(h
, &preferred_bits
, ppd
->patches
);
212 * Then apply printer options in the proper order...
215 if ((code
= ppdEmitString(ppd
, PPD_ORDER_DOCUMENT
, 0.0)) != NULL
)
217 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
221 if ((code
= ppdEmitString(ppd
, PPD_ORDER_ANY
, 0.0)) != NULL
)
223 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
227 if ((code
= ppdEmitString(ppd
, PPD_ORDER_PROLOG
, 0.0)) != NULL
)
229 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
233 if ((code
= ppdEmitString(ppd
, PPD_ORDER_PAGE
, 0.0)) != NULL
)
235 status
|= _cupsRasterExecPS(h
, &preferred_bits
, code
);
241 * Allow option override for page scaling...
244 if ((val
= cupsGetOption("cupsBorderlessScalingFactor", num_options
,
247 double sc
= atof(val
); /* Scale factor */
249 if (sc
>= 0.1 && sc
<= 2.0)
250 h
->cupsBorderlessScalingFactor
= (float)sc
;
254 * Get the margins for the current size...
257 if ((size
= ppdPageSize(ppd
, NULL
)) != NULL
)
260 * Use the margins from the PPD file...
264 bottom
= size
->bottom
;
268 strlcpy(h
->cupsPageSizeName
, size
->name
, sizeof(h
->cupsPageSizeName
));
270 h
->cupsPageSize
[0] = size
->width
;
271 h
->cupsPageSize
[1] = size
->length
;
276 * Use the default margins...
286 * Handle orientation...
289 switch (h
->Orientation
)
296 case CUPS_ORIENT_90
:
297 temp1
= h
->cupsPageSize
[0];
298 h
->cupsPageSize
[0] = h
->cupsPageSize
[1];
299 h
->cupsPageSize
[1] = temp1
;
303 left
= h
->cupsPageSize
[0] - top
;
304 right
= h
->cupsPageSize
[0] - bottom
;
305 bottom
= h
->cupsPageSize
[1] - temp1
;
306 top
= h
->cupsPageSize
[1] - temp2
;
309 case CUPS_ORIENT_180
:
312 left
= h
->cupsPageSize
[0] - right
;
313 right
= h
->cupsPageSize
[0] - temp1
;
314 bottom
= h
->cupsPageSize
[1] - top
;
315 top
= h
->cupsPageSize
[1] - temp2
;
318 case CUPS_ORIENT_270
:
319 temp1
= h
->cupsPageSize
[0];
320 h
->cupsPageSize
[0] = h
->cupsPageSize
[1];
321 h
->cupsPageSize
[1] = temp1
;
327 bottom
= h
->cupsPageSize
[1] - temp2
;
328 top
= h
->cupsPageSize
[1] - temp1
;
346 h
->PageSize
[0] = (unsigned)(h
->cupsPageSize
[0] *
347 h
->cupsBorderlessScalingFactor
);
348 h
->PageSize
[1] = (unsigned)(h
->cupsPageSize
[1] *
349 h
->cupsBorderlessScalingFactor
);
350 h
->Margins
[0] = (unsigned)(left
*
351 h
->cupsBorderlessScalingFactor
);
352 h
->Margins
[1] = (unsigned)(bottom
*
353 h
->cupsBorderlessScalingFactor
);
354 h
->ImagingBoundingBox
[0] = (unsigned)(left
*
355 h
->cupsBorderlessScalingFactor
);
356 h
->ImagingBoundingBox
[1] = (unsigned)(bottom
*
357 h
->cupsBorderlessScalingFactor
);
358 h
->ImagingBoundingBox
[2] = (unsigned)(right
*
359 h
->cupsBorderlessScalingFactor
);
360 h
->ImagingBoundingBox
[3] = (unsigned)(top
*
361 h
->cupsBorderlessScalingFactor
);
362 h
->cupsImagingBBox
[0] = (float)left
;
363 h
->cupsImagingBBox
[1] = (float)bottom
;
364 h
->cupsImagingBBox
[2] = (float)right
;
365 h
->cupsImagingBBox
[3] = (float)top
;
368 * Use the callback to validate the page header...
371 if (func
&& (*func
)(h
, preferred_bits
))
373 _cupsRasterAddError("Page header callback returned error.\n");
378 * Check parameters...
381 if (!h
->HWResolution
[0] || !h
->HWResolution
[1] ||
382 !h
->PageSize
[0] || !h
->PageSize
[1] ||
383 (h
->cupsBitsPerColor
!= 1 && h
->cupsBitsPerColor
!= 2 &&
384 h
->cupsBitsPerColor
!= 4 && h
->cupsBitsPerColor
!= 8 &&
385 h
->cupsBitsPerColor
!= 16) ||
386 h
->cupsBorderlessScalingFactor
< 0.1 ||
387 h
->cupsBorderlessScalingFactor
> 2.0)
389 _cupsRasterAddError("Page header uses unsupported values.\n");
394 * Compute the bitmap parameters...
397 h
->cupsWidth
= (unsigned)((right
- left
) * h
->cupsBorderlessScalingFactor
*
398 h
->HWResolution
[0] / 72.0f
+ 0.5f
);
399 h
->cupsHeight
= (unsigned)((top
- bottom
) * h
->cupsBorderlessScalingFactor
*
400 h
->HWResolution
[1] / 72.0f
+ 0.5f
);
402 switch (h
->cupsColorSpace
)
406 case CUPS_CSPACE_WHITE
:
407 case CUPS_CSPACE_GOLD
:
408 case CUPS_CSPACE_SILVER
:
409 case CUPS_CSPACE_SW
:
410 h
->cupsNumColors
= 1;
411 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
416 * Ensure that colorimetric colorspaces use at least 8 bits per
420 if (h
->cupsColorSpace
>= CUPS_CSPACE_CIEXYZ
&&
421 h
->cupsBitsPerColor
< 8)
422 h
->cupsBitsPerColor
= 8;
425 * Figure out the number of bits per pixel...
428 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
430 if (h
->cupsBitsPerColor
>= 8)
431 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 3;
433 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
436 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
438 h
->cupsNumColors
= 3;
441 case CUPS_CSPACE_KCMYcm
:
442 if (h
->cupsBitsPerColor
== 1)
444 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
445 h
->cupsBitsPerPixel
= 8;
447 h
->cupsBitsPerPixel
= 1;
449 h
->cupsNumColors
= 6;
454 * Fall through to CMYK code...
457 case CUPS_CSPACE_RGBA
:
458 case CUPS_CSPACE_RGBW
:
459 case CUPS_CSPACE_CMYK
:
460 case CUPS_CSPACE_YMCK
:
461 case CUPS_CSPACE_KCMY
:
462 case CUPS_CSPACE_GMCK
:
463 case CUPS_CSPACE_GMCS
:
464 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
465 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
467 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
469 h
->cupsNumColors
= 4;
472 case CUPS_CSPACE_DEVICE1
:
473 case CUPS_CSPACE_DEVICE2
:
474 case CUPS_CSPACE_DEVICE3
:
475 case CUPS_CSPACE_DEVICE4
:
476 case CUPS_CSPACE_DEVICE5
:
477 case CUPS_CSPACE_DEVICE6
:
478 case CUPS_CSPACE_DEVICE7
:
479 case CUPS_CSPACE_DEVICE8
:
480 case CUPS_CSPACE_DEVICE9
:
481 case CUPS_CSPACE_DEVICEA
:
482 case CUPS_CSPACE_DEVICEB
:
483 case CUPS_CSPACE_DEVICEC
:
484 case CUPS_CSPACE_DEVICED
:
485 case CUPS_CSPACE_DEVICEE
:
486 case CUPS_CSPACE_DEVICEF
:
487 h
->cupsNumColors
= h
->cupsColorSpace
- CUPS_CSPACE_DEVICE1
+ 1;
489 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
490 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* h
->cupsNumColors
;
492 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
496 h
->cupsBytesPerLine
= (h
->cupsBitsPerPixel
* h
->cupsWidth
+ 7) / 8;
498 if (h
->cupsColorOrder
== CUPS_ORDER_BANDED
)
499 h
->cupsBytesPerLine
*= h
->cupsNumColors
;
506 * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header.
509 int /* O - 0 on success, -1 on error */
511 cups_page_header2_t
*h
, /* O - Page header */
512 int *preferred_bits
,/* O - Preferred bits per color */
513 const char *code
) /* I - PS code to execute */
515 int error
= 0; /* Error condition? */
516 _cups_ps_stack_t
*st
; /* PostScript value stack */
517 _cups_ps_obj_t
*obj
; /* Object from top of stack */
518 char *codecopy
, /* Copy of code */
519 *codeptr
; /* Pointer into copy of code */
522 DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n",
523 h
, preferred_bits
, code
));
526 * Copy the PostScript code and create a stack...
529 if ((codecopy
= strdup(code
)) == NULL
)
531 _cupsRasterAddError("Unable to duplicate code string.\n");
535 if ((st
= new_stack()) == NULL
)
537 _cupsRasterAddError("Unable to create stack.\n");
543 * Parse the PS string until we run out of data...
548 while ((obj
= scan_ps(st
, &codeptr
)) != NULL
)
551 DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)", st
->num_objs
));
552 DEBUG_object("_cupsRasterExecPS", obj
);
558 /* Do nothing for regular values */
561 case CUPS_PS_CLEARTOMARK
:
564 if (cleartomark_stack(st
))
565 _cupsRasterAddError("cleartomark: Stack underflow.\n");
568 DEBUG_puts("1_cupsRasterExecPS: dup");
569 DEBUG_stack("_cupsRasterExecPS", st
);
575 if ((obj
= pop_stack(st
)) != NULL
)
577 copy_stack(st
, (int)obj
->value
.number
);
580 DEBUG_puts("_cupsRasterExecPS: copy");
581 DEBUG_stack("_cupsRasterExecPS", st
);
591 DEBUG_puts("_cupsRasterExecPS: dup");
592 DEBUG_stack("_cupsRasterExecPS", st
);
598 if ((obj
= pop_stack(st
)) != NULL
)
600 index_stack(st
, (int)obj
->value
.number
);
603 DEBUG_puts("_cupsRasterExecPS: index");
604 DEBUG_stack("_cupsRasterExecPS", st
);
614 DEBUG_puts("_cupsRasterExecPS: pop");
615 DEBUG_stack("_cupsRasterExecPS", st
);
621 if ((obj
= pop_stack(st
)) != NULL
)
626 c
= (int)obj
->value
.number
;
628 if ((obj
= pop_stack(st
)) != NULL
)
630 roll_stack(st
, (int)obj
->value
.number
, c
);
633 DEBUG_puts("_cupsRasterExecPS: roll");
634 DEBUG_stack("_cupsRasterExecPS", st
);
640 case CUPS_PS_SETPAGEDEVICE
:
642 setpagedevice(st
, h
, preferred_bits
);
645 DEBUG_puts("_cupsRasterExecPS: setpagedevice");
646 DEBUG_stack("_cupsRasterExecPS", st
);
650 case CUPS_PS_START_PROC
:
651 case CUPS_PS_END_PROC
:
652 case CUPS_PS_STOPPED
:
657 _cupsRasterAddError("Unknown operator \"%s\".\n", obj
->value
.other
);
659 DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\".", obj
->value
.other
));
673 if (st
->num_objs
> 0)
675 error_stack(st
, "Stack not empty:");
678 DEBUG_puts("_cupsRasterExecPS: Stack not empty");
679 DEBUG_stack("_cupsRasterExecPS", st
);
698 * 'cleartomark_stack()' - Clear to the last mark ([) on the stack.
701 static int /* O - 0 on success, -1 on error */
702 cleartomark_stack(_cups_ps_stack_t
*st
) /* I - Stack */
704 _cups_ps_obj_t
*obj
; /* Current object on stack */
707 while ((obj
= pop_stack(st
)) != NULL
)
708 if (obj
->type
== CUPS_PS_START_ARRAY
)
711 return (obj
? 0 : -1);
716 * 'copy_stack()' - Copy the top N stack objects.
719 static int /* O - 0 on success, -1 on error */
720 copy_stack(_cups_ps_stack_t
*st
, /* I - Stack */
721 int c
) /* I - Number of objects to copy */
731 if ((n
= st
->num_objs
- c
) < 0)
736 if (!push_stack(st
, st
->objs
+ n
))
748 * 'delete_stack()' - Free memory used by a stack.
752 delete_stack(_cups_ps_stack_t
*st
) /* I - Stack */
760 * 'error_object()' - Add an object's value to the current error message.
764 error_object(_cups_ps_obj_t
*obj
) /* I - Object to add */
769 _cupsRasterAddError(" /%s", obj
->value
.name
);
772 case CUPS_PS_NUMBER
:
773 _cupsRasterAddError(" %g", obj
->value
.number
);
776 case CUPS_PS_STRING
:
777 _cupsRasterAddError(" (%s)", obj
->value
.string
);
780 case CUPS_PS_BOOLEAN
:
781 if (obj
->value
.boolean
)
782 _cupsRasterAddError(" true");
784 _cupsRasterAddError(" false");
788 _cupsRasterAddError(" null");
791 case CUPS_PS_START_ARRAY
:
792 _cupsRasterAddError(" [");
795 case CUPS_PS_END_ARRAY
:
796 _cupsRasterAddError(" ]");
799 case CUPS_PS_START_DICT
:
800 _cupsRasterAddError(" <<");
803 case CUPS_PS_END_DICT
:
804 _cupsRasterAddError(" >>");
807 case CUPS_PS_START_PROC
:
808 _cupsRasterAddError(" {");
811 case CUPS_PS_END_PROC
:
812 _cupsRasterAddError(" }");
816 _cupsRasterAddError(" --copy--");
819 case CUPS_PS_CLEARTOMARK
:
820 _cupsRasterAddError(" --cleartomark--");
824 _cupsRasterAddError(" --dup--");
828 _cupsRasterAddError(" --index--");
832 _cupsRasterAddError(" --pop--");
836 _cupsRasterAddError(" --roll--");
839 case CUPS_PS_SETPAGEDEVICE
:
840 _cupsRasterAddError(" --setpagedevice--");
843 case CUPS_PS_STOPPED
:
844 _cupsRasterAddError(" --stopped--");
848 _cupsRasterAddError(" --%s--", obj
->value
.other
);
855 * 'error_stack()' - Add a stack to the current error message...
859 error_stack(_cups_ps_stack_t
*st
, /* I - Stack */
860 const char *title
) /* I - Title string */
862 int c
; /* Looping var */
863 _cups_ps_obj_t
*obj
; /* Current object on stack */
866 _cupsRasterAddError("%s", title
);
868 for (obj
= st
->objs
, c
= st
->num_objs
; c
> 0; c
--, obj
++)
871 _cupsRasterAddError("\n");
876 * 'index_stack()' - Copy the Nth value on the stack.
879 static _cups_ps_obj_t
* /* O - New object */
880 index_stack(_cups_ps_stack_t
*st
, /* I - Stack */
881 int n
) /* I - Object index */
883 if (n
< 0 || (n
= st
->num_objs
- n
- 1) < 0)
886 return (push_stack(st
, st
->objs
+ n
));
891 * 'new_stack()' - Create a new stack.
894 static _cups_ps_stack_t
* /* O - New stack */
897 _cups_ps_stack_t
*st
; /* New stack */
900 if ((st
= calloc(1, sizeof(_cups_ps_stack_t
))) == NULL
)
905 if ((st
->objs
= calloc(32, sizeof(_cups_ps_obj_t
))) == NULL
)
916 * 'pop_stock()' - Pop the top object off the stack.
919 static _cups_ps_obj_t
* /* O - Object */
920 pop_stack(_cups_ps_stack_t
*st
) /* I - Stack */
922 if (st
->num_objs
> 0)
926 return (st
->objs
+ st
->num_objs
);
934 * 'push_stack()' - Push an object on the stack.
937 static _cups_ps_obj_t
* /* O - New object */
938 push_stack(_cups_ps_stack_t
*st
, /* I - Stack */
939 _cups_ps_obj_t
*obj
) /* I - Object */
941 _cups_ps_obj_t
*temp
; /* New object */
944 if (st
->num_objs
>= st
->alloc_objs
)
948 st
->alloc_objs
+= 32;
950 if ((temp
= realloc(st
->objs
, (size_t)st
->alloc_objs
*
951 sizeof(_cups_ps_obj_t
))) == NULL
)
955 memset(temp
+ st
->num_objs
, 0, 32 * sizeof(_cups_ps_obj_t
));
958 temp
= st
->objs
+ st
->num_objs
;
961 memcpy(temp
, obj
, sizeof(_cups_ps_obj_t
));
968 * 'roll_stack()' - Rotate stack objects.
971 static int /* O - 0 on success, -1 on error */
972 roll_stack(_cups_ps_stack_t
*st
, /* I - Stack */
973 int c
, /* I - Number of objects */
974 int s
) /* I - Amount to shift */
976 _cups_ps_obj_t
*temp
; /* Temporary array of objects */
977 int n
; /* Index into array */
980 DEBUG_printf(("3roll_stack(st=%p, s=%d, c=%d)", st
, s
, c
));
983 * Range check input...
991 if ((n
= st
->num_objs
- c
) < 0)
1000 * Copy N objects and move things around...
1011 if ((temp
= calloc((size_t)s
, sizeof(_cups_ps_obj_t
))) == NULL
)
1014 memcpy(temp
, st
->objs
+ n
, (size_t)s
* sizeof(_cups_ps_obj_t
));
1015 memmove(st
->objs
+ n
, st
->objs
+ n
+ s
, (size_t)(c
- s
) * sizeof(_cups_ps_obj_t
));
1016 memcpy(st
->objs
+ n
+ c
- s
, temp
, (size_t)s
* sizeof(_cups_ps_obj_t
));
1024 if ((temp
= calloc((size_t)s
, sizeof(_cups_ps_obj_t
))) == NULL
)
1027 memcpy(temp
, st
->objs
+ n
+ c
- s
, (size_t)s
* sizeof(_cups_ps_obj_t
));
1028 memmove(st
->objs
+ n
+ s
, st
->objs
+ n
, (size_t)(c
- s
) * sizeof(_cups_ps_obj_t
));
1029 memcpy(st
->objs
+ n
, temp
, (size_t)s
* sizeof(_cups_ps_obj_t
));
1039 * 'scan_ps()' - Scan a string for the next PS object.
1042 static _cups_ps_obj_t
* /* O - New object or NULL on EOF */
1043 scan_ps(_cups_ps_stack_t
*st
, /* I - Stack */
1044 char **ptr
) /* IO - String pointer */
1046 _cups_ps_obj_t obj
; /* Current object */
1047 char *start
, /* Start of object */
1048 *cur
, /* Current position */
1049 *valptr
, /* Pointer into value string */
1050 *valend
; /* End of value string */
1051 int parens
; /* Parenthesis nesting level */
1055 * Skip leading whitespace...
1058 for (cur
= *ptr
; *cur
; cur
++)
1063 * Comment, skip to end of line...
1066 for (cur
++; *cur
&& *cur
!= '\n' && *cur
!= '\r'; cur
++);
1071 else if (!isspace(*cur
& 255))
1083 * See what we have...
1086 memset(&obj
, 0, sizeof(obj
));
1090 case '(' : /* (string) */
1091 obj
.type
= CUPS_PS_STRING
;
1094 for (cur
++, parens
= 1, valptr
= obj
.value
.string
,
1095 valend
= obj
.value
.string
+ sizeof(obj
.value
.string
) - 1;
1099 if (*cur
== ')' && parens
== 1)
1104 else if (*cur
== ')')
1107 if (valptr
>= valend
)
1117 * Decode escaped character...
1124 else if (*cur
== 'f')
1126 else if (*cur
== 'n')
1128 else if (*cur
== 'r')
1130 else if (*cur
== 't')
1132 else if (*cur
>= '0' && *cur
<= '7')
1134 int ch
= *cur
- '0';
1136 if (cur
[1] >= '0' && cur
[1] <= '7')
1139 ch
= (ch
<< 3) + *cur
- '0';
1142 if (cur
[1] >= '0' && cur
[1] <= '7')
1145 ch
= (ch
<< 3) + *cur
- '0';
1148 *valptr
++ = (char)ch
;
1150 else if (*cur
== '\r')
1155 else if (*cur
!= '\n')
1172 case '[' : /* Start array */
1173 obj
.type
= CUPS_PS_START_ARRAY
;
1177 case ']' : /* End array */
1178 obj
.type
= CUPS_PS_END_ARRAY
;
1182 case '<' : /* Start dictionary or hex string */
1185 obj
.type
= CUPS_PS_START_DICT
;
1190 obj
.type
= CUPS_PS_STRING
;
1193 for (cur
++, valptr
= obj
.value
.string
,
1194 valend
= obj
.value
.string
+ sizeof(obj
.value
.string
) - 1;
1198 int ch
; /* Current character */
1204 else if (valptr
>= valend
|| !isxdigit(*cur
& 255))
1210 if (*cur
>= '0' && *cur
<= '9')
1211 ch
= (*cur
- '0') << 4;
1213 ch
= (tolower(*cur
) - 'a' + 10) << 4;
1215 if (isxdigit(cur
[1] & 255))
1219 if (*cur
>= '0' && *cur
<= '9')
1222 ch
|= tolower(*cur
) - 'a' + 10;
1225 *valptr
++ = (char)ch
;
1238 case '>' : /* End dictionary? */
1241 obj
.type
= CUPS_PS_END_DICT
;
1246 obj
.type
= CUPS_PS_OTHER
;
1247 obj
.value
.other
[0] = *cur
;
1253 case '{' : /* Start procedure */
1254 obj
.type
= CUPS_PS_START_PROC
;
1258 case '}' : /* End procedure */
1259 obj
.type
= CUPS_PS_END_PROC
;
1263 case '-' : /* Possible number */
1265 if (!isdigit(cur
[1] & 255) && cur
[1] != '.')
1267 obj
.type
= CUPS_PS_OTHER
;
1268 obj
.value
.other
[0] = *cur
;
1274 case '0' : /* Number */
1285 obj
.type
= CUPS_PS_NUMBER
;
1288 for (cur
++; *cur
; cur
++)
1289 if (!isdigit(*cur
& 255))
1295 * Integer with radix...
1298 obj
.value
.number
= strtol(cur
+ 1, &cur
, atoi(start
));
1301 else if (strchr(".Ee()<>[]{}/%", *cur
) || isspace(*cur
& 255))
1304 * Integer or real number...
1307 obj
.value
.number
= _cupsStrScand(start
, &cur
, localeconv());
1313 default : /* Operator/variable name */
1318 obj
.type
= CUPS_PS_NAME
;
1319 valptr
= obj
.value
.name
;
1320 valend
= obj
.value
.name
+ sizeof(obj
.value
.name
) - 1;
1325 obj
.type
= CUPS_PS_OTHER
;
1326 valptr
= obj
.value
.other
;
1327 valend
= obj
.value
.other
+ sizeof(obj
.value
.other
) - 1;
1332 if (strchr("()<>[]{}/%", *cur
) || isspace(*cur
& 255))
1334 else if (valptr
< valend
)
1343 if (obj
.type
== CUPS_PS_OTHER
)
1345 if (!strcmp(obj
.value
.other
, "true"))
1347 obj
.type
= CUPS_PS_BOOLEAN
;
1348 obj
.value
.boolean
= 1;
1350 else if (!strcmp(obj
.value
.other
, "false"))
1352 obj
.type
= CUPS_PS_BOOLEAN
;
1353 obj
.value
.boolean
= 0;
1355 else if (!strcmp(obj
.value
.other
, "null"))
1356 obj
.type
= CUPS_PS_NULL
;
1357 else if (!strcmp(obj
.value
.other
, "cleartomark"))
1358 obj
.type
= CUPS_PS_CLEARTOMARK
;
1359 else if (!strcmp(obj
.value
.other
, "copy"))
1360 obj
.type
= CUPS_PS_COPY
;
1361 else if (!strcmp(obj
.value
.other
, "dup"))
1362 obj
.type
= CUPS_PS_DUP
;
1363 else if (!strcmp(obj
.value
.other
, "index"))
1364 obj
.type
= CUPS_PS_INDEX
;
1365 else if (!strcmp(obj
.value
.other
, "pop"))
1366 obj
.type
= CUPS_PS_POP
;
1367 else if (!strcmp(obj
.value
.other
, "roll"))
1368 obj
.type
= CUPS_PS_ROLL
;
1369 else if (!strcmp(obj
.value
.other
, "setpagedevice"))
1370 obj
.type
= CUPS_PS_SETPAGEDEVICE
;
1371 else if (!strcmp(obj
.value
.other
, "stopped"))
1372 obj
.type
= CUPS_PS_STOPPED
;
1378 * Save the current position in the string and return the new object...
1383 return (push_stack(st
, &obj
));
1388 * 'setpagedevice()' - Simulate the PostScript setpagedevice operator.
1391 static int /* O - 0 on success, -1 on error */
1393 _cups_ps_stack_t
*st
, /* I - Stack */
1394 cups_page_header2_t
*h
, /* O - Page header */
1395 int *preferred_bits
)/* O - Preferred bits per color */
1397 int i
; /* Index into array */
1398 _cups_ps_obj_t
*obj
, /* Current object */
1399 *end
; /* End of dictionary */
1400 const char *name
; /* Attribute name */
1404 * Make sure we have a dictionary on the stack...
1407 if (st
->num_objs
== 0)
1410 obj
= end
= st
->objs
+ st
->num_objs
- 1;
1412 if (obj
->type
!= CUPS_PS_END_DICT
)
1417 while (obj
> st
->objs
)
1419 if (obj
->type
== CUPS_PS_START_DICT
)
1429 * Found the start of the dictionary, empty the stack to this point...
1432 st
->num_objs
= (int)(obj
- st
->objs
);
1435 * Now pull /name and value pairs from the dictionary...
1438 DEBUG_puts("3setpagedevice: Dictionary:");
1440 for (obj
++; obj
< end
; obj
++)
1446 if (obj
->type
!= CUPS_PS_NAME
)
1449 name
= obj
->value
.name
;
1453 DEBUG_printf(("4setpagedevice: /%s ", name
));
1454 DEBUG_object("setpagedevice", obj
);
1458 * Then grab the value...
1461 if (!strcmp(name
, "MediaClass") && obj
->type
== CUPS_PS_STRING
)
1462 strlcpy(h
->MediaClass
, obj
->value
.string
, sizeof(h
->MediaClass
));
1463 else if (!strcmp(name
, "MediaColor") && obj
->type
== CUPS_PS_STRING
)
1464 strlcpy(h
->MediaColor
, obj
->value
.string
, sizeof(h
->MediaColor
));
1465 else if (!strcmp(name
, "MediaType") && obj
->type
== CUPS_PS_STRING
)
1466 strlcpy(h
->MediaType
, obj
->value
.string
, sizeof(h
->MediaType
));
1467 else if (!strcmp(name
, "OutputType") && obj
->type
== CUPS_PS_STRING
)
1468 strlcpy(h
->OutputType
, obj
->value
.string
, sizeof(h
->OutputType
));
1469 else if (!strcmp(name
, "AdvanceDistance") && obj
->type
== CUPS_PS_NUMBER
)
1470 h
->AdvanceDistance
= (unsigned)obj
->value
.number
;
1471 else if (!strcmp(name
, "AdvanceMedia") && obj
->type
== CUPS_PS_NUMBER
)
1472 h
->AdvanceMedia
= (unsigned)obj
->value
.number
;
1473 else if (!strcmp(name
, "Collate") && obj
->type
== CUPS_PS_BOOLEAN
)
1474 h
->Collate
= (unsigned)obj
->value
.boolean
;
1475 else if (!strcmp(name
, "CutMedia") && obj
->type
== CUPS_PS_NUMBER
)
1476 h
->CutMedia
= (cups_cut_t
)(unsigned)obj
->value
.number
;
1477 else if (!strcmp(name
, "Duplex") && obj
->type
== CUPS_PS_BOOLEAN
)
1478 h
->Duplex
= (unsigned)obj
->value
.boolean
;
1479 else if (!strcmp(name
, "HWResolution") && obj
->type
== CUPS_PS_START_ARRAY
)
1481 if (obj
[1].type
== CUPS_PS_NUMBER
&& obj
[2].type
== CUPS_PS_NUMBER
&&
1482 obj
[3].type
== CUPS_PS_END_ARRAY
)
1484 h
->HWResolution
[0] = (unsigned)obj
[1].value
.number
;
1485 h
->HWResolution
[1] = (unsigned)obj
[2].value
.number
;
1491 else if (!strcmp(name
, "InsertSheet") && obj
->type
== CUPS_PS_BOOLEAN
)
1492 h
->InsertSheet
= (unsigned)obj
->value
.boolean
;
1493 else if (!strcmp(name
, "Jog") && obj
->type
== CUPS_PS_NUMBER
)
1494 h
->Jog
= (unsigned)obj
->value
.number
;
1495 else if (!strcmp(name
, "LeadingEdge") && obj
->type
== CUPS_PS_NUMBER
)
1496 h
->LeadingEdge
= (unsigned)obj
->value
.number
;
1497 else if (!strcmp(name
, "ManualFeed") && obj
->type
== CUPS_PS_BOOLEAN
)
1498 h
->ManualFeed
= (unsigned)obj
->value
.boolean
;
1499 else if ((!strcmp(name
, "cupsMediaPosition") ||
1500 !strcmp(name
, "MediaPosition")) && obj
->type
== CUPS_PS_NUMBER
)
1503 * cupsMediaPosition is supported for backwards compatibility only.
1504 * We added it back in the Ghostscript 5.50 days to work around a
1505 * bug in Ghostscript WRT handling of MediaPosition and setpagedevice.
1507 * All new development should set MediaPosition...
1510 h
->MediaPosition
= (unsigned)obj
->value
.number
;
1512 else if (!strcmp(name
, "MediaWeight") && obj
->type
== CUPS_PS_NUMBER
)
1513 h
->MediaWeight
= (unsigned)obj
->value
.number
;
1514 else if (!strcmp(name
, "MirrorPrint") && obj
->type
== CUPS_PS_BOOLEAN
)
1515 h
->MirrorPrint
= (unsigned)obj
->value
.boolean
;
1516 else if (!strcmp(name
, "NegativePrint") && obj
->type
== CUPS_PS_BOOLEAN
)
1517 h
->NegativePrint
= (unsigned)obj
->value
.boolean
;
1518 else if (!strcmp(name
, "NumCopies") && obj
->type
== CUPS_PS_NUMBER
)
1519 h
->NumCopies
= (unsigned)obj
->value
.number
;
1520 else if (!strcmp(name
, "Orientation") && obj
->type
== CUPS_PS_NUMBER
)
1521 h
->Orientation
= (unsigned)obj
->value
.number
;
1522 else if (!strcmp(name
, "OutputFaceUp") && obj
->type
== CUPS_PS_BOOLEAN
)
1523 h
->OutputFaceUp
= (unsigned)obj
->value
.boolean
;
1524 else if (!strcmp(name
, "PageSize") && obj
->type
== CUPS_PS_START_ARRAY
)
1526 if (obj
[1].type
== CUPS_PS_NUMBER
&& obj
[2].type
== CUPS_PS_NUMBER
&&
1527 obj
[3].type
== CUPS_PS_END_ARRAY
)
1529 h
->cupsPageSize
[0] = (float)obj
[1].value
.number
;
1530 h
->cupsPageSize
[1] = (float)obj
[2].value
.number
;
1532 h
->PageSize
[0] = (unsigned)obj
[1].value
.number
;
1533 h
->PageSize
[1] = (unsigned)obj
[2].value
.number
;
1540 else if (!strcmp(name
, "Separations") && obj
->type
== CUPS_PS_BOOLEAN
)
1541 h
->Separations
= (unsigned)obj
->value
.boolean
;
1542 else if (!strcmp(name
, "TraySwitch") && obj
->type
== CUPS_PS_BOOLEAN
)
1543 h
->TraySwitch
= (unsigned)obj
->value
.boolean
;
1544 else if (!strcmp(name
, "Tumble") && obj
->type
== CUPS_PS_BOOLEAN
)
1545 h
->Tumble
= (unsigned)obj
->value
.boolean
;
1546 else if (!strcmp(name
, "cupsMediaType") && obj
->type
== CUPS_PS_NUMBER
)
1547 h
->cupsMediaType
= (unsigned)obj
->value
.number
;
1548 else if (!strcmp(name
, "cupsBitsPerColor") && obj
->type
== CUPS_PS_NUMBER
)
1549 h
->cupsBitsPerColor
= (unsigned)obj
->value
.number
;
1550 else if (!strcmp(name
, "cupsPreferredBitsPerColor") &&
1551 obj
->type
== CUPS_PS_NUMBER
)
1552 *preferred_bits
= (int)obj
->value
.number
;
1553 else if (!strcmp(name
, "cupsColorOrder") && obj
->type
== CUPS_PS_NUMBER
)
1554 h
->cupsColorOrder
= (cups_order_t
)(unsigned)obj
->value
.number
;
1555 else if (!strcmp(name
, "cupsColorSpace") && obj
->type
== CUPS_PS_NUMBER
)
1556 h
->cupsColorSpace
= (cups_cspace_t
)(unsigned)obj
->value
.number
;
1557 else if (!strcmp(name
, "cupsCompression") && obj
->type
== CUPS_PS_NUMBER
)
1558 h
->cupsCompression
= (unsigned)obj
->value
.number
;
1559 else if (!strcmp(name
, "cupsRowCount") && obj
->type
== CUPS_PS_NUMBER
)
1560 h
->cupsRowCount
= (unsigned)obj
->value
.number
;
1561 else if (!strcmp(name
, "cupsRowFeed") && obj
->type
== CUPS_PS_NUMBER
)
1562 h
->cupsRowFeed
= (unsigned)obj
->value
.number
;
1563 else if (!strcmp(name
, "cupsRowStep") && obj
->type
== CUPS_PS_NUMBER
)
1564 h
->cupsRowStep
= (unsigned)obj
->value
.number
;
1565 else if (!strcmp(name
, "cupsBorderlessScalingFactor") &&
1566 obj
->type
== CUPS_PS_NUMBER
)
1567 h
->cupsBorderlessScalingFactor
= (float)obj
->value
.number
;
1568 else if (!strncmp(name
, "cupsInteger", 11) && obj
->type
== CUPS_PS_NUMBER
)
1570 if ((i
= atoi(name
+ 11)) < 0 || i
> 15)
1573 h
->cupsInteger
[i
] = (unsigned)obj
->value
.number
;
1575 else if (!strncmp(name
, "cupsReal", 8) && obj
->type
== CUPS_PS_NUMBER
)
1577 if ((i
= atoi(name
+ 8)) < 0 || i
> 15)
1580 h
->cupsReal
[i
] = (float)obj
->value
.number
;
1582 else if (!strncmp(name
, "cupsString", 10) && obj
->type
== CUPS_PS_STRING
)
1584 if ((i
= atoi(name
+ 10)) < 0 || i
> 15)
1587 strlcpy(h
->cupsString
[i
], obj
->value
.string
, sizeof(h
->cupsString
[i
]));
1589 else if (!strcmp(name
, "cupsMarkerType") && obj
->type
== CUPS_PS_STRING
)
1590 strlcpy(h
->cupsMarkerType
, obj
->value
.string
, sizeof(h
->cupsMarkerType
));
1591 else if (!strcmp(name
, "cupsPageSizeName") && obj
->type
== CUPS_PS_STRING
)
1592 strlcpy(h
->cupsPageSizeName
, obj
->value
.string
,
1593 sizeof(h
->cupsPageSizeName
));
1594 else if (!strcmp(name
, "cupsRenderingIntent") &&
1595 obj
->type
== CUPS_PS_STRING
)
1596 strlcpy(h
->cupsRenderingIntent
, obj
->value
.string
,
1597 sizeof(h
->cupsRenderingIntent
));
1601 * Ignore unknown name+value...
1604 DEBUG_printf(("4setpagedevice: Unknown name (\"%s\") or value...\n", name
));
1606 while (obj
[1].type
!= CUPS_PS_NAME
&& obj
< end
)
1617 * 'DEBUG_object()' - Print an object's value...
1621 DEBUG_object(const char *prefix
, /* I - Prefix string */
1622 _cups_ps_obj_t
*obj
) /* I - Object to print */
1627 DEBUG_printf(("4%s: /%s\n", prefix
, obj
->value
.name
));
1630 case CUPS_PS_NUMBER
:
1631 DEBUG_printf(("4%s: %g\n", prefix
, obj
->value
.number
));
1634 case CUPS_PS_STRING
:
1635 DEBUG_printf(("4%s: (%s)\n", prefix
, obj
->value
.string
));
1638 case CUPS_PS_BOOLEAN
:
1639 if (obj
->value
.boolean
)
1640 DEBUG_printf(("4%s: true", prefix
));
1642 DEBUG_printf(("4%s: false", prefix
));
1646 DEBUG_printf(("4%s: null", prefix
));
1649 case CUPS_PS_START_ARRAY
:
1650 DEBUG_printf(("4%s: [", prefix
));
1653 case CUPS_PS_END_ARRAY
:
1654 DEBUG_printf(("4%s: ]", prefix
));
1657 case CUPS_PS_START_DICT
:
1658 DEBUG_printf(("4%s: <<", prefix
));
1661 case CUPS_PS_END_DICT
:
1662 DEBUG_printf(("4%s: >>", prefix
));
1665 case CUPS_PS_START_PROC
:
1666 DEBUG_printf(("4%s: {", prefix
));
1669 case CUPS_PS_END_PROC
:
1670 DEBUG_printf(("4%s: }", prefix
));
1673 case CUPS_PS_CLEARTOMARK
:
1674 DEBUG_printf(("4%s: --cleartomark--", prefix
));
1678 DEBUG_printf(("4%s: --copy--", prefix
));
1682 DEBUG_printf(("4%s: --dup--", prefix
));
1685 case CUPS_PS_INDEX
:
1686 DEBUG_printf(("4%s: --index--", prefix
));
1690 DEBUG_printf(("4%s: --pop--", prefix
));
1694 DEBUG_printf(("4%s: --roll--", prefix
));
1697 case CUPS_PS_SETPAGEDEVICE
:
1698 DEBUG_printf(("4%s: --setpagedevice--", prefix
));
1701 case CUPS_PS_STOPPED
:
1702 DEBUG_printf(("4%s: --stopped--", prefix
));
1705 case CUPS_PS_OTHER
:
1706 DEBUG_printf(("4%s: --%s--", prefix
, obj
->value
.other
));
1713 * 'DEBUG_stack()' - Print a stack...
1717 DEBUG_stack(const char *prefix
, /* I - Prefix string */
1718 _cups_ps_stack_t
*st
) /* I - Stack */
1720 int c
; /* Looping var */
1721 _cups_ps_obj_t
*obj
; /* Current object on stack */
1724 for (obj
= st
->objs
, c
= st
->num_objs
; c
> 0; c
--, obj
++)
1725 DEBUG_object(prefix
, obj
);