]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/interpret.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / filter / interpret.c
CommitLineData
ef416fc2 1/*
739a2093 2 * PPD command interpreter for CUPS.
ef416fc2 3 *
d9564ec7 4 * Copyright 2007-2015 by Apple Inc.
739a2093 5 * Copyright 1993-2007 by Easy Software Products.
ef416fc2 6 *
e3101897 7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
ef416fc2 8 */
9
10/*
11 * Include necessary headers...
12 */
13
a4845881 14#include <cups/raster-private.h>
6e5a57e8 15#include <cups/ppd.h>
ef416fc2 16
17
18/*
b86bc4cf 19 * Stack values for the PostScript mini-interpreter...
ef416fc2 20 */
21
b86bc4cf 22typedef enum
23{
24 CUPS_PS_NAME,
25 CUPS_PS_NUMBER,
26 CUPS_PS_STRING,
27 CUPS_PS_BOOLEAN,
28 CUPS_PS_NULL,
29 CUPS_PS_START_ARRAY,
30 CUPS_PS_END_ARRAY,
31 CUPS_PS_START_DICT,
32 CUPS_PS_END_DICT,
33 CUPS_PS_START_PROC,
34 CUPS_PS_END_PROC,
35 CUPS_PS_CLEARTOMARK,
36 CUPS_PS_COPY,
37 CUPS_PS_DUP,
38 CUPS_PS_INDEX,
39 CUPS_PS_POP,
40 CUPS_PS_ROLL,
41 CUPS_PS_SETPAGEDEVICE,
42 CUPS_PS_STOPPED,
43 CUPS_PS_OTHER
44} _cups_ps_type_t;
45
46typedef struct
47{
48 _cups_ps_type_t type; /* Object type */
49 union
50 {
51 int boolean; /* Boolean value */
52 char name[64]; /* Name value */
53 double number; /* Number value */
54 char other[64]; /* Other operator */
55 char string[64]; /* Sring value */
56 } value; /* Value */
57} _cups_ps_obj_t;
58
59typedef struct
60{
61 int num_objs, /* Number of objects on stack */
62 alloc_objs; /* Number of allocated objects */
63 _cups_ps_obj_t *objs; /* Objects in stack */
64} _cups_ps_stack_t;
ef416fc2 65
66
67/*
68 * Local functions...
69 */
70
b86bc4cf 71static int cleartomark_stack(_cups_ps_stack_t *st);
72static int copy_stack(_cups_ps_stack_t *st, int count);
73static void delete_stack(_cups_ps_stack_t *st);
f7deaa1a 74static void error_object(_cups_ps_obj_t *obj);
75static void error_stack(_cups_ps_stack_t *st, const char *title);
b86bc4cf 76static _cups_ps_obj_t *index_stack(_cups_ps_stack_t *st, int n);
77static _cups_ps_stack_t *new_stack(void);
78static _cups_ps_obj_t *pop_stack(_cups_ps_stack_t *st);
79static _cups_ps_obj_t *push_stack(_cups_ps_stack_t *st,
80 _cups_ps_obj_t *obj);
81static int roll_stack(_cups_ps_stack_t *st, int c, int s);
82static _cups_ps_obj_t *scan_ps(_cups_ps_stack_t *st, char **ptr);
83static int setpagedevice(_cups_ps_stack_t *st,
84 cups_page_header2_t *h,
85 int *preferred_bits);
86#ifdef DEBUG
d9564ec7
MS
87static void DEBUG_object(const char *prefix, _cups_ps_obj_t *obj);
88static void DEBUG_stack(const char *prefix, _cups_ps_stack_t *st);
b86bc4cf 89#endif /* DEBUG */
ef416fc2 90
91
92/*
93 * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
94 *
db0bd74a
MS
95 * This function is used by raster image processing (RIP) filters like
96 * cgpdftoraster and imagetoraster when writing CUPS raster data for a page.
97 * It is not used by raster printer driver filters which only read CUPS
98 * raster data.
99 *
100 *
101 * @code cupsRasterInterpretPPD@ does not mark the options in the PPD using
102 * the "num_options" and "options" arguments. Instead, mark the options with
103 * @code cupsMarkOptions@ and @code ppdMarkOption@ prior to calling it -
104 * this allows for per-page options without manipulating the options array.
923edb68 105 *
a74454a7 106 * The "func" argument specifies an optional callback function that is
107 * called prior to the computation of the final raster data. The function
5a738aea 108 * can make changes to the @link cups_page_header2_t@ data as needed to use a
a74454a7 109 * supported raster format and then returns 0 on success and -1 if the
110 * requested attributes cannot be supported.
111 *
db0bd74a 112 *
5a738aea
MS
113 * @code cupsRasterInterpretPPD@ supports a subset of the PostScript language.
114 * Currently only the @code [@, @code ]@, @code <<@, @code >>@, @code {@,
115 * @code }@, @code cleartomark@, @code copy@, @code dup@, @code index@,
116 * @code pop@, @code roll@, @code setpagedevice@, and @code stopped@ operators
117 * are supported.
b86bc4cf 118 *
8072030b 119 * @since CUPS 1.2/macOS 10.5@
ef416fc2 120 */
121
122int /* O - 0 on success, -1 on failure */
123cupsRasterInterpretPPD(
db0bd74a 124 cups_page_header2_t *h, /* O - Page header to create */
923edb68 125 ppd_file_t *ppd, /* I - PPD file */
126 int num_options, /* I - Number of options */
a74454a7 127 cups_option_t *options, /* I - Options */
db0bd74a 128 cups_interpret_cb_t func) /* I - Optional page header callback (@code NULL@ for none) */
ef416fc2 129{
ef416fc2 130 int status; /* Cummulative status */
b86bc4cf 131 char *code; /* Code to run */
923edb68 132 const char *val; /* Option value */
ef416fc2 133 ppd_size_t *size; /* Current size */
134 float left, /* Left position */
135 bottom, /* Bottom position */
136 right, /* Right position */
739a2093
MS
137 top, /* Top position */
138 temp1, temp2; /* Temporary variables for swapping */
a74454a7 139 int preferred_bits; /* Preferred bits per color */
ef416fc2 140
141
142 /*
143 * Range check input...
144 */
145
f7deaa1a 146 _cupsRasterClearError();
147
ef416fc2 148 if (!h)
f7deaa1a 149 {
150 _cupsRasterAddError("Page header cannot be NULL!\n");
ef416fc2 151 return (-1);
f7deaa1a 152 }
ef416fc2 153
154 /*
155 * Reset the page header to the defaults...
156 */
157
158 memset(h, 0, sizeof(cups_page_header2_t));
159
923edb68 160 h->NumCopies = 1;
161 h->PageSize[0] = 612;
162 h->PageSize[1] = 792;
163 h->HWResolution[0] = 100;
164 h->HWResolution[1] = 100;
739a2093 165 h->cupsBitsPerColor = 1;
923edb68 166 h->cupsColorOrder = CUPS_ORDER_CHUNKED;
167 h->cupsColorSpace = CUPS_CSPACE_K;
168 h->cupsBorderlessScalingFactor = 1.0f;
169 h->cupsPageSize[0] = 612.0f;
170 h->cupsPageSize[1] = 792.0f;
171 h->cupsImagingBBox[0] = 0.0f;
172 h->cupsImagingBBox[1] = 0.0f;
173 h->cupsImagingBBox[2] = 612.0f;
174 h->cupsImagingBBox[3] = 792.0f;
fa73b229 175
5a9febac 176 strlcpy(h->cupsPageSizeName, "Letter", sizeof(h->cupsPageSizeName));
ef416fc2 177
e38f5e9c
MS
178#ifdef __APPLE__
179 /*
8072030b 180 * cupsInteger0 is also used for the total page count on macOS; set an
e38f5e9c
MS
181 * uncommon default value so we can tell if the driver is using cupsInteger0.
182 */
183
184 h->cupsInteger[0] = 0x80000000;
185#endif /* __APPLE__ */
186
ef416fc2 187 /*
188 * Apply patches and options to the page header...
189 */
190
a74454a7 191 status = 0;
192 preferred_bits = 0;
ef416fc2 193
194 if (ppd)
195 {
196 /*
197 * Apply any patch code (used to override the defaults...)
198 */
199
200 if (ppd->patches)
b86bc4cf 201 status |= _cupsRasterExecPS(h, &preferred_bits, ppd->patches);
ef416fc2 202
203 /*
204 * Then apply printer options in the proper order...
205 */
206
b86bc4cf 207 if ((code = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
ef416fc2 208 {
b86bc4cf 209 status |= _cupsRasterExecPS(h, &preferred_bits, code);
210 free(code);
ef416fc2 211 }
212
b86bc4cf 213 if ((code = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
ef416fc2 214 {
b86bc4cf 215 status |= _cupsRasterExecPS(h, &preferred_bits, code);
216 free(code);
ef416fc2 217 }
218
b86bc4cf 219 if ((code = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
ef416fc2 220 {
b86bc4cf 221 status |= _cupsRasterExecPS(h, &preferred_bits, code);
222 free(code);
ef416fc2 223 }
224
b86bc4cf 225 if ((code = ppdEmitString(ppd, PPD_ORDER_PAGE, 0.0)) != NULL)
ef416fc2 226 {
b86bc4cf 227 status |= _cupsRasterExecPS(h, &preferred_bits, code);
228 free(code);
ef416fc2 229 }
230 }
231
923edb68 232 /*
233 * Allow option override for page scaling...
234 */
235
236 if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options,
237 options)) != NULL)
238 {
c8fef167 239 double sc = atof(val); /* Scale factor */
923edb68 240
06d4e77b 241 if (sc >= 0.1 && sc <= 2.0)
c8fef167 242 h->cupsBorderlessScalingFactor = (float)sc;
923edb68 243 }
244
ef416fc2 245 /*
246 * Get the margins for the current size...
247 */
248
249 if ((size = ppdPageSize(ppd, NULL)) != NULL)
250 {
251 /*
252 * Use the margins from the PPD file...
253 */
254
255 left = size->left;
256 bottom = size->bottom;
257 right = size->right;
258 top = size->top;
fa73b229 259
260 strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName));
07725fee 261
262 h->cupsPageSize[0] = size->width;
263 h->cupsPageSize[1] = size->length;
ef416fc2 264 }
265 else
266 {
267 /*
268 * Use the default margins...
269 */
270
271 left = 0.0f;
272 bottom = 0.0f;
273 right = 612.0f;
274 top = 792.0f;
275 }
276
739a2093
MS
277 /*
278 * Handle orientation...
279 */
280
281 switch (h->Orientation)
282 {
283 case CUPS_ORIENT_0 :
284 default :
285 /* Do nothing */
286 break;
287
288 case CUPS_ORIENT_90 :
289 temp1 = h->cupsPageSize[0];
290 h->cupsPageSize[0] = h->cupsPageSize[1];
291 h->cupsPageSize[1] = temp1;
292
293 temp1 = left;
294 temp2 = right;
295 left = h->cupsPageSize[0] - top;
296 right = h->cupsPageSize[0] - bottom;
297 bottom = h->cupsPageSize[1] - temp1;
298 top = h->cupsPageSize[1] - temp2;
299 break;
300
301 case CUPS_ORIENT_180 :
302 temp1 = left;
303 temp2 = bottom;
304 left = h->cupsPageSize[0] - right;
305 right = h->cupsPageSize[0] - temp1;
306 bottom = h->cupsPageSize[1] - top;
307 top = h->cupsPageSize[1] - temp2;
308 break;
309
310 case CUPS_ORIENT_270 :
311 temp1 = h->cupsPageSize[0];
312 h->cupsPageSize[0] = h->cupsPageSize[1];
313 h->cupsPageSize[1] = temp1;
314
315 temp1 = left;
316 temp2 = right;
317 left = bottom;
318 right = top;
319 bottom = h->cupsPageSize[1] - temp2;
320 top = h->cupsPageSize[1] - temp1;
321 break;
322 }
323
355ddf41
MS
324 if (left > right)
325 {
326 temp1 = left;
327 left = right;
328 right = temp1;
329 }
330
331 if (bottom > top)
332 {
333 temp1 = bottom;
334 bottom = top;
335 top = temp1;
336 }
337
c8fef167
MS
338 h->PageSize[0] = (unsigned)(h->cupsPageSize[0] *
339 h->cupsBorderlessScalingFactor);
340 h->PageSize[1] = (unsigned)(h->cupsPageSize[1] *
341 h->cupsBorderlessScalingFactor);
342 h->Margins[0] = (unsigned)(left *
343 h->cupsBorderlessScalingFactor);
344 h->Margins[1] = (unsigned)(bottom *
345 h->cupsBorderlessScalingFactor);
346 h->ImagingBoundingBox[0] = (unsigned)(left *
347 h->cupsBorderlessScalingFactor);
348 h->ImagingBoundingBox[1] = (unsigned)(bottom *
349 h->cupsBorderlessScalingFactor);
350 h->ImagingBoundingBox[2] = (unsigned)(right *
351 h->cupsBorderlessScalingFactor);
352 h->ImagingBoundingBox[3] = (unsigned)(top *
353 h->cupsBorderlessScalingFactor);
354 h->cupsImagingBBox[0] = (float)left;
355 h->cupsImagingBBox[1] = (float)bottom;
356 h->cupsImagingBBox[2] = (float)right;
357 h->cupsImagingBBox[3] = (float)top;
ef416fc2 358
a74454a7 359 /*
360 * Use the callback to validate the page header...
361 */
362
363 if (func && (*func)(h, preferred_bits))
f7deaa1a 364 {
365 _cupsRasterAddError("Page header callback returned error.\n");
a74454a7 366 return (-1);
f7deaa1a 367 }
a74454a7 368
a9252913 369 /*
370 * Check parameters...
371 */
372
373 if (!h->HWResolution[0] || !h->HWResolution[1] ||
374 !h->PageSize[0] || !h->PageSize[1] ||
375 (h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 &&
376 h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8 &&
377 h->cupsBitsPerColor != 16) ||
06d4e77b 378 h->cupsBorderlessScalingFactor < 0.1 ||
b86bc4cf 379 h->cupsBorderlessScalingFactor > 2.0)
f7deaa1a 380 {
381 _cupsRasterAddError("Page header uses unsupported values.\n");
a9252913 382 return (-1);
f7deaa1a 383 }
a9252913 384
ef416fc2 385 /*
386 * Compute the bitmap parameters...
387 */
388
7e86f2f6 389 h->cupsWidth = (unsigned)((right - left) * h->cupsBorderlessScalingFactor *
fa73b229 390 h->HWResolution[0] / 72.0f + 0.5f);
7e86f2f6 391 h->cupsHeight = (unsigned)((top - bottom) * h->cupsBorderlessScalingFactor *
fa73b229 392 h->HWResolution[1] / 72.0f + 0.5f);
ef416fc2 393
394 switch (h->cupsColorSpace)
395 {
396 case CUPS_CSPACE_W :
397 case CUPS_CSPACE_K :
398 case CUPS_CSPACE_WHITE :
399 case CUPS_CSPACE_GOLD :
400 case CUPS_CSPACE_SILVER :
88f9aafc 401 case CUPS_CSPACE_SW :
ef416fc2 402 h->cupsNumColors = 1;
403 h->cupsBitsPerPixel = h->cupsBitsPerColor;
404 break;
405
406 default :
407 /*
408 * Ensure that colorimetric colorspaces use at least 8 bits per
409 * component...
410 */
411
412 if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ &&
413 h->cupsBitsPerColor < 8)
414 h->cupsBitsPerColor = 8;
415
416 /*
417 * Figure out the number of bits per pixel...
418 */
419
420 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
421 {
422 if (h->cupsBitsPerColor >= 8)
423 h->cupsBitsPerPixel = h->cupsBitsPerColor * 3;
424 else
425 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
426 }
427 else
428 h->cupsBitsPerPixel = h->cupsBitsPerColor;
429
430 h->cupsNumColors = 3;
431 break;
432
433 case CUPS_CSPACE_KCMYcm :
f301802f 434 if (h->cupsBitsPerColor == 1)
ef416fc2 435 {
436 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
437 h->cupsBitsPerPixel = 8;
438 else
439 h->cupsBitsPerPixel = 1;
440
441 h->cupsNumColors = 6;
442 break;
443 }
444
445 /*
446 * Fall through to CMYK code...
447 */
448
449 case CUPS_CSPACE_RGBA :
a74454a7 450 case CUPS_CSPACE_RGBW :
ef416fc2 451 case CUPS_CSPACE_CMYK :
452 case CUPS_CSPACE_YMCK :
453 case CUPS_CSPACE_KCMY :
454 case CUPS_CSPACE_GMCK :
455 case CUPS_CSPACE_GMCS :
456 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
457 h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
458 else
459 h->cupsBitsPerPixel = h->cupsBitsPerColor;
460
461 h->cupsNumColors = 4;
462 break;
88f9aafc
MS
463
464 case CUPS_CSPACE_DEVICE1 :
465 case CUPS_CSPACE_DEVICE2 :
466 case CUPS_CSPACE_DEVICE3 :
467 case CUPS_CSPACE_DEVICE4 :
468 case CUPS_CSPACE_DEVICE5 :
469 case CUPS_CSPACE_DEVICE6 :
470 case CUPS_CSPACE_DEVICE7 :
471 case CUPS_CSPACE_DEVICE8 :
472 case CUPS_CSPACE_DEVICE9 :
473 case CUPS_CSPACE_DEVICEA :
474 case CUPS_CSPACE_DEVICEB :
475 case CUPS_CSPACE_DEVICEC :
476 case CUPS_CSPACE_DEVICED :
477 case CUPS_CSPACE_DEVICEE :
478 case CUPS_CSPACE_DEVICEF :
479 h->cupsNumColors = h->cupsColorSpace - CUPS_CSPACE_DEVICE1 + 1;
480
481 if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
482 h->cupsBitsPerPixel = h->cupsBitsPerColor * h->cupsNumColors;
483 else
484 h->cupsBitsPerPixel = h->cupsBitsPerColor;
485 break;
ef416fc2 486 }
487
488 h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8;
489
490 if (h->cupsColorOrder == CUPS_ORDER_BANDED)
491 h->cupsBytesPerLine *= h->cupsNumColors;
492
493 return (status);
494}
495
496
497/*
b86bc4cf 498 * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header.
ef416fc2 499 */
500
b86bc4cf 501int /* O - 0 on success, -1 on error */
502_cupsRasterExecPS(
a74454a7 503 cups_page_header2_t *h, /* O - Page header */
504 int *preferred_bits,/* O - Preferred bits per color */
b86bc4cf 505 const char *code) /* I - PS code to execute */
ef416fc2 506{
b1564bae 507 int error = 0; /* Error condition? */
b86bc4cf 508 _cups_ps_stack_t *st; /* PostScript value stack */
509 _cups_ps_obj_t *obj; /* Object from top of stack */
510 char *codecopy, /* Copy of code */
511 *codeptr; /* Pointer into copy of code */
512
ef416fc2 513
b86bc4cf 514 DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n",
b1564bae 515 h, preferred_bits, code));
ef416fc2 516
517 /*
b86bc4cf 518 * Copy the PostScript code and create a stack...
ef416fc2 519 */
520
b86bc4cf 521 if ((codecopy = strdup(code)) == NULL)
f7deaa1a 522 {
523 _cupsRasterAddError("Unable to duplicate code string.\n");
b86bc4cf 524 return (-1);
f7deaa1a 525 }
b86bc4cf 526
527 if ((st = new_stack()) == NULL)
528 {
f7deaa1a 529 _cupsRasterAddError("Unable to create stack.\n");
b86bc4cf 530 free(codecopy);
ef416fc2 531 return (-1);
b86bc4cf 532 }
ef416fc2 533
534 /*
b86bc4cf 535 * Parse the PS string until we run out of data...
ef416fc2 536 */
537
b86bc4cf 538 codeptr = codecopy;
539
540 while ((obj = scan_ps(st, &codeptr)) != NULL)
ef416fc2 541 {
b86bc4cf 542#ifdef DEBUG
d9564ec7
MS
543 DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)", st->num_objs));
544 DEBUG_object("_cupsRasterExecPS", obj);
b86bc4cf 545#endif /* DEBUG */
546
547 switch (obj->type)
548 {
549 default :
550 /* Do nothing for regular values */
551 break;
552
553 case CUPS_PS_CLEARTOMARK :
554 pop_stack(st);
555
f7deaa1a 556 if (cleartomark_stack(st))
d9564ec7 557 _cupsRasterAddError("cleartomark: Stack underflow.\n");
b86bc4cf 558
559#ifdef DEBUG
d9564ec7
MS
560 DEBUG_puts("1_cupsRasterExecPS: dup");
561 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 562#endif /* DEBUG */
563 break;
564
565 case CUPS_PS_COPY :
566 pop_stack(st);
567 if ((obj = pop_stack(st)) != NULL)
568 {
569 copy_stack(st, (int)obj->value.number);
570
571#ifdef DEBUG
ae71f5de 572 DEBUG_puts("_cupsRasterExecPS: copy");
d9564ec7 573 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 574#endif /* DEBUG */
575 }
576 break;
577
578 case CUPS_PS_DUP :
579 pop_stack(st);
580 copy_stack(st, 1);
581
582#ifdef DEBUG
ae71f5de 583 DEBUG_puts("_cupsRasterExecPS: dup");
d9564ec7 584 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 585#endif /* DEBUG */
586 break;
587
588 case CUPS_PS_INDEX :
589 pop_stack(st);
590 if ((obj = pop_stack(st)) != NULL)
591 {
592 index_stack(st, (int)obj->value.number);
593
594#ifdef DEBUG
ae71f5de 595 DEBUG_puts("_cupsRasterExecPS: index");
d9564ec7 596 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 597#endif /* DEBUG */
598 }
599 break;
600
601 case CUPS_PS_POP :
602 pop_stack(st);
603 pop_stack(st);
604
605#ifdef DEBUG
ae71f5de 606 DEBUG_puts("_cupsRasterExecPS: pop");
d9564ec7 607 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 608#endif /* DEBUG */
609 break;
610
611 case CUPS_PS_ROLL :
612 pop_stack(st);
613 if ((obj = pop_stack(st)) != NULL)
614 {
615 int c; /* Count */
ef416fc2 616
ef416fc2 617
b86bc4cf 618 c = (int)obj->value.number;
619
620 if ((obj = pop_stack(st)) != NULL)
621 {
622 roll_stack(st, (int)obj->value.number, c);
623
624#ifdef DEBUG
ae71f5de 625 DEBUG_puts("_cupsRasterExecPS: roll");
d9564ec7 626 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 627#endif /* DEBUG */
628 }
629 }
630 break;
631
632 case CUPS_PS_SETPAGEDEVICE :
633 pop_stack(st);
634 setpagedevice(st, h, preferred_bits);
635
636#ifdef DEBUG
ae71f5de 637 DEBUG_puts("_cupsRasterExecPS: setpagedevice");
d9564ec7 638 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 639#endif /* DEBUG */
640 break;
641
642 case CUPS_PS_START_PROC :
643 case CUPS_PS_END_PROC :
644 case CUPS_PS_STOPPED :
645 pop_stack(st);
646 break;
647
648 case CUPS_PS_OTHER :
d9564ec7 649 _cupsRasterAddError("Unknown operator \"%s\".\n", obj->value.other);
b1564bae 650 error = 1;
d9564ec7 651 DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\".", obj->value.other));
b86bc4cf 652 break;
653 }
654
b1564bae 655 if (error)
ef416fc2 656 break;
b86bc4cf 657 }
658
659 /*
660 * Cleanup...
661 */
662
663 free(codecopy);
664
665 if (st->num_objs > 0)
666 {
f7deaa1a 667 error_stack(st, "Stack not empty:");
668
b86bc4cf 669#ifdef DEBUG
d9564ec7
MS
670 DEBUG_puts("_cupsRasterExecPS: Stack not empty");
671 DEBUG_stack("_cupsRasterExecPS", st);
b86bc4cf 672#endif /* DEBUG */
ef416fc2 673
b86bc4cf 674 delete_stack(st);
675
676 return (-1);
677 }
678
679 delete_stack(st);
680
681 /*
682 * Return success...
683 */
684
685 return (0);
686}
687
688
689/*
690 * 'cleartomark_stack()' - Clear to the last mark ([) on the stack.
691 */
692
693static int /* O - 0 on success, -1 on error */
694cleartomark_stack(_cups_ps_stack_t *st) /* I - Stack */
695{
696 _cups_ps_obj_t *obj; /* Current object on stack */
697
698
699 while ((obj = pop_stack(st)) != NULL)
700 if (obj->type == CUPS_PS_START_ARRAY)
701 break;
702
703 return (obj ? 0 : -1);
704}
705
706
707/*
708 * 'copy_stack()' - Copy the top N stack objects.
709 */
710
711static int /* O - 0 on success, -1 on error */
712copy_stack(_cups_ps_stack_t *st, /* I - Stack */
713 int c) /* I - Number of objects to copy */
714{
715 int n; /* Index */
716
717
718 if (c < 0)
719 return (-1);
720 else if (c == 0)
721 return (0);
722
723 if ((n = st->num_objs - c) < 0)
724 return (-1);
725
726 while (c > 0)
727 {
728 if (!push_stack(st, st->objs + n))
729 return (-1);
730
731 n ++;
732 c --;
733 }
734
735 return (0);
736}
737
738
739/*
740 * 'delete_stack()' - Free memory used by a stack.
741 */
742
743static void
744delete_stack(_cups_ps_stack_t *st) /* I - Stack */
745{
746 free(st->objs);
747 free(st);
748}
749
750
f7deaa1a 751/*
752 * 'error_object()' - Add an object's value to the current error message.
753 */
754
755static void
756error_object(_cups_ps_obj_t *obj) /* I - Object to add */
757{
758 switch (obj->type)
759 {
760 case CUPS_PS_NAME :
761 _cupsRasterAddError(" /%s", obj->value.name);
762 break;
763
764 case CUPS_PS_NUMBER :
765 _cupsRasterAddError(" %g", obj->value.number);
766 break;
767
768 case CUPS_PS_STRING :
769 _cupsRasterAddError(" (%s)", obj->value.string);
770 break;
771
772 case CUPS_PS_BOOLEAN :
773 if (obj->value.boolean)
774 _cupsRasterAddError(" true");
775 else
776 _cupsRasterAddError(" false");
777 break;
778
779 case CUPS_PS_NULL :
780 _cupsRasterAddError(" null");
781 break;
782
783 case CUPS_PS_START_ARRAY :
784 _cupsRasterAddError(" [");
785 break;
786
787 case CUPS_PS_END_ARRAY :
788 _cupsRasterAddError(" ]");
789 break;
790
791 case CUPS_PS_START_DICT :
792 _cupsRasterAddError(" <<");
793 break;
794
795 case CUPS_PS_END_DICT :
796 _cupsRasterAddError(" >>");
797 break;
798
799 case CUPS_PS_START_PROC :
800 _cupsRasterAddError(" {");
801 break;
802
803 case CUPS_PS_END_PROC :
804 _cupsRasterAddError(" }");
805 break;
806
807 case CUPS_PS_COPY :
808 _cupsRasterAddError(" --copy--");
809 break;
810
811 case CUPS_PS_CLEARTOMARK :
812 _cupsRasterAddError(" --cleartomark--");
813 break;
814
815 case CUPS_PS_DUP :
816 _cupsRasterAddError(" --dup--");
817 break;
818
819 case CUPS_PS_INDEX :
820 _cupsRasterAddError(" --index--");
821 break;
822
823 case CUPS_PS_POP :
824 _cupsRasterAddError(" --pop--");
825 break;
826
827 case CUPS_PS_ROLL :
828 _cupsRasterAddError(" --roll--");
829 break;
830
831 case CUPS_PS_SETPAGEDEVICE :
832 _cupsRasterAddError(" --setpagedevice--");
833 break;
834
835 case CUPS_PS_STOPPED :
836 _cupsRasterAddError(" --stopped--");
837 break;
838
839 case CUPS_PS_OTHER :
840 _cupsRasterAddError(" --%s--", obj->value.other);
841 break;
842 }
843}
844
845
846/*
847 * 'error_stack()' - Add a stack to the current error message...
848 */
849
850static void
851error_stack(_cups_ps_stack_t *st, /* I - Stack */
852 const char *title) /* I - Title string */
853{
854 int c; /* Looping var */
855 _cups_ps_obj_t *obj; /* Current object on stack */
856
857
85dda01c 858 _cupsRasterAddError("%s", title);
f7deaa1a 859
860 for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++)
861 error_object(obj);
862
863 _cupsRasterAddError("\n");
864}
865
866
b86bc4cf 867/*
868 * 'index_stack()' - Copy the Nth value on the stack.
869 */
870
871static _cups_ps_obj_t * /* O - New object */
872index_stack(_cups_ps_stack_t *st, /* I - Stack */
873 int n) /* I - Object index */
874{
875 if (n < 0 || (n = st->num_objs - n - 1) < 0)
876 return (NULL);
877
878 return (push_stack(st, st->objs + n));
879}
880
881
882/*
883 * 'new_stack()' - Create a new stack.
884 */
885
886static _cups_ps_stack_t * /* O - New stack */
887new_stack(void)
888{
889 _cups_ps_stack_t *st; /* New stack */
890
891
892 if ((st = calloc(1, sizeof(_cups_ps_stack_t))) == NULL)
893 return (NULL);
894
895 st->alloc_objs = 32;
896
897 if ((st->objs = calloc(32, sizeof(_cups_ps_obj_t))) == NULL)
898 {
899 free(st);
900 return (NULL);
901 }
902 else
903 return (st);
904}
905
906
907/*
908 * 'pop_stock()' - Pop the top object off the stack.
909 */
910
911static _cups_ps_obj_t * /* O - Object */
912pop_stack(_cups_ps_stack_t *st) /* I - Stack */
913{
914 if (st->num_objs > 0)
915 {
916 st->num_objs --;
917
918 return (st->objs + st->num_objs);
919 }
920 else
921 return (NULL);
922}
923
924
925/*
926 * 'push_stack()' - Push an object on the stack.
927 */
928
929static _cups_ps_obj_t * /* O - New object */
930push_stack(_cups_ps_stack_t *st, /* I - Stack */
931 _cups_ps_obj_t *obj) /* I - Object */
932{
933 _cups_ps_obj_t *temp; /* New object */
934
935
936 if (st->num_objs >= st->alloc_objs)
937 {
938
939
940 st->alloc_objs += 32;
941
7e86f2f6 942 if ((temp = realloc(st->objs, (size_t)st->alloc_objs *
b86bc4cf 943 sizeof(_cups_ps_obj_t))) == NULL)
944 return (NULL);
945
946 st->objs = temp;
947 memset(temp + st->num_objs, 0, 32 * sizeof(_cups_ps_obj_t));
948 }
949
950 temp = st->objs + st->num_objs;
951 st->num_objs ++;
952
953 memcpy(temp, obj, sizeof(_cups_ps_obj_t));
954
955 return (temp);
956}
957
958
959/*
960 * 'roll_stack()' - Rotate stack objects.
961 */
962
963static int /* O - 0 on success, -1 on error */
964roll_stack(_cups_ps_stack_t *st, /* I - Stack */
965 int c, /* I - Number of objects */
966 int s) /* I - Amount to shift */
967{
968 _cups_ps_obj_t *temp; /* Temporary array of objects */
969 int n; /* Index into array */
970
971
d9564ec7 972 DEBUG_printf(("3roll_stack(st=%p, s=%d, c=%d)", st, s, c));
b86bc4cf 973
974 /*
975 * Range check input...
976 */
977
978 if (c < 0)
979 return (-1);
980 else if (c == 0)
981 return (0);
982
983 if ((n = st->num_objs - c) < 0)
984 return (-1);
985
986 s %= c;
987
988 if (s == 0)
989 return (0);
990
991 /*
992 * Copy N objects and move things around...
993 */
994
995 if (s < 0)
996 {
ef416fc2 997 /*
b86bc4cf 998 * Shift down...
ef416fc2 999 */
1000
b86bc4cf 1001 s = -s;
ef416fc2 1002
7e86f2f6 1003 if ((temp = calloc((size_t)s, sizeof(_cups_ps_obj_t))) == NULL)
b86bc4cf 1004 return (-1);
ef416fc2 1005
7e86f2f6
MS
1006 memcpy(temp, st->objs + n, (size_t)s * sizeof(_cups_ps_obj_t));
1007 memmove(st->objs + n, st->objs + n + s, (size_t)(c - s) * sizeof(_cups_ps_obj_t));
1008 memcpy(st->objs + n + c - s, temp, (size_t)s * sizeof(_cups_ps_obj_t));
b86bc4cf 1009 }
1010 else
1011 {
ef416fc2 1012 /*
b86bc4cf 1013 * Shift up...
ef416fc2 1014 */
1015
7e86f2f6 1016 if ((temp = calloc((size_t)s, sizeof(_cups_ps_obj_t))) == NULL)
b86bc4cf 1017 return (-1);
ef416fc2 1018
7e86f2f6
MS
1019 memcpy(temp, st->objs + n + c - s, (size_t)s * sizeof(_cups_ps_obj_t));
1020 memmove(st->objs + n + s, st->objs + n, (size_t)(c - s) * sizeof(_cups_ps_obj_t));
1021 memcpy(st->objs + n, temp, (size_t)s * sizeof(_cups_ps_obj_t));
b86bc4cf 1022 }
ef416fc2 1023
b86bc4cf 1024 free(temp);
1025
1026 return (0);
1027}
ef416fc2 1028
ef416fc2 1029
b86bc4cf 1030/*
1031 * 'scan_ps()' - Scan a string for the next PS object.
1032 */
1033
1034static _cups_ps_obj_t * /* O - New object or NULL on EOF */
1035scan_ps(_cups_ps_stack_t *st, /* I - Stack */
1036 char **ptr) /* IO - String pointer */
1037{
1038 _cups_ps_obj_t obj; /* Current object */
1039 char *start, /* Start of object */
1040 *cur, /* Current position */
1041 *valptr, /* Pointer into value string */
1042 *valend; /* End of value string */
1043 int parens; /* Parenthesis nesting level */
ef416fc2 1044
ef416fc2 1045
b86bc4cf 1046 /*
1047 * Skip leading whitespace...
1048 */
1049
1050 for (cur = *ptr; *cur; cur ++)
1051 {
1052 if (*cur == '%')
ef416fc2 1053 {
1054 /*
b86bc4cf 1055 * Comment, skip to end of line...
ef416fc2 1056 */
1057
b86bc4cf 1058 for (cur ++; *cur && *cur != '\n' && *cur != '\r'; cur ++);
b0f6947b
MS
1059
1060 if (!*cur)
1061 cur --;
b86bc4cf 1062 }
1063 else if (!isspace(*cur & 255))
1064 break;
1065 }
ef416fc2 1066
b86bc4cf 1067 if (!*cur)
1068 {
1069 *ptr = NULL;
ef416fc2 1070
b86bc4cf 1071 return (NULL);
1072 }
ef416fc2 1073
b86bc4cf 1074 /*
1075 * See what we have...
1076 */
ef416fc2 1077
b86bc4cf 1078 memset(&obj, 0, sizeof(obj));
ef416fc2 1079
b86bc4cf 1080 switch (*cur)
1081 {
1082 case '(' : /* (string) */
1083 obj.type = CUPS_PS_STRING;
1084 start = cur;
1085
1086 for (cur ++, parens = 1, valptr = obj.value.string,
1087 valend = obj.value.string + sizeof(obj.value.string) - 1;
1088 *cur;
1089 cur ++)
1090 {
1091 if (*cur == ')' && parens == 1)
1092 break;
1093
1094 if (*cur == '(')
1095 parens ++;
1096 else if (*cur == ')')
1097 parens --;
1098
1099 if (valptr >= valend)
1100 {
1101 *ptr = start;
1102
1103 return (NULL);
1104 }
1105
1106 if (*cur == '\\')
1107 {
1108 /*
1109 * Decode escaped character...
1110 */
1111
1112 cur ++;
1113
1114 if (*cur == 'b')
1115 *valptr++ = '\b';
1116 else if (*cur == 'f')
1117 *valptr++ = '\f';
1118 else if (*cur == 'n')
1119 *valptr++ = '\n';
1120 else if (*cur == 'r')
1121 *valptr++ = '\r';
1122 else if (*cur == 't')
1123 *valptr++ = '\t';
1124 else if (*cur >= '0' && *cur <= '7')
1125 {
1126 int ch = *cur - '0';
1127
1128 if (cur[1] >= '0' && cur[1] <= '7')
1129 {
1130 cur ++;
1131 ch = (ch << 3) + *cur - '0';
1132 }
1133
1134 if (cur[1] >= '0' && cur[1] <= '7')
1135 {
1136 cur ++;
1137 ch = (ch << 3) + *cur - '0';
1138 }
1139
7e86f2f6 1140 *valptr++ = (char)ch;
b86bc4cf 1141 }
1142 else if (*cur == '\r')
1143 {
1144 if (cur[1] == '\n')
1145 cur ++;
1146 }
1147 else if (*cur != '\n')
1148 *valptr++ = *cur;
1149 }
1150 else
1151 *valptr++ = *cur;
1152 }
1153
1154 if (*cur != ')')
1155 {
1156 *ptr = start;
1157
1158 return (NULL);
1159 }
1160
1161 cur ++;
1162 break;
1163
1164 case '[' : /* Start array */
1165 obj.type = CUPS_PS_START_ARRAY;
1166 cur ++;
1167 break;
1168
1169 case ']' : /* End array */
1170 obj.type = CUPS_PS_END_ARRAY;
1171 cur ++;
1172 break;
1173
1174 case '<' : /* Start dictionary or hex string */
1175 if (cur[1] == '<')
1176 {
1177 obj.type = CUPS_PS_START_DICT;
1178 cur += 2;
1179 }
ef416fc2 1180 else
b86bc4cf 1181 {
1182 obj.type = CUPS_PS_STRING;
1183 start = cur;
1184
1185 for (cur ++, valptr = obj.value.string,
1186 valend = obj.value.string + sizeof(obj.value.string) - 1;
1187 *cur;
1188 cur ++)
1189 {
1190 int ch; /* Current character */
1191
1192
1193
1194 if (*cur == '>')
1195 break;
1196 else if (valptr >= valend || !isxdigit(*cur & 255))
1197 {
1198 *ptr = start;
1199 return (NULL);
1200 }
1201
1202 if (*cur >= '0' && *cur <= '9')
1203 ch = (*cur - '0') << 4;
1204 else
1205 ch = (tolower(*cur) - 'a' + 10) << 4;
1206
1207 if (isxdigit(cur[1] & 255))
1208 {
1209 cur ++;
1210
1211 if (*cur >= '0' && *cur <= '9')
1212 ch |= *cur - '0';
1213 else
1214 ch |= tolower(*cur) - 'a' + 10;
1215 }
1216
7e86f2f6 1217 *valptr++ = (char)ch;
b86bc4cf 1218 }
1219
1220 if (*cur != '>')
1221 {
1222 *ptr = start;
1223 return (NULL);
1224 }
1225
1226 cur ++;
1227 }
1228 break;
ef416fc2 1229
b86bc4cf 1230 case '>' : /* End dictionary? */
1231 if (cur[1] == '>')
1232 {
1233 obj.type = CUPS_PS_END_DICT;
1234 cur += 2;
1235 }
1236 else
1237 {
1238 obj.type = CUPS_PS_OTHER;
1239 obj.value.other[0] = *cur;
1240
1241 cur ++;
1242 }
1243 break;
1244
1245 case '{' : /* Start procedure */
1246 obj.type = CUPS_PS_START_PROC;
1247 cur ++;
1248 break;
1249
1250 case '}' : /* End procedure */
1251 obj.type = CUPS_PS_END_PROC;
1252 cur ++;
1253 break;
1254
1255 case '-' : /* Possible number */
1256 case '+' :
1257 if (!isdigit(cur[1] & 255) && cur[1] != '.')
1258 {
1259 obj.type = CUPS_PS_OTHER;
1260 obj.value.other[0] = *cur;
1261
1262 cur ++;
1263 break;
1264 }
1265
1266 case '0' : /* Number */
1267 case '1' :
1268 case '2' :
1269 case '3' :
1270 case '4' :
1271 case '5' :
1272 case '6' :
1273 case '7' :
1274 case '8' :
1275 case '9' :
1276 case '.' :
1277 obj.type = CUPS_PS_NUMBER;
1278
1279 start = cur;
1280 for (cur ++; *cur; cur ++)
1281 if (!isdigit(*cur & 255))
1282 break;
1283
1284 if (*cur == '#')
1285 {
1286 /*
1287 * Integer with radix...
1288 */
1289
1290 obj.value.number = strtol(cur + 1, &cur, atoi(start));
1291 break;
1292 }
1293 else if (strchr(".Ee()<>[]{}/%", *cur) || isspace(*cur & 255))
1294 {
1295 /*
1296 * Integer or real number...
1297 */
ef416fc2 1298
b86bc4cf 1299 obj.value.number = _cupsStrScand(start, &cur, localeconv());
1300 break;
1301 }
1302 else
1303 cur = start;
ef416fc2 1304
b86bc4cf 1305 default : /* Operator/variable name */
1306 start = cur;
1307
1308 if (*cur == '/')
1309 {
1310 obj.type = CUPS_PS_NAME;
1311 valptr = obj.value.name;
1312 valend = obj.value.name + sizeof(obj.value.name) - 1;
1313 cur ++;
1314 }
ef416fc2 1315 else
b86bc4cf 1316 {
1317 obj.type = CUPS_PS_OTHER;
1318 valptr = obj.value.other;
1319 valend = obj.value.other + sizeof(obj.value.other) - 1;
1320 }
ef416fc2 1321
b86bc4cf 1322 while (*cur)
1323 {
1324 if (strchr("()<>[]{}/%", *cur) || isspace(*cur & 255))
1325 break;
1326 else if (valptr < valend)
1327 *valptr++ = *cur++;
1328 else
1329 {
1330 *ptr = start;
1331 return (NULL);
1332 }
1333 }
1334
1335 if (obj.type == CUPS_PS_OTHER)
1336 {
1337 if (!strcmp(obj.value.other, "true"))
1338 {
1339 obj.type = CUPS_PS_BOOLEAN;
1340 obj.value.boolean = 1;
1341 }
1342 else if (!strcmp(obj.value.other, "false"))
1343 {
1344 obj.type = CUPS_PS_BOOLEAN;
1345 obj.value.boolean = 0;
1346 }
1347 else if (!strcmp(obj.value.other, "null"))
1348 obj.type = CUPS_PS_NULL;
1349 else if (!strcmp(obj.value.other, "cleartomark"))
1350 obj.type = CUPS_PS_CLEARTOMARK;
1351 else if (!strcmp(obj.value.other, "copy"))
1352 obj.type = CUPS_PS_COPY;
1353 else if (!strcmp(obj.value.other, "dup"))
1354 obj.type = CUPS_PS_DUP;
1355 else if (!strcmp(obj.value.other, "index"))
1356 obj.type = CUPS_PS_INDEX;
1357 else if (!strcmp(obj.value.other, "pop"))
1358 obj.type = CUPS_PS_POP;
1359 else if (!strcmp(obj.value.other, "roll"))
1360 obj.type = CUPS_PS_ROLL;
1361 else if (!strcmp(obj.value.other, "setpagedevice"))
1362 obj.type = CUPS_PS_SETPAGEDEVICE;
1363 else if (!strcmp(obj.value.other, "stopped"))
1364 obj.type = CUPS_PS_STOPPED;
1365 }
1366 break;
1367 }
1368
1369 /*
1370 * Save the current position in the string and return the new object...
1371 */
1372
1373 *ptr = cur;
1374
1375 return (push_stack(st, &obj));
1376}
1377
1378
1379/*
1380 * 'setpagedevice()' - Simulate the PostScript setpagedevice operator.
1381 */
1382
1383static int /* O - 0 on success, -1 on error */
1384setpagedevice(
1385 _cups_ps_stack_t *st, /* I - Stack */
1386 cups_page_header2_t *h, /* O - Page header */
1387 int *preferred_bits)/* O - Preferred bits per color */
1388{
1389 int i; /* Index into array */
1390 _cups_ps_obj_t *obj, /* Current object */
1391 *end; /* End of dictionary */
1392 const char *name; /* Attribute name */
1393
1394
1395 /*
1396 * Make sure we have a dictionary on the stack...
1397 */
1398
1399 if (st->num_objs == 0)
1400 return (-1);
1401
1402 obj = end = st->objs + st->num_objs - 1;
1403
1404 if (obj->type != CUPS_PS_END_DICT)
1405 return (-1);
1406
1407 obj --;
1408
1409 while (obj > st->objs)
1410 {
1411 if (obj->type == CUPS_PS_START_DICT)
1412 break;
1413
1414 obj --;
1415 }
1416
1417 if (obj < st->objs)
1418 return (-1);
ef416fc2 1419
b86bc4cf 1420 /*
1421 * Found the start of the dictionary, empty the stack to this point...
1422 */
1423
a2326b5b 1424 st->num_objs = (int)(obj - st->objs);
b86bc4cf 1425
1426 /*
1427 * Now pull /name and value pairs from the dictionary...
1428 */
1429
d9564ec7 1430 DEBUG_puts("3setpagedevice: Dictionary:");
b86bc4cf 1431
1432 for (obj ++; obj < end; obj ++)
1433 {
ef416fc2 1434 /*
b86bc4cf 1435 * Grab the name...
ef416fc2 1436 */
1437
b86bc4cf 1438 if (obj->type != CUPS_PS_NAME)
1439 return (-1);
1440
1441 name = obj->value.name;
1442 obj ++;
1443
1444#ifdef DEBUG
d9564ec7
MS
1445 DEBUG_printf(("4setpagedevice: /%s ", name));
1446 DEBUG_object("setpagedevice", obj);
b86bc4cf 1447#endif /* DEBUG */
1448
1449 /*
1450 * Then grab the value...
1451 */
1452
1453 if (!strcmp(name, "MediaClass") && obj->type == CUPS_PS_STRING)
1454 strlcpy(h->MediaClass, obj->value.string, sizeof(h->MediaClass));
1455 else if (!strcmp(name, "MediaColor") && obj->type == CUPS_PS_STRING)
1456 strlcpy(h->MediaColor, obj->value.string, sizeof(h->MediaColor));
1457 else if (!strcmp(name, "MediaType") && obj->type == CUPS_PS_STRING)
1458 strlcpy(h->MediaType, obj->value.string, sizeof(h->MediaType));
1459 else if (!strcmp(name, "OutputType") && obj->type == CUPS_PS_STRING)
1460 strlcpy(h->OutputType, obj->value.string, sizeof(h->OutputType));
1461 else if (!strcmp(name, "AdvanceDistance") && obj->type == CUPS_PS_NUMBER)
1462 h->AdvanceDistance = (unsigned)obj->value.number;
1463 else if (!strcmp(name, "AdvanceMedia") && obj->type == CUPS_PS_NUMBER)
1464 h->AdvanceMedia = (unsigned)obj->value.number;
1465 else if (!strcmp(name, "Collate") && obj->type == CUPS_PS_BOOLEAN)
1466 h->Collate = (unsigned)obj->value.boolean;
1467 else if (!strcmp(name, "CutMedia") && obj->type == CUPS_PS_NUMBER)
1468 h->CutMedia = (cups_cut_t)(unsigned)obj->value.number;
1469 else if (!strcmp(name, "Duplex") && obj->type == CUPS_PS_BOOLEAN)
1470 h->Duplex = (unsigned)obj->value.boolean;
1471 else if (!strcmp(name, "HWResolution") && obj->type == CUPS_PS_START_ARRAY)
ef416fc2 1472 {
b86bc4cf 1473 if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER &&
1474 obj[3].type == CUPS_PS_END_ARRAY)
1475 {
1476 h->HWResolution[0] = (unsigned)obj[1].value.number;
1477 h->HWResolution[1] = (unsigned)obj[2].value.number;
1478 obj += 3;
1479 }
1480 else
ef416fc2 1481 return (-1);
1482 }
b86bc4cf 1483 else if (!strcmp(name, "InsertSheet") && obj->type == CUPS_PS_BOOLEAN)
1484 h->InsertSheet = (unsigned)obj->value.boolean;
1485 else if (!strcmp(name, "Jog") && obj->type == CUPS_PS_NUMBER)
1486 h->Jog = (unsigned)obj->value.number;
1487 else if (!strcmp(name, "LeadingEdge") && obj->type == CUPS_PS_NUMBER)
1488 h->LeadingEdge = (unsigned)obj->value.number;
1489 else if (!strcmp(name, "ManualFeed") && obj->type == CUPS_PS_BOOLEAN)
1490 h->ManualFeed = (unsigned)obj->value.boolean;
09a101d6 1491 else if ((!strcmp(name, "cupsMediaPosition") ||
b86bc4cf 1492 !strcmp(name, "MediaPosition")) && obj->type == CUPS_PS_NUMBER)
09a101d6 1493 {
1494 /*
1495 * cupsMediaPosition is supported for backwards compatibility only.
1496 * We added it back in the Ghostscript 5.50 days to work around a
1497 * bug in Ghostscript WRT handling of MediaPosition and setpagedevice.
1498 *
1499 * All new development should set MediaPosition...
1500 */
1501
b86bc4cf 1502 h->MediaPosition = (unsigned)obj->value.number;
09a101d6 1503 }
b86bc4cf 1504 else if (!strcmp(name, "MediaWeight") && obj->type == CUPS_PS_NUMBER)
1505 h->MediaWeight = (unsigned)obj->value.number;
1506 else if (!strcmp(name, "MirrorPrint") && obj->type == CUPS_PS_BOOLEAN)
1507 h->MirrorPrint = (unsigned)obj->value.boolean;
1508 else if (!strcmp(name, "NegativePrint") && obj->type == CUPS_PS_BOOLEAN)
1509 h->NegativePrint = (unsigned)obj->value.boolean;
1510 else if (!strcmp(name, "NumCopies") && obj->type == CUPS_PS_NUMBER)
1511 h->NumCopies = (unsigned)obj->value.number;
1512 else if (!strcmp(name, "Orientation") && obj->type == CUPS_PS_NUMBER)
1513 h->Orientation = (unsigned)obj->value.number;
1514 else if (!strcmp(name, "OutputFaceUp") && obj->type == CUPS_PS_BOOLEAN)
1515 h->OutputFaceUp = (unsigned)obj->value.boolean;
1516 else if (!strcmp(name, "PageSize") && obj->type == CUPS_PS_START_ARRAY)
ef416fc2 1517 {
b86bc4cf 1518 if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER &&
1519 obj[3].type == CUPS_PS_END_ARRAY)
1520 {
c8fef167
MS
1521 h->cupsPageSize[0] = (float)obj[1].value.number;
1522 h->cupsPageSize[1] = (float)obj[2].value.number;
b86bc4cf 1523
1524 h->PageSize[0] = (unsigned)obj[1].value.number;
1525 h->PageSize[1] = (unsigned)obj[2].value.number;
1526
1527 obj += 3;
1528 }
1529 else
fa73b229 1530 return (-1);
ef416fc2 1531 }
b86bc4cf 1532 else if (!strcmp(name, "Separations") && obj->type == CUPS_PS_BOOLEAN)
1533 h->Separations = (unsigned)obj->value.boolean;
1534 else if (!strcmp(name, "TraySwitch") && obj->type == CUPS_PS_BOOLEAN)
1535 h->TraySwitch = (unsigned)obj->value.boolean;
1536 else if (!strcmp(name, "Tumble") && obj->type == CUPS_PS_BOOLEAN)
1537 h->Tumble = (unsigned)obj->value.boolean;
1538 else if (!strcmp(name, "cupsMediaType") && obj->type == CUPS_PS_NUMBER)
1539 h->cupsMediaType = (unsigned)obj->value.number;
1540 else if (!strcmp(name, "cupsBitsPerColor") && obj->type == CUPS_PS_NUMBER)
1541 h->cupsBitsPerColor = (unsigned)obj->value.number;
1542 else if (!strcmp(name, "cupsPreferredBitsPerColor") &&
1543 obj->type == CUPS_PS_NUMBER)
1544 *preferred_bits = (int)obj->value.number;
1545 else if (!strcmp(name, "cupsColorOrder") && obj->type == CUPS_PS_NUMBER)
1546 h->cupsColorOrder = (cups_order_t)(unsigned)obj->value.number;
1547 else if (!strcmp(name, "cupsColorSpace") && obj->type == CUPS_PS_NUMBER)
1548 h->cupsColorSpace = (cups_cspace_t)(unsigned)obj->value.number;
1549 else if (!strcmp(name, "cupsCompression") && obj->type == CUPS_PS_NUMBER)
1550 h->cupsCompression = (unsigned)obj->value.number;
1551 else if (!strcmp(name, "cupsRowCount") && obj->type == CUPS_PS_NUMBER)
1552 h->cupsRowCount = (unsigned)obj->value.number;
1553 else if (!strcmp(name, "cupsRowFeed") && obj->type == CUPS_PS_NUMBER)
1554 h->cupsRowFeed = (unsigned)obj->value.number;
1555 else if (!strcmp(name, "cupsRowStep") && obj->type == CUPS_PS_NUMBER)
1556 h->cupsRowStep = (unsigned)obj->value.number;
923edb68 1557 else if (!strcmp(name, "cupsBorderlessScalingFactor") &&
b86bc4cf 1558 obj->type == CUPS_PS_NUMBER)
c8fef167 1559 h->cupsBorderlessScalingFactor = (float)obj->value.number;
b86bc4cf 1560 else if (!strncmp(name, "cupsInteger", 11) && obj->type == CUPS_PS_NUMBER)
ef416fc2 1561 {
b86bc4cf 1562 if ((i = atoi(name + 11)) < 0 || i > 15)
ef416fc2 1563 return (-1);
1564
b86bc4cf 1565 h->cupsInteger[i] = (unsigned)obj->value.number;
ef416fc2 1566 }
b86bc4cf 1567 else if (!strncmp(name, "cupsReal", 8) && obj->type == CUPS_PS_NUMBER)
ef416fc2 1568 {
b86bc4cf 1569 if ((i = atoi(name + 8)) < 0 || i > 15)
ef416fc2 1570 return (-1);
1571
c8fef167 1572 h->cupsReal[i] = (float)obj->value.number;
ef416fc2 1573 }
b86bc4cf 1574 else if (!strncmp(name, "cupsString", 10) && obj->type == CUPS_PS_STRING)
ef416fc2 1575 {
b86bc4cf 1576 if ((i = atoi(name + 10)) < 0 || i > 15)
ef416fc2 1577 return (-1);
1578
b86bc4cf 1579 strlcpy(h->cupsString[i], obj->value.string, sizeof(h->cupsString[i]));
ef416fc2 1580 }
b86bc4cf 1581 else if (!strcmp(name, "cupsMarkerType") && obj->type == CUPS_PS_STRING)
1582 strlcpy(h->cupsMarkerType, obj->value.string, sizeof(h->cupsMarkerType));
1583 else if (!strcmp(name, "cupsPageSizeName") && obj->type == CUPS_PS_STRING)
1584 strlcpy(h->cupsPageSizeName, obj->value.string,
1585 sizeof(h->cupsPageSizeName));
1586 else if (!strcmp(name, "cupsRenderingIntent") &&
1587 obj->type == CUPS_PS_STRING)
1588 strlcpy(h->cupsRenderingIntent, obj->value.string,
1589 sizeof(h->cupsRenderingIntent));
1590 else
ef416fc2 1591 {
b86bc4cf 1592 /*
1593 * Ignore unknown name+value...
1594 */
1595
d9564ec7 1596 DEBUG_printf(("4setpagedevice: Unknown name (\"%s\") or value...\n", name));
b86bc4cf 1597
1598 while (obj[1].type != CUPS_PS_NAME && obj < end)
1599 obj ++;
ef416fc2 1600 }
ef416fc2 1601 }
1602
ef416fc2 1603 return (0);
1604}
1605
1606
b86bc4cf 1607#ifdef DEBUG
1608/*
1609 * 'DEBUG_object()' - Print an object's value...
1610 */
1611
1612static void
d9564ec7
MS
1613DEBUG_object(const char *prefix, /* I - Prefix string */
1614 _cups_ps_obj_t *obj) /* I - Object to print */
b86bc4cf 1615{
1616 switch (obj->type)
1617 {
1618 case CUPS_PS_NAME :
d9564ec7 1619 DEBUG_printf(("4%s: /%s\n", prefix, obj->value.name));
b86bc4cf 1620 break;
1621
1622 case CUPS_PS_NUMBER :
d9564ec7 1623 DEBUG_printf(("4%s: %g\n", prefix, obj->value.number));
b86bc4cf 1624 break;
1625
1626 case CUPS_PS_STRING :
d9564ec7 1627 DEBUG_printf(("4%s: (%s)\n", prefix, obj->value.string));
b86bc4cf 1628 break;
1629
1630 case CUPS_PS_BOOLEAN :
1631 if (obj->value.boolean)
d9564ec7 1632 DEBUG_printf(("4%s: true", prefix));
b86bc4cf 1633 else
d9564ec7 1634 DEBUG_printf(("4%s: false", prefix));
b86bc4cf 1635 break;
1636
1637 case CUPS_PS_NULL :
d9564ec7 1638 DEBUG_printf(("4%s: null", prefix));
b86bc4cf 1639 break;
1640
1641 case CUPS_PS_START_ARRAY :
d9564ec7 1642 DEBUG_printf(("4%s: [", prefix));
b86bc4cf 1643 break;
1644
1645 case CUPS_PS_END_ARRAY :
d9564ec7 1646 DEBUG_printf(("4%s: ]", prefix));
b86bc4cf 1647 break;
1648
1649 case CUPS_PS_START_DICT :
d9564ec7 1650 DEBUG_printf(("4%s: <<", prefix));
b86bc4cf 1651 break;
1652
1653 case CUPS_PS_END_DICT :
d9564ec7 1654 DEBUG_printf(("4%s: >>", prefix));
b86bc4cf 1655 break;
1656
1657 case CUPS_PS_START_PROC :
d9564ec7 1658 DEBUG_printf(("4%s: {", prefix));
b86bc4cf 1659 break;
1660
1661 case CUPS_PS_END_PROC :
d9564ec7 1662 DEBUG_printf(("4%s: }", prefix));
b86bc4cf 1663 break;
1664
1665 case CUPS_PS_CLEARTOMARK :
d9564ec7 1666 DEBUG_printf(("4%s: --cleartomark--", prefix));
b86bc4cf 1667 break;
1668
1669 case CUPS_PS_COPY :
d9564ec7 1670 DEBUG_printf(("4%s: --copy--", prefix));
b86bc4cf 1671 break;
1672
1673 case CUPS_PS_DUP :
d9564ec7 1674 DEBUG_printf(("4%s: --dup--", prefix));
b86bc4cf 1675 break;
1676
1677 case CUPS_PS_INDEX :
d9564ec7 1678 DEBUG_printf(("4%s: --index--", prefix));
b86bc4cf 1679 break;
1680
1681 case CUPS_PS_POP :
d9564ec7 1682 DEBUG_printf(("4%s: --pop--", prefix));
b86bc4cf 1683 break;
1684
1685 case CUPS_PS_ROLL :
d9564ec7 1686 DEBUG_printf(("4%s: --roll--", prefix));
b86bc4cf 1687 break;
1688
1689 case CUPS_PS_SETPAGEDEVICE :
d9564ec7 1690 DEBUG_printf(("4%s: --setpagedevice--", prefix));
b86bc4cf 1691 break;
1692
1693 case CUPS_PS_STOPPED :
d9564ec7 1694 DEBUG_printf(("4%s: --stopped--", prefix));
b86bc4cf 1695 break;
1696
1697 case CUPS_PS_OTHER :
d9564ec7 1698 DEBUG_printf(("4%s: --%s--", prefix, obj->value.other));
b86bc4cf 1699 break;
1700 }
1701}
1702
1703
1704/*
1705 * 'DEBUG_stack()' - Print a stack...
1706 */
1707
1708static void
d9564ec7
MS
1709DEBUG_stack(const char *prefix, /* I - Prefix string */
1710 _cups_ps_stack_t *st) /* I - Stack */
b86bc4cf 1711{
1712 int c; /* Looping var */
1713 _cups_ps_obj_t *obj; /* Current object on stack */
1714
1715
1716 for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++)
d9564ec7 1717 DEBUG_object(prefix, obj);
b86bc4cf 1718}
1719#endif /* DEBUG */