2 * "$Id: interpret.c 177 2006-06-21 00:20:03Z jlovell $"
4 * PPD command interpreter for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-2006 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 * exec_code() - Execute PostScript setpagedevice commands as
34 * Include necessary headers...
37 #include <cups/string.h>
43 * Value types for PS code...
46 #define CUPS_TYPE_NUMBER 0 /* Integer or real number */
47 #define CUPS_TYPE_NAME 1 /* Name */
48 #define CUPS_TYPE_STRING 2 /* String */
49 #define CUPS_TYPE_ARRAY 3 /* Array of integers */
56 static int exec_code(cups_page_header2_t
*header
, int *preferred_bits
,
61 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
63 * This function does not mark the options in the PPD using the "num_options"
64 * and "options" arguments. Instead, mark the options prior to calling
65 * cupsRasterInterpretPPD() - this allows you to do per-page options
66 * without manipulating the options array.
68 * The "func" argument specifies an optional callback function that is
69 * called prior to the computation of the final raster data. The function
70 * can make changes to the cups_page_header2_t data as needed to use a
71 * supported raster format and then returns 0 on success and -1 if the
72 * requested attributes cannot be supported.
77 int /* O - 0 on success, -1 on failure */
78 cupsRasterInterpretPPD(
79 cups_page_header2_t
*h
, /* O - Page header */
80 ppd_file_t
*ppd
, /* I - PPD file */
81 int num_options
, /* I - Number of options */
82 cups_option_t
*options
, /* I - Options */
83 cups_interpret_cb_t func
) /* I - Optional page header callback */
85 int i
; /* Looping var */
86 int status
; /* Cummulative status */
87 int count
; /* Number of marked choices */
88 const char *val
; /* Option value */
89 ppd_choice_t
**choices
; /* List of marked choices */
90 ppd_size_t
*size
; /* Current size */
91 float left
, /* Left position */
92 bottom
, /* Bottom position */
93 right
, /* Right position */
94 top
; /* Top position */
95 int preferred_bits
; /* Preferred bits per color */
99 * Range check input...
106 * Reset the page header to the defaults...
109 memset(h
, 0, sizeof(cups_page_header2_t
));
112 h
->PageSize
[0] = 612;
113 h
->PageSize
[1] = 792;
114 h
->HWResolution
[0] = 100;
115 h
->HWResolution
[1] = 100;
116 h
->cupsBitsPerColor
= 1;
117 h
->cupsColorOrder
= CUPS_ORDER_CHUNKED
;
118 h
->cupsColorSpace
= CUPS_CSPACE_K
;
119 h
->cupsBorderlessScalingFactor
= 1.0f
;
120 h
->cupsPageSize
[0] = 612.0f
;
121 h
->cupsPageSize
[1] = 792.0f
;
122 h
->cupsImagingBBox
[0] = 0.0f
;
123 h
->cupsImagingBBox
[1] = 0.0f
;
124 h
->cupsImagingBBox
[2] = 612.0f
;
125 h
->cupsImagingBBox
[3] = 792.0f
;
127 strcpy(h
->cupsPageSizeName
, "Letter");
130 * Apply patches and options to the page header...
139 * Apply any patch code (used to override the defaults...)
143 status
|= exec_code(h
, &preferred_bits
, ppd
->patches
);
146 * Then apply printer options in the proper order...
149 if ((count
= ppdCollect(ppd
, PPD_ORDER_DOCUMENT
, &choices
)) > 0)
151 for (i
= 0; i
< count
; i
++)
152 status
|= exec_code(h
, &preferred_bits
, choices
[i
]->code
);
155 if ((count
= ppdCollect(ppd
, PPD_ORDER_ANY
, &choices
)) > 0)
157 for (i
= 0; i
< count
; i
++)
158 status
|= exec_code(h
, &preferred_bits
, choices
[i
]->code
);
161 if ((count
= ppdCollect(ppd
, PPD_ORDER_PROLOG
, &choices
)) > 0)
163 for (i
= 0; i
< count
; i
++)
164 status
|= exec_code(h
, &preferred_bits
, choices
[i
]->code
);
167 if ((count
= ppdCollect(ppd
, PPD_ORDER_PAGE
, &choices
)) > 0)
169 for (i
= 0; i
< count
; i
++)
170 status
|= exec_code(h
, &preferred_bits
, choices
[i
]->code
);
175 * Allow option override for page scaling...
178 if ((val
= cupsGetOption("cupsBorderlessScalingFactor", num_options
,
181 float sc
= atof(val
);
183 if (sc
>= 0.9 && sc
<= 1.1)
184 h
->cupsBorderlessScalingFactor
= sc
;
188 * Get the margins for the current size...
191 if ((size
= ppdPageSize(ppd
, NULL
)) != NULL
)
194 * Use the margins from the PPD file...
198 bottom
= size
->bottom
;
202 strlcpy(h
->cupsPageSizeName
, size
->name
, sizeof(h
->cupsPageSizeName
));
207 * Use the default margins...
216 h
->PageSize
[0] = h
->cupsPageSize
[0] *
217 h
->cupsBorderlessScalingFactor
;
218 h
->PageSize
[1] = h
->cupsPageSize
[1] *
219 h
->cupsBorderlessScalingFactor
;
220 h
->Margins
[0] = left
* h
->cupsBorderlessScalingFactor
;
221 h
->Margins
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
222 h
->ImagingBoundingBox
[0] = left
* h
->cupsBorderlessScalingFactor
;
223 h
->ImagingBoundingBox
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
224 h
->ImagingBoundingBox
[2] = right
* h
->cupsBorderlessScalingFactor
;
225 h
->ImagingBoundingBox
[3] = top
* h
->cupsBorderlessScalingFactor
;
226 h
->cupsImagingBBox
[0] = left
;
227 h
->cupsImagingBBox
[1] = bottom
;
228 h
->cupsImagingBBox
[2] = right
;
229 h
->cupsImagingBBox
[3] = top
;
232 * Use the callback to validate the page header...
235 if (func
&& (*func
)(h
, preferred_bits
))
239 * Check parameters...
242 if (!h
->HWResolution
[0] || !h
->HWResolution
[1] ||
243 !h
->PageSize
[0] || !h
->PageSize
[1] ||
244 (h
->cupsBitsPerColor
!= 1 && h
->cupsBitsPerColor
!= 2 &&
245 h
->cupsBitsPerColor
!= 4 && h
->cupsBitsPerColor
!= 8 &&
246 h
->cupsBitsPerColor
!= 16) ||
247 h
->cupsBorderlessScalingFactor
< 0.9 ||
248 h
->cupsBorderlessScalingFactor
> 1.1)
252 * Compute the bitmap parameters...
255 h
->cupsWidth
= (int)((right
- left
) * h
->cupsBorderlessScalingFactor
*
256 h
->HWResolution
[0] / 72.0f
+ 0.5f
);
257 h
->cupsHeight
= (int)((top
- bottom
) * h
->cupsBorderlessScalingFactor
*
258 h
->HWResolution
[1] / 72.0f
+ 0.5f
);
260 switch (h
->cupsColorSpace
)
264 case CUPS_CSPACE_WHITE
:
265 case CUPS_CSPACE_GOLD
:
266 case CUPS_CSPACE_SILVER
:
267 h
->cupsNumColors
= 1;
268 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
273 * Ensure that colorimetric colorspaces use at least 8 bits per
277 if (h
->cupsColorSpace
>= CUPS_CSPACE_CIEXYZ
&&
278 h
->cupsBitsPerColor
< 8)
279 h
->cupsBitsPerColor
= 8;
282 * Figure out the number of bits per pixel...
285 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
287 if (h
->cupsBitsPerColor
>= 8)
288 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 3;
290 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
293 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
295 h
->cupsNumColors
= 3;
298 case CUPS_CSPACE_KCMYcm
:
299 if (h
->cupsBitsPerColor
== 1)
301 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
302 h
->cupsBitsPerPixel
= 8;
304 h
->cupsBitsPerPixel
= 1;
306 h
->cupsNumColors
= 6;
311 * Fall through to CMYK code...
314 case CUPS_CSPACE_RGBA
:
315 case CUPS_CSPACE_RGBW
:
316 case CUPS_CSPACE_CMYK
:
317 case CUPS_CSPACE_YMCK
:
318 case CUPS_CSPACE_KCMY
:
319 case CUPS_CSPACE_GMCK
:
320 case CUPS_CSPACE_GMCS
:
321 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
322 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
324 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
326 h
->cupsNumColors
= 4;
330 h
->cupsBytesPerLine
= (h
->cupsBitsPerPixel
* h
->cupsWidth
+ 7) / 8;
332 if (h
->cupsColorOrder
== CUPS_ORDER_BANDED
)
333 h
->cupsBytesPerLine
*= h
->cupsNumColors
;
340 * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate.
343 static int /* O - 0 on success, -1 on error */
345 cups_page_header2_t
*h
, /* O - Page header */
346 int *preferred_bits
,/* O - Preferred bits per color */
347 const char *code
) /* I - Option choice to execute */
349 int i
; /* Index into array */
350 int type
; /* Type of value */
351 char *ptr
, /* Pointer into name/value string */
352 name
[255], /* Name of pagedevice entry */
353 value
[1024]; /* Value of pagedevice entry */
357 * Range check input...
364 * Parse the code string...
370 * Search for the start of a dictionary name...
373 while (*code
&& *code
!= '/')
384 for (ptr
= name
; isalnum(*code
& 255); code
++)
385 if (ptr
< (name
+ sizeof(name
) - 1))
393 * Then parse the value as needed...
396 while (isspace(*code
& 255))
405 * Read array of values...
408 type
= CUPS_TYPE_ARRAY
;
410 for (ptr
= value
; *code
&& *code
!= ']'; code
++)
411 if (ptr
< (value
+ sizeof(value
) - 1))
421 else if (*code
== '(')
424 * Read string value...
427 type
= CUPS_TYPE_STRING
;
429 for (ptr
= value
; *code
&& *code
!= ')'; code
++)
430 if (ptr
< (value
+ sizeof(value
) - 1))
440 else if (isdigit(*code
& 255) || *code
== '-' || *code
== '.')
443 * Read single number...
446 type
= CUPS_TYPE_NUMBER
;
449 isdigit(*code
& 255) || *code
== '-' || *code
== '.';
451 if (ptr
< (value
+ sizeof(value
) - 1))
461 * Read a single name...
464 type
= CUPS_TYPE_NAME
;
466 for (ptr
= value
; isalnum(*code
& 255) || *code
== '_'; code
++)
467 if (ptr
< (value
+ sizeof(value
) - 1))
476 * Assign the value as needed...
479 if (!strcmp(name
, "MediaClass") && type
== CUPS_TYPE_STRING
)
481 if (sscanf(value
, "(%63[^)])", h
->MediaClass
) != 1)
484 else if (!strcmp(name
, "MediaColor") && type
== CUPS_TYPE_STRING
)
486 if (sscanf(value
, "(%63[^)])", h
->MediaColor
) != 1)
489 else if (!strcmp(name
, "MediaType") && type
== CUPS_TYPE_STRING
)
491 if (sscanf(value
, "(%63[^)])", h
->MediaType
) != 1)
494 else if (!strcmp(name
, "OutputType") && type
== CUPS_TYPE_STRING
)
496 if (sscanf(value
, "(%63[^)])", h
->OutputType
) != 1)
499 else if (!strcmp(name
, "AdvanceDistance") && type
== CUPS_TYPE_NUMBER
)
500 h
->AdvanceDistance
= atoi(value
);
501 else if (!strcmp(name
, "AdvanceMedia") && type
== CUPS_TYPE_NUMBER
)
502 h
->AdvanceMedia
= atoi(value
);
503 else if (!strcmp(name
, "Collate") && type
== CUPS_TYPE_NAME
)
504 h
->Collate
= !strcmp(value
, "true");
505 else if (!strcmp(name
, "CutMedia") && type
== CUPS_TYPE_NUMBER
)
506 h
->CutMedia
= (cups_cut_t
)atoi(value
);
507 else if (!strcmp(name
, "Duplex") && type
== CUPS_TYPE_NAME
)
508 h
->Duplex
= !strcmp(value
, "true");
509 else if (!strcmp(name
, "HWResolution") && type
== CUPS_TYPE_ARRAY
)
511 if (sscanf(value
, "[%d%d]", h
->HWResolution
+ 0,
512 h
->HWResolution
+ 1) != 2)
515 else if (!strcmp(name
, "InsertSheet") && type
== CUPS_TYPE_NAME
)
516 h
->InsertSheet
= !strcmp(value
, "true");
517 else if (!strcmp(name
, "Jog") && type
== CUPS_TYPE_NUMBER
)
518 h
->Jog
= atoi(value
);
519 else if (!strcmp(name
, "LeadingEdge") && type
== CUPS_TYPE_NUMBER
)
520 h
->LeadingEdge
= atoi(value
);
521 else if (!strcmp(name
, "ManualFeed") && type
== CUPS_TYPE_NAME
)
522 h
->ManualFeed
= !strcmp(value
, "true");
523 else if ((!strcmp(name
, "cupsMediaPosition") || /* Compatibility */
524 !strcmp(name
, "MediaPosition")) && type
== CUPS_TYPE_NUMBER
)
525 h
->MediaPosition
= atoi(value
);
526 else if (!strcmp(name
, "MediaWeight") && type
== CUPS_TYPE_NUMBER
)
527 h
->MediaWeight
= atoi(value
);
528 else if (!strcmp(name
, "MirrorPrint") && type
== CUPS_TYPE_NAME
)
529 h
->MirrorPrint
= !strcmp(value
, "true");
530 else if (!strcmp(name
, "NegativePrint") && type
== CUPS_TYPE_NAME
)
531 h
->NegativePrint
= !strcmp(value
, "true");
532 else if (!strcmp(name
, "Orientation") && type
== CUPS_TYPE_NUMBER
)
533 h
->Orientation
= atoi(value
);
534 else if (!strcmp(name
, "OutputFaceUp") && type
== CUPS_TYPE_NAME
)
535 h
->OutputFaceUp
= !strcmp(value
, "true");
536 else if (!strcmp(name
, "PageSize") && type
== CUPS_TYPE_ARRAY
)
538 if (sscanf(value
, "[%f%f]", h
->cupsPageSize
+ 0, h
->cupsPageSize
+ 1) != 2)
541 else if (!strcmp(name
, "Separations") && type
== CUPS_TYPE_NAME
)
542 h
->Separations
= !strcmp(value
, "true");
543 else if (!strcmp(name
, "TraySwitch") && type
== CUPS_TYPE_NAME
)
544 h
->TraySwitch
= !strcmp(value
, "true");
545 else if (!strcmp(name
, "Tumble") && type
== CUPS_TYPE_NAME
)
546 h
->Tumble
= !strcmp(value
, "true");
547 else if (!strcmp(name
, "cupsMediaType") && type
== CUPS_TYPE_NUMBER
)
548 h
->cupsMediaType
= atoi(value
);
549 else if (!strcmp(name
, "cupsBitsPerColor") && type
== CUPS_TYPE_NUMBER
)
550 h
->cupsBitsPerColor
= atoi(value
);
551 else if (!strcmp(name
, "cupsPreferredBitsPerColor") && type
== CUPS_TYPE_NUMBER
)
552 *preferred_bits
= atoi(value
);
553 else if (!strcmp(name
, "cupsColorOrder") && type
== CUPS_TYPE_NUMBER
)
554 h
->cupsColorOrder
= (cups_order_t
)atoi(value
);
555 else if (!strcmp(name
, "cupsColorSpace") && type
== CUPS_TYPE_NUMBER
)
556 h
->cupsColorSpace
= (cups_cspace_t
)atoi(value
);
557 else if (!strcmp(name
, "cupsCompression") && type
== CUPS_TYPE_NUMBER
)
558 h
->cupsCompression
= atoi(value
);
559 else if (!strcmp(name
, "cupsRowCount") && type
== CUPS_TYPE_NUMBER
)
560 h
->cupsRowCount
= atoi(value
);
561 else if (!strcmp(name
, "cupsRowFeed") && type
== CUPS_TYPE_NUMBER
)
562 h
->cupsRowFeed
= atoi(value
);
563 else if (!strcmp(name
, "cupsRowStep") && type
== CUPS_TYPE_NUMBER
)
564 h
->cupsRowStep
= atoi(value
);
565 else if (!strcmp(name
, "cupsBorderlessScalingFactor") &&
566 type
== CUPS_TYPE_NUMBER
)
567 h
->cupsBorderlessScalingFactor
= atof(value
);
568 else if (!strncmp(name
, "cupsInteger", 11) && type
== CUPS_TYPE_NUMBER
)
570 if ((i
= atoi(name
+ 11)) >= 0 || i
> 15)
573 h
->cupsInteger
[i
] = atoi(value
);
575 else if (!strncmp(name
, "cupsReal", 8) && type
== CUPS_TYPE_NUMBER
)
577 if ((i
= atoi(name
+ 8)) >= 0 || i
> 15)
580 h
->cupsReal
[i
] = atof(value
);
582 else if (!strncmp(name
, "cupsString", 10) && type
== CUPS_TYPE_STRING
)
584 if ((i
= atoi(name
+ 10)) >= 0 || i
> 15)
587 if (sscanf(value
, "(%63[^)])", h
->cupsString
[i
]) != 1)
590 else if (!strcmp(name
, "cupsMarkerType") && type
== CUPS_TYPE_STRING
)
592 if (sscanf(value
, "(%63[^)])", h
->cupsMarkerType
) != 1)
595 else if (!strcmp(name
, "cupsRenderingIntent") && type
== CUPS_TYPE_STRING
)
597 if (sscanf(value
, "(%63[^)])", h
->cupsRenderingIntent
) != 1)
611 * End of "$Id: interpret.c 177 2006-06-21 00:20:03Z jlovell $".