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