]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/interpret.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / interpret.c
CommitLineData
ef416fc2 1/*
07725fee 2 * "$Id: interpret.c 5926 2006-09-05 20:45:47Z mike $"
ef416fc2 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
ef416fc2 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
a74454a7 56static int exec_code(cups_page_header2_t *header, int *preferred_bits,
57 const char *code);
ef416fc2 58
59
60/*
61 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
62 *
923edb68 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 *
a74454a7 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 *
ef416fc2 74 * @since CUPS 1.2@
75 */
76
77int /* O - 0 on success, -1 on failure */
78cupsRasterInterpretPPD(
79 cups_page_header2_t *h, /* O - Page header */
923edb68 80 ppd_file_t *ppd, /* I - PPD file */
81 int num_options, /* I - Number of options */
a74454a7 82 cups_option_t *options, /* I - Options */
83 cups_interpret_cb_t func) /* I - Optional page header callback */
ef416fc2 84{
85 int i; /* Looping var */
86 int status; /* Cummulative status */
87 int count; /* Number of marked choices */
923edb68 88 const char *val; /* Option value */
ef416fc2 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 */
a74454a7 95 int preferred_bits; /* Preferred bits per color */
ef416fc2 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
923edb68 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;
fa73b229 126
127 strcpy(h->cupsPageSizeName, "Letter");
ef416fc2 128
129 /*
130 * Apply patches and options to the page header...
131 */
132
a74454a7 133 status = 0;
134 preferred_bits = 0;
ef416fc2 135
136 if (ppd)
137 {
138 /*
139 * Apply any patch code (used to override the defaults...)
140 */
141
142 if (ppd->patches)
a74454a7 143 status |= exec_code(h, &preferred_bits, ppd->patches);
ef416fc2 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 ++)
a74454a7 152 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 153 }
154
155 if ((count = ppdCollect(ppd, PPD_ORDER_ANY, &choices)) > 0)
156 {
157 for (i = 0; i < count; i ++)
a74454a7 158 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 159 }
160
161 if ((count = ppdCollect(ppd, PPD_ORDER_PROLOG, &choices)) > 0)
162 {
163 for (i = 0; i < count; i ++)
a74454a7 164 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 165 }
166
167 if ((count = ppdCollect(ppd, PPD_ORDER_PAGE, &choices)) > 0)
168 {
169 for (i = 0; i < count; i ++)
a74454a7 170 status |= exec_code(h, &preferred_bits, choices[i]->code);
ef416fc2 171 }
172 }
173
923edb68 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
ef416fc2 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;
fa73b229 201
202 strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName));
07725fee 203
204 h->cupsPageSize[0] = size->width;
205 h->cupsPageSize[1] = size->length;
ef416fc2 206 }
207 else
208 {
209 /*
210 * Use the default margins...
211 */
212
213 left = 0.0f;
214 bottom = 0.0f;
215 right = 612.0f;
216 top = 792.0f;
217 }
218
923edb68 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;
fa73b229 229 h->cupsImagingBBox[0] = left;
230 h->cupsImagingBBox[1] = bottom;
231 h->cupsImagingBBox[2] = right;
232 h->cupsImagingBBox[3] = top;
ef416fc2 233
a74454a7 234 /*
235 * Use the callback to validate the page header...
236 */
237
238 if (func && (*func)(h, preferred_bits))
239 return (-1);
240
a9252913 241 /*
242 * Check parameters...
243 */
244
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)
252 return (-1);
253
ef416fc2 254 /*
255 * Compute the bitmap parameters...
256 */
257
923edb68 258 h->cupsWidth = (int)((right - left) * h->cupsBorderlessScalingFactor *
fa73b229 259 h->HWResolution[0] / 72.0f + 0.5f);
923edb68 260 h->cupsHeight = (int)((top - bottom) * h->cupsBorderlessScalingFactor *
fa73b229 261 h->HWResolution[1] / 72.0f + 0.5f);
ef416fc2 262
263 switch (h->cupsColorSpace)
264 {
265 case CUPS_CSPACE_W :
266 case CUPS_CSPACE_K :
267 case CUPS_CSPACE_WHITE :
268 case CUPS_CSPACE_GOLD :
269 case CUPS_CSPACE_SILVER :
270 h->cupsNumColors = 1;
271 h->cupsBitsPerPixel = h->cupsBitsPerColor;
272 break;
273
274 default :
275 /*
276 * Ensure that colorimetric colorspaces use at least 8 bits per
277 * component...
278 */
279
280 if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ &&
281 h->cupsBitsPerColor < 8)
282 h->cupsBitsPerColor = 8;
283
284 /*
285 * Figure out the number of bits per pixel...
286 */
287
288 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
289 {
290 if (h->cupsBitsPerColor >= 8)
291 h->cupsBitsPerPixel = h->cupsBitsPerColor * 3;
292 else
293 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
294 }
295 else
296 h->cupsBitsPerPixel = h->cupsBitsPerColor;
297
298 h->cupsNumColors = 3;
299 break;
300
301 case CUPS_CSPACE_KCMYcm :
f301802f 302 if (h->cupsBitsPerColor == 1)
ef416fc2 303 {
304 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
305 h->cupsBitsPerPixel = 8;
306 else
307 h->cupsBitsPerPixel = 1;
308
309 h->cupsNumColors = 6;
310 break;
311 }
312
313 /*
314 * Fall through to CMYK code...
315 */
316
317 case CUPS_CSPACE_RGBA :
a74454a7 318 case CUPS_CSPACE_RGBW :
ef416fc2 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;
326 else
327 h->cupsBitsPerPixel = h->cupsBitsPerColor;
328
329 h->cupsNumColors = 4;
330 break;
331 }
332
333 h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8;
334
335 if (h->cupsColorOrder == CUPS_ORDER_BANDED)
336 h->cupsBytesPerLine *= h->cupsNumColors;
337
338 return (status);
339}
340
341
342/*
343 * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate.
344 */
345
346static int /* O - 0 on success, -1 on error */
a74454a7 347exec_code(
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 */
ef416fc2 351{
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 */
357
358
359 /*
360 * Range check input...
361 */
362
363 if (!code || !h)
364 return (-1);
365
366 /*
367 * Parse the code string...
368 */
369
370 while (*code)
371 {
372 /*
373 * Search for the start of a dictionary name...
374 */
375
376 while (*code && *code != '/')
377 code ++;
378
379 if (!*code)
380 break;
381
382 /*
383 * Get the name...
384 */
385
386 code ++;
387 for (ptr = name; isalnum(*code & 255); code ++)
388 if (ptr < (name + sizeof(name) - 1))
389 *ptr++ = *code;
390 else
391 return (-1);
392
393 *ptr = '\0';
394
395 /*
396 * Then parse the value as needed...
397 */
398
399 while (isspace(*code & 255))
400 code ++;
401
402 if (!*code)
403 break;
404
405 if (*code == '[')
406 {
407 /*
408 * Read array of values...
409 */
410
411 type = CUPS_TYPE_ARRAY;
412
413 for (ptr = value; *code && *code != ']'; code ++)
414 if (ptr < (value + sizeof(value) - 1))
415 *ptr++ = *code;
416 else
417 return (-1);
418
419 if (*code == ']')
420 *ptr++ = *code++;
421
422 *ptr = '\0';
423 }
424 else if (*code == '(')
425 {
426 /*
427 * Read string value...
428 */
429
430 type = CUPS_TYPE_STRING;
431
432 for (ptr = value; *code && *code != ')'; code ++)
433 if (ptr < (value + sizeof(value) - 1))
434 *ptr++ = *code;
435 else
436 return (-1);
437
438 if (*code == ')')
439 *ptr++ = *code++;
440
441 *ptr = '\0';
442 }
443 else if (isdigit(*code & 255) || *code == '-' || *code == '.')
444 {
445 /*
446 * Read single number...
447 */
448
449 type = CUPS_TYPE_NUMBER;
450
451 for (ptr = value;
452 isdigit(*code & 255) || *code == '-' || *code == '.';
453 code ++)
454 if (ptr < (value + sizeof(value) - 1))
455 *ptr++ = *code;
456 else
457 return (-1);
458
459 *ptr = '\0';
460 }
461 else
462 {
463 /*
464 * Read a single name...
465 */
466
467 type = CUPS_TYPE_NAME;
468
469 for (ptr = value; isalnum(*code & 255) || *code == '_'; code ++)
470 if (ptr < (value + sizeof(value) - 1))
471 *ptr++ = *code;
472 else
473 return (-1);
474
475 *ptr = '\0';
476 }
477
478 /*
479 * Assign the value as needed...
480 */
481
482 if (!strcmp(name, "MediaClass") && type == CUPS_TYPE_STRING)
483 {
484 if (sscanf(value, "(%63[^)])", h->MediaClass) != 1)
485 return (-1);
486 }
487 else if (!strcmp(name, "MediaColor") && type == CUPS_TYPE_STRING)
488 {
489 if (sscanf(value, "(%63[^)])", h->MediaColor) != 1)
490 return (-1);
491 }
492 else if (!strcmp(name, "MediaType") && type == CUPS_TYPE_STRING)
493 {
494 if (sscanf(value, "(%63[^)])", h->MediaType) != 1)
495 return (-1);
496 }
497 else if (!strcmp(name, "OutputType") && type == CUPS_TYPE_STRING)
498 {
499 if (sscanf(value, "(%63[^)])", h->OutputType) != 1)
500 return (-1);
501 }
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)
513 {
514 if (sscanf(value, "[%d%d]", h->HWResolution + 0,
515 h->HWResolution + 1) != 2)
516 return (-1);
517 }
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)
540 {
fa73b229 541 if (sscanf(value, "[%f%f]", h->cupsPageSize + 0, h->cupsPageSize + 1) != 2)
542 return (-1);
ef416fc2 543 }
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);
a74454a7 554 else if (!strcmp(name, "cupsPreferredBitsPerColor") && type == CUPS_TYPE_NUMBER)
555 *preferred_bits = atoi(value);
ef416fc2 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);
923edb68 568 else if (!strcmp(name, "cupsBorderlessScalingFactor") &&
569 type == CUPS_TYPE_NUMBER)
570 h->cupsBorderlessScalingFactor = atof(value);
ef416fc2 571 else if (!strncmp(name, "cupsInteger", 11) && type == CUPS_TYPE_NUMBER)
572 {
573 if ((i = atoi(name + 11)) >= 0 || i > 15)
574 return (-1);
575
576 h->cupsInteger[i] = atoi(value);
577 }
578 else if (!strncmp(name, "cupsReal", 8) && type == CUPS_TYPE_NUMBER)
579 {
580 if ((i = atoi(name + 8)) >= 0 || i > 15)
581 return (-1);
582
583 h->cupsReal[i] = atof(value);
584 }
585 else if (!strncmp(name, "cupsString", 10) && type == CUPS_TYPE_STRING)
586 {
587 if ((i = atoi(name + 10)) >= 0 || i > 15)
588 return (-1);
589
590 if (sscanf(value, "(%63[^)])", h->cupsString[i]) != 1)
591 return (-1);
592 }
593 else if (!strcmp(name, "cupsMarkerType") && type == CUPS_TYPE_STRING)
594 {
595 if (sscanf(value, "(%63[^)])", h->cupsMarkerType) != 1)
596 return (-1);
597 }
598 else if (!strcmp(name, "cupsRenderingIntent") && type == CUPS_TYPE_STRING)
599 {
600 if (sscanf(value, "(%63[^)])", h->cupsRenderingIntent) != 1)
601 return (-1);
602 }
ef416fc2 603 }
604
605 /*
606 * Return success...
607 */
608
609 return (0);
610}
611
612
613/*
07725fee 614 * End of "$Id: interpret.c 5926 2006-09-05 20:45:47Z mike $".
ef416fc2 615 */