Coverage Report

Created: 2025-08-26 06:18

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