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