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