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