2 * "$Id: interpret.c 5926 2006-09-05 20:45:47Z mike $"
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
));
204 h
->cupsPageSize
[0] = size
->width
;
205 h
->cupsPageSize
[1] = size
->length
;
210 * Use the default margins...
219 h
->PageSize
[0] = h
->cupsPageSize
[0] *
220 h
->cupsBorderlessScalingFactor
;
221 h
->PageSize
[1] = h
->cupsPageSize
[1] *
222 h
->cupsBorderlessScalingFactor
;
223 h
->Margins
[0] = left
* h
->cupsBorderlessScalingFactor
;
224 h
->Margins
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
225 h
->ImagingBoundingBox
[0] = left
* h
->cupsBorderlessScalingFactor
;
226 h
->ImagingBoundingBox
[1] = bottom
* h
->cupsBorderlessScalingFactor
;
227 h
->ImagingBoundingBox
[2] = right
* h
->cupsBorderlessScalingFactor
;
228 h
->ImagingBoundingBox
[3] = top
* h
->cupsBorderlessScalingFactor
;
229 h
->cupsImagingBBox
[0] = left
;
230 h
->cupsImagingBBox
[1] = bottom
;
231 h
->cupsImagingBBox
[2] = right
;
232 h
->cupsImagingBBox
[3] = top
;
235 * Use the callback to validate the page header...
238 if (func
&& (*func
)(h
, preferred_bits
))
242 * Check parameters...
245 if (!h
->HWResolution
[0] || !h
->HWResolution
[1] ||
246 !h
->PageSize
[0] || !h
->PageSize
[1] ||
247 (h
->cupsBitsPerColor
!= 1 && h
->cupsBitsPerColor
!= 2 &&
248 h
->cupsBitsPerColor
!= 4 && h
->cupsBitsPerColor
!= 8 &&
249 h
->cupsBitsPerColor
!= 16) ||
250 h
->cupsBorderlessScalingFactor
< 0.9 ||
251 h
->cupsBorderlessScalingFactor
> 1.1)
255 * Compute the bitmap parameters...
258 h
->cupsWidth
= (int)((right
- left
) * h
->cupsBorderlessScalingFactor
*
259 h
->HWResolution
[0] / 72.0f
+ 0.5f
);
260 h
->cupsHeight
= (int)((top
- bottom
) * h
->cupsBorderlessScalingFactor
*
261 h
->HWResolution
[1] / 72.0f
+ 0.5f
);
263 switch (h
->cupsColorSpace
)
267 case CUPS_CSPACE_WHITE
:
268 case CUPS_CSPACE_GOLD
:
269 case CUPS_CSPACE_SILVER
:
270 h
->cupsNumColors
= 1;
271 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
276 * Ensure that colorimetric colorspaces use at least 8 bits per
280 if (h
->cupsColorSpace
>= CUPS_CSPACE_CIEXYZ
&&
281 h
->cupsBitsPerColor
< 8)
282 h
->cupsBitsPerColor
= 8;
285 * Figure out the number of bits per pixel...
288 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
290 if (h
->cupsBitsPerColor
>= 8)
291 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 3;
293 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
296 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
298 h
->cupsNumColors
= 3;
301 case CUPS_CSPACE_KCMYcm
:
302 if (h
->cupsBitsPerColor
== 1)
304 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
305 h
->cupsBitsPerPixel
= 8;
307 h
->cupsBitsPerPixel
= 1;
309 h
->cupsNumColors
= 6;
314 * Fall through to CMYK code...
317 case CUPS_CSPACE_RGBA
:
318 case CUPS_CSPACE_RGBW
:
319 case CUPS_CSPACE_CMYK
:
320 case CUPS_CSPACE_YMCK
:
321 case CUPS_CSPACE_KCMY
:
322 case CUPS_CSPACE_GMCK
:
323 case CUPS_CSPACE_GMCS
:
324 if (h
->cupsColorOrder
== CUPS_ORDER_CHUNKED
)
325 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
* 4;
327 h
->cupsBitsPerPixel
= h
->cupsBitsPerColor
;
329 h
->cupsNumColors
= 4;
333 h
->cupsBytesPerLine
= (h
->cupsBitsPerPixel
* h
->cupsWidth
+ 7) / 8;
335 if (h
->cupsColorOrder
== CUPS_ORDER_BANDED
)
336 h
->cupsBytesPerLine
*= h
->cupsNumColors
;
343 * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate.
346 static int /* O - 0 on success, -1 on error */
348 cups_page_header2_t
*h
, /* O - Page header */
349 int *preferred_bits
,/* O - Preferred bits per color */
350 const char *code
) /* I - Option choice to execute */
352 int i
; /* Index into array */
353 int type
; /* Type of value */
354 char *ptr
, /* Pointer into name/value string */
355 name
[255], /* Name of pagedevice entry */
356 value
[1024]; /* Value of pagedevice entry */
360 * Range check input...
367 * Parse the code string...
373 * Search for the start of a dictionary name...
376 while (*code
&& *code
!= '/')
387 for (ptr
= name
; isalnum(*code
& 255); code
++)
388 if (ptr
< (name
+ sizeof(name
) - 1))
396 * Then parse the value as needed...
399 while (isspace(*code
& 255))
408 * Read array of values...
411 type
= CUPS_TYPE_ARRAY
;
413 for (ptr
= value
; *code
&& *code
!= ']'; code
++)
414 if (ptr
< (value
+ sizeof(value
) - 1))
424 else if (*code
== '(')
427 * Read string value...
430 type
= CUPS_TYPE_STRING
;
432 for (ptr
= value
; *code
&& *code
!= ')'; code
++)
433 if (ptr
< (value
+ sizeof(value
) - 1))
443 else if (isdigit(*code
& 255) || *code
== '-' || *code
== '.')
446 * Read single number...
449 type
= CUPS_TYPE_NUMBER
;
452 isdigit(*code
& 255) || *code
== '-' || *code
== '.';
454 if (ptr
< (value
+ sizeof(value
) - 1))
464 * Read a single name...
467 type
= CUPS_TYPE_NAME
;
469 for (ptr
= value
; isalnum(*code
& 255) || *code
== '_'; code
++)
470 if (ptr
< (value
+ sizeof(value
) - 1))
479 * Assign the value as needed...
482 if (!strcmp(name
, "MediaClass") && type
== CUPS_TYPE_STRING
)
484 if (sscanf(value
, "(%63[^)])", h
->MediaClass
) != 1)
487 else if (!strcmp(name
, "MediaColor") && type
== CUPS_TYPE_STRING
)
489 if (sscanf(value
, "(%63[^)])", h
->MediaColor
) != 1)
492 else if (!strcmp(name
, "MediaType") && type
== CUPS_TYPE_STRING
)
494 if (sscanf(value
, "(%63[^)])", h
->MediaType
) != 1)
497 else if (!strcmp(name
, "OutputType") && type
== CUPS_TYPE_STRING
)
499 if (sscanf(value
, "(%63[^)])", h
->OutputType
) != 1)
502 else if (!strcmp(name
, "AdvanceDistance") && type
== CUPS_TYPE_NUMBER
)
503 h
->AdvanceDistance
= atoi(value
);
504 else if (!strcmp(name
, "AdvanceMedia") && type
== CUPS_TYPE_NUMBER
)
505 h
->AdvanceMedia
= atoi(value
);
506 else if (!strcmp(name
, "Collate") && type
== CUPS_TYPE_NAME
)
507 h
->Collate
= !strcmp(value
, "true");
508 else if (!strcmp(name
, "CutMedia") && type
== CUPS_TYPE_NUMBER
)
509 h
->CutMedia
= (cups_cut_t
)atoi(value
);
510 else if (!strcmp(name
, "Duplex") && type
== CUPS_TYPE_NAME
)
511 h
->Duplex
= !strcmp(value
, "true");
512 else if (!strcmp(name
, "HWResolution") && type
== CUPS_TYPE_ARRAY
)
514 if (sscanf(value
, "[%d%d]", h
->HWResolution
+ 0,
515 h
->HWResolution
+ 1) != 2)
518 else if (!strcmp(name
, "InsertSheet") && type
== CUPS_TYPE_NAME
)
519 h
->InsertSheet
= !strcmp(value
, "true");
520 else if (!strcmp(name
, "Jog") && type
== CUPS_TYPE_NUMBER
)
521 h
->Jog
= atoi(value
);
522 else if (!strcmp(name
, "LeadingEdge") && type
== CUPS_TYPE_NUMBER
)
523 h
->LeadingEdge
= atoi(value
);
524 else if (!strcmp(name
, "ManualFeed") && type
== CUPS_TYPE_NAME
)
525 h
->ManualFeed
= !strcmp(value
, "true");
526 else if ((!strcmp(name
, "cupsMediaPosition") || /* Compatibility */
527 !strcmp(name
, "MediaPosition")) && type
== CUPS_TYPE_NUMBER
)
528 h
->MediaPosition
= atoi(value
);
529 else if (!strcmp(name
, "MediaWeight") && type
== CUPS_TYPE_NUMBER
)
530 h
->MediaWeight
= atoi(value
);
531 else if (!strcmp(name
, "MirrorPrint") && type
== CUPS_TYPE_NAME
)
532 h
->MirrorPrint
= !strcmp(value
, "true");
533 else if (!strcmp(name
, "NegativePrint") && type
== CUPS_TYPE_NAME
)
534 h
->NegativePrint
= !strcmp(value
, "true");
535 else if (!strcmp(name
, "Orientation") && type
== CUPS_TYPE_NUMBER
)
536 h
->Orientation
= atoi(value
);
537 else if (!strcmp(name
, "OutputFaceUp") && type
== CUPS_TYPE_NAME
)
538 h
->OutputFaceUp
= !strcmp(value
, "true");
539 else if (!strcmp(name
, "PageSize") && type
== CUPS_TYPE_ARRAY
)
541 if (sscanf(value
, "[%f%f]", h
->cupsPageSize
+ 0, h
->cupsPageSize
+ 1) != 2)
544 else if (!strcmp(name
, "Separations") && type
== CUPS_TYPE_NAME
)
545 h
->Separations
= !strcmp(value
, "true");
546 else if (!strcmp(name
, "TraySwitch") && type
== CUPS_TYPE_NAME
)
547 h
->TraySwitch
= !strcmp(value
, "true");
548 else if (!strcmp(name
, "Tumble") && type
== CUPS_TYPE_NAME
)
549 h
->Tumble
= !strcmp(value
, "true");
550 else if (!strcmp(name
, "cupsMediaType") && type
== CUPS_TYPE_NUMBER
)
551 h
->cupsMediaType
= atoi(value
);
552 else if (!strcmp(name
, "cupsBitsPerColor") && type
== CUPS_TYPE_NUMBER
)
553 h
->cupsBitsPerColor
= atoi(value
);
554 else if (!strcmp(name
, "cupsPreferredBitsPerColor") && type
== CUPS_TYPE_NUMBER
)
555 *preferred_bits
= atoi(value
);
556 else if (!strcmp(name
, "cupsColorOrder") && type
== CUPS_TYPE_NUMBER
)
557 h
->cupsColorOrder
= (cups_order_t
)atoi(value
);
558 else if (!strcmp(name
, "cupsColorSpace") && type
== CUPS_TYPE_NUMBER
)
559 h
->cupsColorSpace
= (cups_cspace_t
)atoi(value
);
560 else if (!strcmp(name
, "cupsCompression") && type
== CUPS_TYPE_NUMBER
)
561 h
->cupsCompression
= atoi(value
);
562 else if (!strcmp(name
, "cupsRowCount") && type
== CUPS_TYPE_NUMBER
)
563 h
->cupsRowCount
= atoi(value
);
564 else if (!strcmp(name
, "cupsRowFeed") && type
== CUPS_TYPE_NUMBER
)
565 h
->cupsRowFeed
= atoi(value
);
566 else if (!strcmp(name
, "cupsRowStep") && type
== CUPS_TYPE_NUMBER
)
567 h
->cupsRowStep
= atoi(value
);
568 else if (!strcmp(name
, "cupsBorderlessScalingFactor") &&
569 type
== CUPS_TYPE_NUMBER
)
570 h
->cupsBorderlessScalingFactor
= atof(value
);
571 else if (!strncmp(name
, "cupsInteger", 11) && type
== CUPS_TYPE_NUMBER
)
573 if ((i
= atoi(name
+ 11)) >= 0 || i
> 15)
576 h
->cupsInteger
[i
] = atoi(value
);
578 else if (!strncmp(name
, "cupsReal", 8) && type
== CUPS_TYPE_NUMBER
)
580 if ((i
= atoi(name
+ 8)) >= 0 || i
> 15)
583 h
->cupsReal
[i
] = atof(value
);
585 else if (!strncmp(name
, "cupsString", 10) && type
== CUPS_TYPE_STRING
)
587 if ((i
= atoi(name
+ 10)) >= 0 || i
> 15)
590 if (sscanf(value
, "(%63[^)])", h
->cupsString
[i
]) != 1)
593 else if (!strcmp(name
, "cupsMarkerType") && type
== CUPS_TYPE_STRING
)
595 if (sscanf(value
, "(%63[^)])", h
->cupsMarkerType
) != 1)
598 else if (!strcmp(name
, "cupsRenderingIntent") && type
== CUPS_TYPE_STRING
)
600 if (sscanf(value
, "(%63[^)])", h
->cupsRenderingIntent
) != 1)
614 * End of "$Id: interpret.c 5926 2006-09-05 20:45:47Z mike $".