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