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