]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/interpret.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / filter / interpret.c
1 /*
2 * "$Id: interpret.c 177 2006-06-21 00:20:03Z jlovell $"
3 *
4 * PPD command interpreter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2006 by Easy Software Products.
7 *
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
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header.
29 * exec_code() - Execute PostScript setpagedevice commands as
30 * appropriate.
31 */
32
33 /*
34 * Include necessary headers...
35 */
36
37 #include <cups/string.h>
38 #include "raster.h"
39 #include <stdlib.h>
40
41
42 /*
43 * Value types for PS code...
44 */
45
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 */
50
51
52 /*
53 * Local functions...
54 */
55
56 static int exec_code(cups_page_header2_t *header, int *preferred_bits,
57 const char *code);
58
59
60 /*
61 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
62 *
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.
67 *
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.
73 *
74 * @since CUPS 1.2@
75 */
76
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 */
84 {
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 */
96
97
98 /*
99 * Range check input...
100 */
101
102 if (!h)
103 return (-1);
104
105 /*
106 * Reset the page header to the defaults...
107 */
108
109 memset(h, 0, sizeof(cups_page_header2_t));
110
111 h->NumCopies = 1;
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;
126
127 strcpy(h->cupsPageSizeName, "Letter");
128
129 /*
130 * Apply patches and options to the page header...
131 */
132
133 status = 0;
134 preferred_bits = 0;
135
136 if (ppd)
137 {
138 /*
139 * Apply any patch code (used to override the defaults...)
140 */
141
142 if (ppd->patches)
143 status |= exec_code(h, &preferred_bits, ppd->patches);
144
145 /*
146 * Then apply printer options in the proper order...
147 */
148
149 if ((count = ppdCollect(ppd, PPD_ORDER_DOCUMENT, &choices)) > 0)
150 {
151 for (i = 0; i < count; i ++)
152 status |= exec_code(h, &preferred_bits, choices[i]->code);
153 }
154
155 if ((count = ppdCollect(ppd, PPD_ORDER_ANY, &choices)) > 0)
156 {
157 for (i = 0; i < count; i ++)
158 status |= exec_code(h, &preferred_bits, choices[i]->code);
159 }
160
161 if ((count = ppdCollect(ppd, PPD_ORDER_PROLOG, &choices)) > 0)
162 {
163 for (i = 0; i < count; i ++)
164 status |= exec_code(h, &preferred_bits, choices[i]->code);
165 }
166
167 if ((count = ppdCollect(ppd, PPD_ORDER_PAGE, &choices)) > 0)
168 {
169 for (i = 0; i < count; i ++)
170 status |= exec_code(h, &preferred_bits, choices[i]->code);
171 }
172 }
173
174 /*
175 * Allow option override for page scaling...
176 */
177
178 if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options,
179 options)) != NULL)
180 {
181 float sc = atof(val);
182
183 if (sc >= 0.9 && sc <= 1.1)
184 h->cupsBorderlessScalingFactor = sc;
185 }
186
187 /*
188 * Get the margins for the current size...
189 */
190
191 if ((size = ppdPageSize(ppd, NULL)) != NULL)
192 {
193 /*
194 * Use the margins from the PPD file...
195 */
196
197 left = size->left;
198 bottom = size->bottom;
199 right = size->right;
200 top = size->top;
201
202 strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName));
203 }
204 else
205 {
206 /*
207 * Use the default margins...
208 */
209
210 left = 0.0f;
211 bottom = 0.0f;
212 right = 612.0f;
213 top = 792.0f;
214 }
215
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;
230
231 /*
232 * Use the callback to validate the page header...
233 */
234
235 if (func && (*func)(h, preferred_bits))
236 return (-1);
237
238 /*
239 * Check parameters...
240 */
241
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)
249 return (-1);
250
251 /*
252 * Compute the bitmap parameters...
253 */
254
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);
259
260 switch (h->cupsColorSpace)
261 {
262 case CUPS_CSPACE_W :
263 case CUPS_CSPACE_K :
264 case CUPS_CSPACE_WHITE :
265 case CUPS_CSPACE_GOLD :
266 case CUPS_CSPACE_SILVER :
267 h->cupsNumColors = 1;
268 h->cupsBitsPerPixel = h->cupsBitsPerColor;
269 break;
270
271 default :
272 /*
273 * Ensure that colorimetric colorspaces use at least 8 bits per
274 * component...
275 */
276
277 if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ &&
278 h->cupsBitsPerColor < 8)
279 h->cupsBitsPerColor = 8;
280
281 /*
282 * Figure out the number of bits per pixel...
283 */
284
285 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
286 {
287 if (h->cupsBitsPerColor >= 8)
288 h->cupsBitsPerPixel = h->cupsBitsPerColor * 3;
289 else
290 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
291 }
292 else
293 h->cupsBitsPerPixel = h->cupsBitsPerColor;
294
295 h->cupsNumColors = 3;
296 break;
297
298 case CUPS_CSPACE_KCMYcm :
299 if (h->cupsBitsPerColor == 1)
300 {
301 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
302 h->cupsBitsPerPixel = 8;
303 else
304 h->cupsBitsPerPixel = 1;
305
306 h->cupsNumColors = 6;
307 break;
308 }
309
310 /*
311 * Fall through to CMYK code...
312 */
313
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;
323 else
324 h->cupsBitsPerPixel = h->cupsBitsPerColor;
325
326 h->cupsNumColors = 4;
327 break;
328 }
329
330 h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8;
331
332 if (h->cupsColorOrder == CUPS_ORDER_BANDED)
333 h->cupsBytesPerLine *= h->cupsNumColors;
334
335 return (status);
336 }
337
338
339 /*
340 * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate.
341 */
342
343 static int /* O - 0 on success, -1 on error */
344 exec_code(
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 */
348 {
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 */
354
355
356 /*
357 * Range check input...
358 */
359
360 if (!code || !h)
361 return (-1);
362
363 /*
364 * Parse the code string...
365 */
366
367 while (*code)
368 {
369 /*
370 * Search for the start of a dictionary name...
371 */
372
373 while (*code && *code != '/')
374 code ++;
375
376 if (!*code)
377 break;
378
379 /*
380 * Get the name...
381 */
382
383 code ++;
384 for (ptr = name; isalnum(*code & 255); code ++)
385 if (ptr < (name + sizeof(name) - 1))
386 *ptr++ = *code;
387 else
388 return (-1);
389
390 *ptr = '\0';
391
392 /*
393 * Then parse the value as needed...
394 */
395
396 while (isspace(*code & 255))
397 code ++;
398
399 if (!*code)
400 break;
401
402 if (*code == '[')
403 {
404 /*
405 * Read array of values...
406 */
407
408 type = CUPS_TYPE_ARRAY;
409
410 for (ptr = value; *code && *code != ']'; code ++)
411 if (ptr < (value + sizeof(value) - 1))
412 *ptr++ = *code;
413 else
414 return (-1);
415
416 if (*code == ']')
417 *ptr++ = *code++;
418
419 *ptr = '\0';
420 }
421 else if (*code == '(')
422 {
423 /*
424 * Read string value...
425 */
426
427 type = CUPS_TYPE_STRING;
428
429 for (ptr = value; *code && *code != ')'; code ++)
430 if (ptr < (value + sizeof(value) - 1))
431 *ptr++ = *code;
432 else
433 return (-1);
434
435 if (*code == ')')
436 *ptr++ = *code++;
437
438 *ptr = '\0';
439 }
440 else if (isdigit(*code & 255) || *code == '-' || *code == '.')
441 {
442 /*
443 * Read single number...
444 */
445
446 type = CUPS_TYPE_NUMBER;
447
448 for (ptr = value;
449 isdigit(*code & 255) || *code == '-' || *code == '.';
450 code ++)
451 if (ptr < (value + sizeof(value) - 1))
452 *ptr++ = *code;
453 else
454 return (-1);
455
456 *ptr = '\0';
457 }
458 else
459 {
460 /*
461 * Read a single name...
462 */
463
464 type = CUPS_TYPE_NAME;
465
466 for (ptr = value; isalnum(*code & 255) || *code == '_'; code ++)
467 if (ptr < (value + sizeof(value) - 1))
468 *ptr++ = *code;
469 else
470 return (-1);
471
472 *ptr = '\0';
473 }
474
475 /*
476 * Assign the value as needed...
477 */
478
479 if (!strcmp(name, "MediaClass") && type == CUPS_TYPE_STRING)
480 {
481 if (sscanf(value, "(%63[^)])", h->MediaClass) != 1)
482 return (-1);
483 }
484 else if (!strcmp(name, "MediaColor") && type == CUPS_TYPE_STRING)
485 {
486 if (sscanf(value, "(%63[^)])", h->MediaColor) != 1)
487 return (-1);
488 }
489 else if (!strcmp(name, "MediaType") && type == CUPS_TYPE_STRING)
490 {
491 if (sscanf(value, "(%63[^)])", h->MediaType) != 1)
492 return (-1);
493 }
494 else if (!strcmp(name, "OutputType") && type == CUPS_TYPE_STRING)
495 {
496 if (sscanf(value, "(%63[^)])", h->OutputType) != 1)
497 return (-1);
498 }
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)
510 {
511 if (sscanf(value, "[%d%d]", h->HWResolution + 0,
512 h->HWResolution + 1) != 2)
513 return (-1);
514 }
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)
537 {
538 if (sscanf(value, "[%f%f]", h->cupsPageSize + 0, h->cupsPageSize + 1) != 2)
539 return (-1);
540 }
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)
569 {
570 if ((i = atoi(name + 11)) >= 0 || i > 15)
571 return (-1);
572
573 h->cupsInteger[i] = atoi(value);
574 }
575 else if (!strncmp(name, "cupsReal", 8) && type == CUPS_TYPE_NUMBER)
576 {
577 if ((i = atoi(name + 8)) >= 0 || i > 15)
578 return (-1);
579
580 h->cupsReal[i] = atof(value);
581 }
582 else if (!strncmp(name, "cupsString", 10) && type == CUPS_TYPE_STRING)
583 {
584 if ((i = atoi(name + 10)) >= 0 || i > 15)
585 return (-1);
586
587 if (sscanf(value, "(%63[^)])", h->cupsString[i]) != 1)
588 return (-1);
589 }
590 else if (!strcmp(name, "cupsMarkerType") && type == CUPS_TYPE_STRING)
591 {
592 if (sscanf(value, "(%63[^)])", h->cupsMarkerType) != 1)
593 return (-1);
594 }
595 else if (!strcmp(name, "cupsRenderingIntent") && type == CUPS_TYPE_STRING)
596 {
597 if (sscanf(value, "(%63[^)])", h->cupsRenderingIntent) != 1)
598 return (-1);
599 }
600 }
601
602 /*
603 * Return success...
604 */
605
606 return (0);
607 }
608
609
610 /*
611 * End of "$Id: interpret.c 177 2006-06-21 00:20:03Z jlovell $".
612 */