Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/gpdl/pwgtop.c
Line
Count
Source
1
/* Copyright (C) 2019-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* pwgtop.c */
17
/* Top-level API implementation of "PWG" Language Interface */
18
19
#include "pltop.h"
20
#include "gserrors.h"
21
#include "gxdevice.h"
22
#include "gsstate.h"
23
#include "strimpl.h"
24
#include "gscoord.h"
25
#include "gsicc_manage.h"
26
#include "gspaint.h"
27
#include "plmain.h"
28
#include "spwgx.h"
29
#include "stream.h"
30
31
/* Forward decls */
32
33
/************************************************************/
34
/******** Language wrapper implementation (see pltop.h) *****/
35
/************************************************************/
36
37
typedef enum
38
{
39
    ii_state_identifying = 0,
40
    ii_state_pwg,
41
    ii_state_pwg_header,
42
    ii_state_pwg_data,
43
    ii_state_flush
44
} ii_state;
45
46
/*
47
 * PWG interpreter instance
48
 */
49
typedef struct pwg_interp_instance_s {
50
    gs_memory_t       *memory;
51
    gx_device         *dev;
52
    gx_device         *nulldev;
53
54
    gs_color_space    *gray;
55
    gs_color_space    *rgb;
56
    gs_color_space    *cmyk;
57
58
    /* PWG parser state machine */
59
    ii_state           state;
60
61
    int                pages;
62
63
    uint32_t           bpc;
64
    uint32_t           bpp;
65
    uint32_t           bpl;
66
    uint32_t           colororder;
67
    uint32_t           cs;
68
    uint32_t           duplexMode;
69
    uint32_t           printQuality;
70
    uint32_t           mediaType;
71
    uint32_t           copies;
72
    uint32_t           width;
73
    uint32_t           height;
74
    uint32_t           xresolution;
75
    uint32_t           yresolution;
76
77
    uint32_t           num_comps;
78
    uint32_t           byte_width;
79
    uint32_t           x;
80
    uint32_t           y;
81
82
    gs_image_t         image;
83
    gs_image_enum     *penum;
84
    gs_gstate         *pgs;
85
86
    stream_PWGD_state  pwgd_state;
87
    byte               stream_buffer[2048];
88
89
} pwg_interp_instance_t;
90
91
static int
92
pwg_detect_language(const char *s, int len)
93
17.7k
{
94
    /* For postscript, we look for %! */
95
17.7k
    if (len >= 4) {
96
17.7k
        if (memcmp(s, "RaS2", 4) == 0)
97
0
            return 100;
98
17.7k
    }
99
100
17.7k
    return 0;
101
17.7k
}
102
103
static const pl_interp_characteristics_t pwg_characteristics = {
104
    "PWG",
105
    pwg_detect_language,
106
};
107
108
/* Get implementation's characteristics */
109
static const pl_interp_characteristics_t * /* always returns a descriptor */
110
pwg_impl_characteristics(const pl_interp_implementation_t *impl)     /* implementation of interpreter to alloc */
111
37.5k
{
112
37.5k
  return &pwg_characteristics;
113
37.5k
}
114
115
static void
116
pwg_deallocate(pwg_interp_instance_t *pwg)
117
8.09k
{
118
8.09k
    if (pwg == NULL)
119
0
        return;
120
121
8.09k
    rc_decrement_cs(pwg->gray, "pwg_deallocate");
122
8.09k
    rc_decrement_cs(pwg->rgb, "pwg_deallocate");
123
8.09k
    rc_decrement_cs(pwg->cmyk, "pwg_deallocate");
124
125
8.09k
    if (pwg->pgs != NULL)
126
8.09k
        gs_gstate_free_chain(pwg->pgs);
127
8.09k
    gs_free_object(pwg->memory, pwg, "pwg_impl_allocate_interp_instance");
128
8.09k
}
129
130
/* Deallocate a interpreter instance */
131
static int
132
pwg_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
133
8.09k
{
134
8.09k
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
135
136
8.09k
    pwg_deallocate(pwg);
137
8.09k
    impl->interp_client_data = NULL;
138
139
8.09k
    return 0;
140
8.09k
}
141
142
/* Do per-instance interpreter allocation/init. */
143
static int
144
pwg_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *mem)
145
8.09k
{
146
8.09k
    int code;
147
8.09k
    pwg_interp_instance_t *pwg
148
8.09k
        = (pwg_interp_instance_t *)gs_alloc_bytes(mem,
149
8.09k
                                                  sizeof(pwg_interp_instance_t),
150
8.09k
                                                  "pwg_impl_allocate_interp_instance");
151
8.09k
    if (!pwg)
152
0
        return_error(gs_error_VMerror);
153
8.09k
    memset(pwg, 0, sizeof(*pwg));
154
155
8.09k
    pwg->memory = mem;
156
8.09k
    pwg->pgs = gs_gstate_alloc(mem);
157
8.09k
    if (pwg->pgs == NULL)
158
0
        goto failVM;
159
160
    /* Push one save level onto the stack to assuage the memory handling */
161
8.09k
    code = gs_gsave(pwg->pgs);
162
8.09k
    if (code < 0)
163
0
        goto fail;
164
165
8.09k
    code = gsicc_init_iccmanager(pwg->pgs);
166
8.09k
    if (code < 0)
167
0
        goto fail;
168
169
8.09k
    pwg->gray = gs_cspace_new_ICC(mem, pwg->pgs, 1);
170
8.09k
    pwg->rgb  = gs_cspace_new_ICC(mem, pwg->pgs, 3);
171
8.09k
    pwg->cmyk = gs_cspace_new_ICC(mem, pwg->pgs, 4);
172
173
8.09k
    impl->interp_client_data = pwg;
174
175
8.09k
    return 0;
176
177
0
failVM:
178
0
    code = gs_note_error(gs_error_VMerror);
179
0
fail:
180
0
    (void)pwg_deallocate(pwg);
181
0
    return code;
182
0
}
183
184
/*
185
 * Get the allocator with which to allocate a device
186
 */
187
static gs_memory_t *
188
pwg_impl_get_device_memory(pl_interp_implementation_t *impl)
189
0
{
190
0
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
191
192
0
    return pwg->dev ? pwg->dev->memory : NULL;
193
0
}
194
195
#if 0 /* UNUSED */
196
static int
197
pwg_impl_set_param(pl_interp_implementation_t *impl,
198
                   pl_set_param_type           type,
199
                   const char                 *param,
200
                   const void                 *val)
201
{
202
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
203
204
    /* No params set here */
205
    return 0;
206
}
207
208
static int
209
pwg_impl_add_path(pl_interp_implementation_t *impl,
210
                  const char                 *path)
211
{
212
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
213
214
    /* No paths to add */
215
    return 0;
216
}
217
218
static int
219
pwg_impl_post_args_init(pl_interp_implementation_t *impl)
220
{
221
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
222
223
    /* No post args processing */
224
    return 0;
225
}
226
#endif
227
228
/* Prepare interp instance for the next "job" */
229
static int
230
pwg_impl_init_job(pl_interp_implementation_t *impl,
231
                  gx_device                  *device)
232
0
{
233
0
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
234
235
0
    pwg->dev = device;
236
0
    pwg->state = ii_state_identifying;
237
238
0
    return 0;
239
0
}
240
241
#if 0 /* UNUSED */
242
static int
243
pwg_impl_run_prefix_commands(pl_interp_implementation_t *impl,
244
                             const char                 *prefix)
245
{
246
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
247
248
    return 0;
249
}
250
251
static int
252
pwg_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
253
{
254
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
255
256
    return 0;
257
}
258
#endif
259
260
/* Do any setup for parser per-cursor */
261
static int                      /* ret 0 or +ve if ok, else -ve error code */
262
pwg_impl_process_begin(pl_interp_implementation_t * impl)
263
0
{
264
0
    return 0;
265
0
}
266
267
/* Ensure we have 'required' bytes to read, and further ensure
268
 * that we have no UEL's within those bytes. */
269
static int
270
ensure_bytes(pwg_interp_instance_t *pwg, stream_cursor_read *pr, int required)
271
0
{
272
0
    int n;
273
0
    const uint8_t *p = pr->ptr+1;
274
0
    const uint8_t *q;
275
0
    int avail;
276
277
    /* Find out how many bytes we need to check */
278
0
    n = pr->limit - pr->ptr;
279
0
    if (n > required)
280
0
        n = required;
281
282
    /* Make sure there are no UELs in that block */
283
0
    q = p + n;
284
0
    while (p != q) {
285
0
        while (p != q && *p != '\033')
286
0
            p++;
287
0
        if (p == q)
288
0
            break;
289
0
        avail = pr->limit - pr->ptr;
290
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
291
            /* At least a partial match to a UEL */
292
0
            return avail < 9 ? gs_error_NeedInput : gs_error_InterpreterExit;
293
0
        }
294
0
        p++;
295
0
    }
296
297
    /* If we have enough bytes, great, if not, get some more */
298
0
    return (n < required) ? gs_error_NeedInput : 0;
299
0
}
300
301
static int
302
flush_to_uel(stream_cursor_read *pr)
303
0
{
304
0
    const uint8_t *p = pr->ptr+1;
305
0
    const uint8_t *q = pr->limit+1;
306
0
    int avail;
307
308
0
    while (p != q) {
309
0
        while (p != q && *p != '\033')
310
0
            p++;
311
0
        if (p == q)
312
0
            break;
313
0
        avail = pr->limit - pr->ptr;
314
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
315
            /* At least a partial match to a UEL. Bin everything to
316
             * the start of the match. */
317
0
            pr->ptr = p-1;
318
0
            if (avail == 9) /* Complete match. Exit! */
319
0
                return gs_error_InterpreterExit;
320
            /* Partial match. Get more data. */
321
0
            return gs_error_NeedInput;
322
0
        }
323
0
        p++;
324
0
    }
325
326
0
    pr->ptr = pr->limit;
327
328
0
    return 0;
329
0
}
330
331
static int
332
bytes_until_uel(const stream_cursor_read *pr)
333
0
{
334
0
    const uint8_t *p = pr->ptr+1;
335
0
    const uint8_t *q = pr->limit+1;
336
0
    int avail;
337
338
0
    while (p != q) {
339
0
        while (p != q && *p != '\033')
340
0
            p++;
341
0
        if (p == q)
342
0
            break;
343
0
        avail = q - p;
344
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
345
            /* At least a partial match to a UEL. Everything up to
346
             * the start of the match is up for grabs. */
347
0
            return p - (pr->ptr+1);
348
0
        }
349
0
        p++;
350
0
    }
351
352
0
    return pr->limit - pr->ptr;
353
0
}
354
355
static int
356
get32be(stream_cursor_read *pr)
357
0
{
358
0
    int v = pr->ptr[1] << 24;
359
0
    v |= pr->ptr[2] << 16;
360
0
    v |= pr->ptr[3] << 8;
361
0
    v |= pr->ptr[4];
362
0
    pr->ptr += 4;
363
364
0
    return v;
365
0
}
366
367
static int
368
pwg_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
369
0
{
370
0
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
371
0
    int code = 0;
372
0
    gs_color_space *cs;
373
374
    /* Loop while we have bytes to read */
375
0
    while (pr->limit > pr->ptr)
376
0
    {
377
0
        switch(pwg->state)
378
0
        {
379
0
        case ii_state_identifying:
380
            /* Try and get us 4 bytes for "RaS2" */
381
0
            code = ensure_bytes(pwg, pr, 4);
382
0
            if (code < 0)
383
0
                return code;
384
0
            if (memcmp("RaS2", (const char *)pr->ptr+1, 4) == 0)
385
0
            {
386
0
                pr->ptr += 4;
387
0
                pwg->state = ii_state_pwg_header;
388
0
                break;
389
0
            }
390
0
            pwg->state = ii_state_flush;
391
0
            break;
392
0
        case ii_state_pwg_header:
393
            /* Try and get us 1796 bytes for the page header */
394
0
            code = ensure_bytes(pwg, pr, 1796);
395
0
            if (code < 0)
396
0
                return code;
397
0
      pr->ptr          += 64;            /* CString PwgRaster */
398
0
      pr->ptr          += 64;            /* CString MediaColor */
399
0
      pr->ptr          += 64;            /* CString MediaType */
400
0
      pr->ptr          += 64;            /* CString PrintContentOptimize */
401
0
      pr->ptr          += 1-(256-267);   /* Reserved */
402
0
            (void)get32be(pr);                 /* WhenEnum CutMedia */
403
0
            pwg->duplexMode   = !!get32be(pr); /* Boolean Duplex */
404
0
      pwg->xresolution  = get32be(pr);
405
0
      pwg->yresolution  = get32be(pr);
406
0
      pr->ptr          += 1-(284-299);   /* Reserved */
407
0
      (void)!!get32be(pr);               /* Boolean InsertSheet */
408
0
      (void)get32be(pr);                 /* WhenEnum Jog */
409
0
      (void)get32be(pr);                 /* EdgeEnum LeadingEdge FeedDirection */
410
0
      pr->ptr          += 1-(312-323);   /* Reserved */
411
0
      (void)get32be(pr);                 /* MediaPosition */
412
0
      (void)get32be(pr);                 /* MediaWeightMetric */
413
0
      pr->ptr          += 1-(332-339);   /* Reserved */
414
0
      pwg->copies       = get32be(pr);   /* NumCopies */
415
0
            if (pwg->copies == 0)
416
0
                pwg->copies = 1;
417
0
      (void)get32be(pr);                 /* OrientationEnum Orientation OrientationRequested */
418
0
      pr->ptr          += 1-(348-351);   /* Reserved */
419
0
      (void)get32be(pr);                 /* UnsignedInt PageSize */
420
0
      (void)get32be(pr);                 /* UnsignedInt PageSize */
421
0
      pr->ptr          += 1-(360-367);   /* Reserved */
422
0
      (void)!!get32be(pr);               /* Boolean Tumble */
423
0
            pwg->width        = get32be(pr);   /* Width */
424
0
            pwg->height       = get32be(pr);   /* Height */
425
0
      pr->ptr          += 1-(380-383);   /* Reserved */
426
0
            pwg->bpc          = get32be(pr);   /* Bits Per Color */
427
0
            pwg->bpp          = get32be(pr);   /* Bits Per Pixel */
428
0
            pwg->bpl          = get32be(pr);   /* Bytes Per Line */
429
0
      pwg->colororder   = get32be(pr);   /* ColorOrderEnum ColorOrder */
430
0
      pwg->cs           = get32be(pr);   /* ColorSpaceEnum ColorSpace */
431
0
      pr->ptr          += 1-(404-419);   /* Reserved */
432
0
      (void)get32be(pr);                 /* NumColors */
433
0
      pr->ptr          += 1-(424-451);   /* Reserved */
434
0
      (void)get32be(pr);                 /* TotalPageCount */
435
0
      (void)get32be(pr);                 /* CrossFeedTransform */
436
0
      (void)get32be(pr);                 /* FeedTransform */
437
0
      (void)get32be(pr);                 /* ImageBoxLeft */
438
0
      (void)get32be(pr);                 /* ImageBoxTop */
439
0
      (void)get32be(pr);                 /* ImageBoxRight */
440
0
      (void)get32be(pr);                 /* ImageBoxBottom */
441
0
      (void)get32be(pr);                 /* SrgbColor AlternatePrimary */
442
0
            pwg->printQuality = get32be(pr);   /* PrintQuality */
443
0
      pr->ptr          += 1-(488-507);   /* Reserved */
444
0
      (void)get32be(pr);                 /* VendorIdentifier */
445
0
      (void)get32be(pr);                 /* VendorLength */
446
0
      pr->ptr          += 1-(516-1603);  /* VendorData */
447
0
      pr->ptr          += 1-(1604-1667); /* Reserved */
448
0
      pr->ptr          += 1-(1668-1731); /* RenderingIntent */
449
0
      pr->ptr          += 1-(1732-1795); /* PageSizeName */
450
451
            /* Decode the header */
452
0
      if (pwg->colororder != 0)
453
0
        goto bad_header; /* 0 = chunky = only defined one so far */
454
455
0
            switch(pwg->cs) {
456
0
            case 3:  /* DeviceBlack */
457
0
            case 18: /* Sgray */
458
0
            case 48: /* Device1 (Device color, 1 colorant) */
459
0
                pwg->num_comps = 1;
460
0
                cs = pwg->gray;
461
0
                break;
462
0
            case 1:  /* DeviceRGB */
463
0
            case 19: /* sRGB */
464
0
            case 20: /* AdobeRGB */
465
0
                pwg->num_comps = 3;
466
0
                cs = pwg->rgb;
467
0
                break;
468
0
            case 6: /* DeviceCMYK */
469
0
                pwg->num_comps = 4;
470
0
                cs = pwg->cmyk;
471
0
                break;
472
0
            default:
473
0
                goto bad_header;
474
0
            }
475
0
            if (pwg->bpc != 8)
476
0
                goto bad_header;
477
0
            if (pwg->bpp != 8*pwg->num_comps && pwg->bpp != 16*pwg->num_comps) {
478
0
bad_header:
479
0
                pwg->state = ii_state_flush;
480
0
                break;
481
0
            }
482
0
            if (check_uint32_multiply(pwg->width, (pwg->bpp>>3), &pwg->byte_width) != 0)
483
0
                goto bad_header;
484
0
            if (pwg->bpl != pwg->byte_width)
485
0
                goto bad_header;
486
487
0
            pwg->nulldev = gs_currentdevice(pwg->pgs);
488
0
            rc_increment(pwg->nulldev);
489
0
            code = gs_setdevice_no_erase(pwg->pgs, pwg->dev);
490
0
            if (code < 0)
491
0
                goto early_flush;
492
0
            gs_initmatrix(pwg->pgs);
493
494
            /* By default the ctm is set to:
495
             *   xres/72   0
496
             *   0         -yres/72
497
             *   0         dev->height * yres/72
498
             * i.e. it moves the origin from being top right to being bottom left.
499
             * We want to move it back, as without this, the image will be displayed
500
             * upside down.
501
             */
502
0
            code = gs_translate(pwg->pgs, 0.0, pwg->dev->height * 72 / pwg->dev->HWResolution[1]);
503
0
            if (code >= 0)
504
0
                code = gs_scale(pwg->pgs, 1, -1);
505
            /* At this point, the ctm is set to:
506
             *   xres/72  0
507
             *   0        yres/72
508
             *   0        0
509
             */
510
0
            if (code >= 0)
511
0
                code = gs_erasepage(pwg->pgs);
512
0
            if (code < 0)
513
0
                goto early_flush;
514
515
0
            memset(&pwg->image, 0, sizeof(pwg->image));
516
0
            gs_image_t_init(&pwg->image, cs);
517
0
            pwg->image.BitsPerComponent = pwg->bpp/pwg->num_comps;
518
0
            pwg->image.Width = pwg->width;
519
0
            pwg->image.Height = pwg->height;
520
521
0
            pwg->image.ImageMatrix.xx = pwg->xresolution / 72.0f;
522
0
            pwg->image.ImageMatrix.yy = pwg->yresolution / 72.0f;
523
524
0
            pwg->penum = gs_image_enum_alloc(pwg->memory, "pwg_impl_process(penum)");
525
0
            if (pwg->penum == NULL) {
526
0
                code = gs_note_error(gs_error_VMerror);
527
0
                goto early_flush;
528
0
            }
529
530
0
            code = gs_image_init(pwg->penum,
531
0
                                 &pwg->image,
532
0
                                 false,
533
0
                                 false,
534
0
                                 pwg->pgs);
535
0
            if (code < 0)
536
0
                goto early_flush;
537
538
0
            s_init_state((stream_state *)&pwg->pwgd_state, &s_PWGD_template, pwg->memory);
539
0
            if (s_PWGD_template.set_defaults)
540
0
                s_PWGD_template.set_defaults((stream_state *)&pwg->pwgd_state);
541
542
0
            pwg->pwgd_state.width = pwg->width;
543
0
            pwg->pwgd_state.bpp = pwg->bpp;
544
545
0
            code = (s_PWGD_template.init)((stream_state *)&pwg->pwgd_state);
546
0
            if (code < 0)
547
0
                goto early_flush;
548
0
            pwg->x = pwg->y = 0;
549
0
            pwg->state = ii_state_pwg_data;
550
0
            break;
551
0
        case ii_state_pwg_data:
552
0
        {
553
0
            int n = bytes_until_uel(pr);
554
0
            stream_cursor_read local_r;
555
0
            stream_cursor_write local_w;
556
0
            int status;
557
0
            unsigned int used;
558
0
            int decoded_any = 0;
559
560
0
            local_r.ptr = pr->ptr;
561
0
            local_r.limit = local_r.ptr + n;
562
563
0
            do {
564
0
                local_w.ptr = pwg->stream_buffer-1;
565
0
                local_w.limit = local_w.ptr + sizeof(pwg->stream_buffer);
566
567
0
                status = (s_PWGD_template.process)((stream_state *)&pwg->pwgd_state,
568
0
                                                                   &local_r, &local_w,
569
0
                                                                   true);
570
                /* status = 0 => need data
571
                 *          1 => need output space
572
                 * but we don't actually use this currently. */
573
0
                (void)status;
574
                /* Copy the updated pointer back */
575
0
                pr->ptr = local_r.ptr;
576
0
                if (local_w.ptr + 1 == pwg->stream_buffer)
577
0
                    break; /* Failed to decode any data */
578
0
                decoded_any = 1;
579
580
0
                code = gs_image_next(pwg->penum, pwg->stream_buffer, local_w.ptr + 1 - pwg->stream_buffer, &used);
581
0
                if (code < 0)
582
0
                    goto flush;
583
584
0
                pwg->x += used;
585
0
                while (pwg->x >= pwg->byte_width) {
586
0
                    pwg->x -= pwg->byte_width;
587
0
                    pwg->y++;
588
0
                }
589
                /* Loop while we haven't had all the lines, the decompression
590
                 * didn't ask for more data, and the decompression didn't give
591
                 * us more data. */
592
0
            } while (pwg->y < pwg->height);
593
594
0
            if (pwg->y == pwg->height) {
595
0
                code = gs_image_cleanup_and_free_enum(pwg->penum, pwg->pgs);
596
0
                pwg->penum = NULL;
597
0
                if (code < 0)
598
0
                    goto flush;
599
0
                code = pl_finish_page(pwg->memory->gs_lib_ctx->top_of_system,
600
0
                                      pwg->pgs, pwg->copies, true);
601
0
                if (code < 0)
602
0
                    goto flush;
603
0
                if (pwg->pages > 0) {
604
0
                    pwg->pages--;
605
                    /* If we've reached the expected end, we should probably flush to UEL */
606
0
                    if (pwg->pages == 0)
607
0
                        pwg->state = ii_state_flush;
608
0
                }
609
0
                if (pwg->pwgd_state.templat->release)
610
0
                    pwg->pwgd_state.templat->release((stream_state *)&pwg->pwgd_state);
611
0
                pwg->state = ii_state_pwg_header;
612
0
            } else if (decoded_any == 0) {
613
                /* Failed to make progress. Just give up to avoid livelocking. */
614
0
                goto flush;
615
0
            }
616
0
            break;
617
0
        }
618
0
        default:
619
0
        case ii_state_flush:
620
0
            if (0) {
621
0
flush:
622
0
                if (pwg->pwgd_state.templat->release)
623
0
                    pwg->pwgd_state.templat->release((stream_state *)&pwg->pwgd_state);
624
0
early_flush:
625
0
                pwg->state = ii_state_flush;
626
0
            }
627
            /* We want to bin any data we get up to, but not including
628
             * a UEL. */
629
0
            return flush_to_uel(pr);
630
0
        }
631
0
    }
632
633
0
    return code;
634
0
}
635
636
static int
637
pwg_impl_process_end(pl_interp_implementation_t * impl)
638
0
{
639
0
    return 0;
640
0
}
641
642
/* Not implemented */
643
static int
644
pwg_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
645
0
{
646
0
    const byte *p = cursor->ptr;
647
0
    const byte *rlimit = cursor->limit;
648
649
    /* Skip to, but leave UEL in buffer for PJL to find later */
650
0
    for (; p < rlimit; ++p)
651
0
        if (p[1] == '\033') {
652
0
            uint avail = rlimit - p;
653
654
0
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
655
0
                continue;
656
0
            if (avail < 9)
657
0
                break;
658
0
            cursor->ptr = p;
659
0
            return 1;           /* found eoj */
660
0
        }
661
0
    cursor->ptr = p;
662
0
    return 0;                   /* need more */
663
0
}
664
665
/* Parser action for end-of-file */
666
static int
667
pwg_impl_process_eof(pl_interp_implementation_t *impl)
668
0
{
669
0
    return 0;
670
0
}
671
672
/* Report any errors after running a job */
673
static int
674
pwg_impl_report_errors(pl_interp_implementation_t *impl,          /* interp instance to wrap up job in */
675
                       int                         code,          /* prev termination status */
676
                       long                        file_position, /* file position of error, -1 if unknown */
677
                       bool                        force_to_cout  /* force errors to cout */
678
)
679
0
{
680
0
    return 0;
681
0
}
682
683
/* Wrap up interp instance after a "job" */
684
static int
685
pwg_impl_dnit_job(pl_interp_implementation_t *impl)
686
0
{
687
0
    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
688
689
0
    if (pwg->nulldev) {
690
0
        int code = gs_setdevice(pwg->pgs, pwg->nulldev);
691
0
        pwg->dev = NULL;
692
0
        rc_decrement(pwg->nulldev, "pwg_impl_dnit_job(nulldevice)");
693
0
        pwg->nulldev = NULL;
694
0
        return code;
695
0
    }
696
0
    return 0;
697
0
}
698
699
/* Parser implementation descriptor */
700
const pl_interp_implementation_t pwg_implementation = {
701
  pwg_impl_characteristics,
702
  pwg_impl_allocate_interp_instance,
703
  pwg_impl_get_device_memory,
704
  NULL, /* pwg_impl_set_param */
705
  NULL, /* pwg_impl_add_path */
706
  NULL, /* pwg_impl_post_args_init */
707
  pwg_impl_init_job,
708
  NULL, /* pwg_impl_run_prefix_commands */
709
  NULL, /* pwg_impl_process_file */
710
  pwg_impl_process_begin,
711
  pwg_impl_process,
712
  pwg_impl_process_end,
713
  pwg_impl_flush_to_eoj,
714
  pwg_impl_process_eof,
715
  pwg_impl_report_errors,
716
  pwg_impl_dnit_job,
717
  pwg_impl_deallocate_interp_instance,
718
  NULL, /* pwg_impl_reset */
719
  NULL  /* interp_client_data */
720
};