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