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