Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/gpdl/pngtop.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
/* pngtop.c */
17
/* Top-level API implementation of "PNG" 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 "png_.h"
29
#include "setjmp_.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_png,
41
    ii_state_png_decode,
42
    ii_state_flush
43
} ii_state;
44
45
/*
46
 * Png interpreter instance
47
 */
48
typedef struct png_interp_instance_s {
49
    gs_memory_t       *memory;
50
    gs_memory_t       *cmemory;
51
    gx_device         *dev;
52
    gx_device         *nulldev;
53
54
    gs_color_space    *gray;
55
    gs_color_space    *rgb;
56
57
    /* Png parser state machine */
58
    ii_state           state;
59
60
    int                pages;
61
62
    uint8_t            bpp;
63
    uint8_t            cs;
64
    uint32_t           width;
65
    uint32_t           height;
66
    uint32_t           xresolution;
67
    uint32_t           yresolution;
68
    int                interlaced;
69
70
    uint32_t           num_comps;
71
    uint32_t           byte_width;
72
    uint32_t           y;
73
    uint32_t           passes;
74
75
    uint32_t           bytes_available_on_entry;
76
77
    gs_image_t         image;
78
    gs_image_enum     *penum;
79
    gs_gstate         *pgs;
80
81
    png_structp        png;
82
    png_infop          png_info;
83
    size_t             buffer_full;
84
    size_t             buffer_max;
85
    byte              *buffer;
86
    size_t             file_pos;
87
88
    byte              *samples;
89
90
} png_interp_instance_t;
91
92
static int
93
png_detect_language(const char *s, int len)
94
31.1k
{
95
31.1k
    const byte *hdr = (const byte *)s;
96
31.1k
    if (len >= 8) {
97
30.5k
        if (hdr[0] == 137 &&
98
2.76k
            hdr[1] == 80 &&
99
2.76k
            hdr[2] == 78 &&
100
2.75k
            hdr[3] == 71 &&
101
2.75k
            hdr[4] == 13 &&
102
2.75k
            hdr[5] == 10 &&
103
2.75k
            hdr[6] == 26 &&
104
2.75k
            hdr[7] == 10)
105
2.74k
            return 100;
106
30.5k
    }
107
108
28.4k
    return 0;
109
31.1k
}
110
111
static const pl_interp_characteristics_t png_characteristics = {
112
    "PNG",
113
    png_detect_language,
114
};
115
116
/* Get implementation's characteristics */
117
static const pl_interp_characteristics_t * /* always returns a descriptor */
118
png_impl_characteristics(const pl_interp_implementation_t *impl)     /* implementation of interpreter to alloc */
119
66.0k
{
120
66.0k
  return &png_characteristics;
121
66.0k
}
122
123
static void
124
png_deallocate(png_interp_instance_t *png)
125
16.0k
{
126
16.0k
    if (png == NULL)
127
0
        return;
128
129
16.0k
    rc_decrement_cs(png->gray, "png_deallocate");
130
16.0k
    rc_decrement_cs(png->rgb, "png_deallocate");
131
132
16.0k
    if (png->pgs != NULL)
133
16.0k
        gs_gstate_free_chain(png->pgs);
134
16.0k
    gs_free_object(png->memory, png, "png_impl_allocate_interp_instance");
135
16.0k
}
136
137
/* Deallocate a interpreter instance */
138
static int
139
png_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
140
16.0k
{
141
16.0k
    png_interp_instance_t *png = (png_interp_instance_t *)impl->interp_client_data;
142
143
16.0k
    png_deallocate(png);
144
16.0k
    impl->interp_client_data = NULL;
145
146
16.0k
    return 0;
147
16.0k
}
148
149
/* Do per-instance interpreter allocation/init. */
150
static int
151
png_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *mem)
152
16.0k
{
153
16.0k
    int code;
154
16.0k
    png_interp_instance_t *png
155
16.0k
        = (png_interp_instance_t *)gs_alloc_bytes(mem,
156
16.0k
                                                  sizeof(png_interp_instance_t),
157
16.0k
                                                  "png_impl_allocate_interp_instance");
158
16.0k
    if (!png)
159
0
        return_error(gs_error_VMerror);
160
16.0k
    memset(png, 0, sizeof(*png));
161
162
16.0k
    png->memory = mem;
163
16.0k
    png->pgs = gs_gstate_alloc(mem);
164
16.0k
    if (png->pgs == NULL)
165
0
        goto failVM;
166
167
    /* Push one save level onto the stack to assuage the memory handling */
168
16.0k
    code = gs_gsave(png->pgs);
169
16.0k
    if (code < 0)
170
0
        goto fail;
171
172
16.0k
    code = gsicc_init_iccmanager(png->pgs);
173
16.0k
    if (code < 0)
174
0
        goto fail;
175
176
16.0k
    png->gray = gs_cspace_new_ICC(mem, png->pgs, 1);
177
16.0k
    png->rgb  = gs_cspace_new_ICC(mem, png->pgs, 3);
178
179
16.0k
    impl->interp_client_data = png;
180
181
16.0k
    return 0;
182
183
0
failVM:
184
0
    code = gs_note_error(gs_error_VMerror);
185
0
fail:
186
0
    (void)png_deallocate(png);
187
0
    return code;
188
0
}
189
190
/*
191
 * Get the allocator with which to allocate a device
192
 */
193
static gs_memory_t *
194
png_impl_get_device_memory(pl_interp_implementation_t *impl)
195
0
{
196
0
    png_interp_instance_t *png = (png_interp_instance_t *)impl->interp_client_data;
197
198
0
    return png->dev ? png->dev->memory : NULL;
199
0
}
200
201
/* Prepare interp instance for the next "job" */
202
static int
203
png_impl_init_job(pl_interp_implementation_t *impl,
204
                  gx_device                  *device)
205
2.74k
{
206
2.74k
    png_interp_instance_t *png = (png_interp_instance_t *)impl->interp_client_data;
207
208
2.74k
    png->dev = device;
209
2.74k
    png->state = ii_state_identifying;
210
211
2.74k
    return 0;
212
2.74k
}
213
214
/* Do any setup for parser per-cursor */
215
static int                      /* ret 0 or +ve if ok, else -ve error code */
216
png_impl_process_begin(pl_interp_implementation_t * impl)
217
2.74k
{
218
2.74k
    return 0;
219
2.74k
}
220
221
/* Ensure we have 'required' bytes to read, and further ensure
222
 * that we have no UEL's within those bytes. */
223
static int
224
ensure_bytes(png_interp_instance_t *png, stream_cursor_read *pr, int required)
225
2.74k
{
226
2.74k
    int n;
227
2.74k
    const uint8_t *p = pr->ptr+1;
228
2.74k
    const uint8_t *q;
229
2.74k
    int avail;
230
231
    /* Find out how many bytes we need to check */
232
2.74k
    n = pr->limit - pr->ptr;
233
2.74k
    if (n > required)
234
2.74k
        n = required;
235
236
    /* Make sure there are no UELs in that block */
237
2.74k
    q = p + n;
238
2.74k
    while (p != q) {
239
24.7k
        while (p != q && *p != '\033')
240
21.9k
            p++;
241
2.74k
        if (p == q)
242
2.74k
            break;
243
0
        avail = pr->limit - pr->ptr;
244
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
245
            /* At least a partial match to a UEL */
246
0
            return avail < 9 ? gs_error_NeedInput : gs_error_InterpreterExit;
247
0
        }
248
0
        p++;
249
0
    }
250
251
    /* If we have enough bytes, great, if not, get some more */
252
2.74k
    return (n < required) ? gs_error_NeedInput : 0;
253
2.74k
}
254
255
static int
256
flush_to_uel(stream_cursor_read *pr)
257
2.74k
{
258
2.74k
    const uint8_t *p = pr->ptr+1;
259
2.74k
    const uint8_t *q = pr->limit+1;
260
2.74k
    int avail;
261
262
2.74k
    while (p != q) {
263
0
        while (p != q && *p != '\033')
264
0
            p++;
265
0
        if (p == q)
266
0
            break;
267
0
        avail = pr->limit - pr->ptr;
268
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
269
            /* At least a partial match to a UEL. Bin everything to
270
             * the start of the match. */
271
0
            pr->ptr = p-1;
272
0
            if (avail == 9) /* Complete match. Exit! */
273
0
                return gs_error_InterpreterExit;
274
            /* Partial match. Get more data. */
275
0
            return gs_error_NeedInput;
276
0
        }
277
0
        p++;
278
0
    }
279
280
2.74k
    pr->ptr = pr->limit;
281
282
2.74k
    return 0;
283
2.74k
}
284
285
static int
286
bytes_until_uel(const stream_cursor_read *pr)
287
11.2k
{
288
11.2k
    const uint8_t *p = pr->ptr+1;
289
11.2k
    const uint8_t *q = pr->limit+1;
290
11.2k
    int avail;
291
292
17.6k
    while (p != q) {
293
3.93M
        while (p != q && *p != '\033')
294
3.92M
            p++;
295
10.6k
        if (p == q)
296
4.22k
            break;
297
6.41k
        avail = q - p;
298
6.41k
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
299
            /* At least a partial match to a UEL. Everything up to
300
             * the start of the match is up for grabs. */
301
19
            return p - (pr->ptr+1);
302
19
        }
303
6.39k
        p++;
304
6.39k
    }
305
306
11.2k
    return pr->limit - pr->ptr;
307
11.2k
}
308
309
OPTIMIZE_SETJMP
310
static void
311
my_png_error(png_structp png_ptr, png_const_charp error_msg)
312
2.72k
{
313
    /* png_interp_instance_t *png = (png_interp_instance_t *)png_get_error_ptr(png_ptr); */
314
315
2.72k
    png_longjmp(png_ptr, 1);
316
2.72k
}
317
318
static void
319
my_png_warning(png_structp png_ptr, png_const_charp warning_msg)
320
99.2k
{
321
    /* png_interp_instance_t *png = (png_interp_instance_t *)png_get_error_ptr(png_ptr); */
322
99.2k
}
323
324
static png_voidp
325
my_png_malloc(png_structp png_ptr, png_alloc_size_t size)
326
136k
{
327
136k
    png_interp_instance_t *png = (png_interp_instance_t *)png_get_mem_ptr(png_ptr);
328
329
136k
    if (sizeof(void *) == 8) {
330
        /* gs_alloc_bytes returns blocks aligned to 8 on 64bit platforms.
331
         * PNG (on Windows at least) requires blocks aligned to 16. */
332
136k
        unsigned char *block = gs_alloc_bytes(png->memory, size+16, "my_png_malloc");
333
136k
        intptr_t num_bytes_padded;
334
335
136k
        if (block == NULL)
336
0
            return NULL;
337
136k
        num_bytes_padded = 16-(((intptr_t)block) & 15);
338
136k
        block += num_bytes_padded;
339
136k
        block[-1] = num_bytes_padded;
340
341
136k
        return block;
342
136k
    }
343
0
    return gs_alloc_bytes(png->memory, size, "my_png_malloc");
344
136k
}
345
346
static void
347
my_png_free(png_structp png_ptr, png_voidp ptr)
348
136k
{
349
136k
    png_interp_instance_t *png = (png_interp_instance_t *)png_get_mem_ptr(png_ptr);
350
351
136k
    if (sizeof(void *) == 8) {
352
136k
        unsigned char *block = ptr;
353
136k
        if (block == NULL)
354
0
            return;
355
136k
        block -= block[-1];
356
136k
        ptr = (void *)block;
357
136k
    }
358
136k
    gs_free_object(png->memory, ptr, "my_png_free");
359
136k
}
360
361
static void
362
my_png_read(png_structp png_ptr, png_bytep data, png_size_t length)
363
270k
{
364
270k
    png_interp_instance_t *png = (png_interp_instance_t *)png_get_io_ptr(png_ptr);
365
270k
    if (length + png->file_pos > png->buffer_full)
366
2.43k
        png_error(png_ptr, "Overread!");
367
368
268k
    memcpy(data, &png->buffer[png->file_pos], length);
369
268k
    png->file_pos += length;
370
268k
}
371
372
OPTIMIZE_SETJMP
373
static int
374
do_impl_process(png_interp_instance_t *png, stream_cursor_read * pr, bool eof)
375
7.03k
{
376
7.03k
    int code = 0, bytes;
377
7.03k
    ii_state ostate;
378
7.03k
    size_t bytes_in;
379
7.03k
    int advanced;
380
381
    /* Loop until we stop 'advancing'. */
382
7.03k
    do
383
19.4k
    {
384
19.4k
        ostate = png->state;
385
19.4k
        bytes_in = pr->limit - pr->ptr;
386
19.4k
        advanced = 0;
387
19.4k
        switch(png->state)
388
19.4k
        {
389
2.74k
        case ii_state_identifying:
390
2.74k
        {
391
2.74k
            const byte *hdr;
392
            /* Try and get us 8 bytes */
393
2.74k
            code = ensure_bytes(png, pr, 8);
394
2.74k
            if (code < 0)
395
0
                return code;
396
2.74k
            hdr = pr->ptr+1;
397
2.74k
            if (hdr[0] == 137 &&
398
2.74k
                hdr[1] == 80 &&
399
2.74k
                hdr[2] == 78 &&
400
2.74k
                hdr[3] == 71 &&
401
2.74k
                hdr[4] == 13 &&
402
2.74k
                hdr[5] == 10 &&
403
2.74k
                hdr[6] == 26 &&
404
2.74k
                hdr[7] == 10) {
405
2.74k
                png->state = ii_state_png;
406
2.74k
                break;
407
2.74k
            }
408
0
            png->state = ii_state_flush;
409
0
            break;
410
2.74k
        }
411
11.2k
        case ii_state_png:
412
11.2k
        {
413
            /* Gather data into a buffer */
414
11.2k
            bytes = bytes_until_uel(pr);
415
416
11.2k
            if (bytes == 0 && pr->limit - pr->ptr > 9) {
417
                /* No bytes until UEL, and there is space for a UEL in the buffer */
418
0
                png->state = ii_state_png_decode;
419
0
                png->file_pos = 0;
420
0
                break;
421
0
            }
422
11.2k
            if (bytes == 0 && eof) {
423
                /* No bytes until UEL, and we are at eof */
424
2.74k
                png->state = ii_state_png_decode;
425
2.74k
                png->file_pos = 0;
426
2.74k
                break;
427
2.74k
            }
428
429
8.51k
            if (png->buffer_full + bytes > png->buffer_max) {
430
                /* Need to expand our buffer */
431
2.76k
                size_t proposed = png->buffer_full*2;
432
2.76k
                if (proposed == 0)
433
2.74k
                    proposed = 32768;
434
2.76k
                while (proposed < png->buffer_full + bytes)
435
0
                    proposed *= 2;
436
437
2.76k
                if (png->buffer == NULL) {
438
2.74k
                    png->buffer = gs_alloc_bytes(png->memory, proposed, "png_buffer");
439
2.74k
                    if (png->buffer == NULL) {
440
0
                        png->state = ii_state_flush;
441
0
                        break;
442
0
                    }
443
2.74k
                } else {
444
21
                    void *new_buf = gs_resize_object(png->memory, png->buffer, proposed, "png_buffer");
445
21
                    if (new_buf == NULL) {
446
0
                        png->state = ii_state_flush;
447
0
                        break;
448
0
                    }
449
21
                    png->buffer = new_buf;
450
21
                }
451
2.76k
                png->buffer_max = proposed;
452
2.76k
            }
453
454
8.51k
            memcpy(&png->buffer[png->buffer_full], pr->ptr+1, bytes);
455
8.51k
            png->buffer_full += bytes;
456
8.51k
            pr->ptr += bytes;
457
8.51k
            break;
458
8.51k
        }
459
2.74k
        case ii_state_png_decode:
460
2.74k
        {
461
2.74k
            gs_color_space *cs;
462
2.74k
            float scale, xext, yext, xoffset, yoffset;
463
464
2.74k
            png->png = png_create_read_struct_2(
465
2.74k
                               PNG_LIBPNG_VER_STRING,
466
2.74k
                               (png_voidp)png,
467
2.74k
                               my_png_error,
468
2.74k
                               my_png_warning,
469
2.74k
                               (png_voidp)png,
470
2.74k
                               my_png_malloc,
471
2.74k
                               my_png_free);
472
2.74k
            if (png->png == NULL) {
473
0
                png->state = ii_state_flush;
474
0
                break;
475
0
            }
476
477
2.74k
            png->png_info = png_create_info_struct(png->png);
478
2.74k
            if (!png->png_info) {
479
0
                png->state = ii_state_flush;
480
0
                break;
481
0
            }
482
483
2.74k
            png_set_read_fn(png->png, png, my_png_read);
484
2.74k
            png_set_alpha_mode(png->png, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
485
486
2.74k
            if (setjmp(png_jmpbuf(png->png))) {
487
2.72k
                png->state = ii_state_flush;
488
2.72k
                break;
489
2.72k
            }
490
491
            /* We use the "low level" interface to libpng to allow us to
492
             * optimise memory usage. Any errors will longjmp. */
493
21
            png_read_info(png->png, png->png_info);
494
495
21
            png_set_expand_16(png->png);
496
21
            png_set_alpha_mode(png->png, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);
497
21
            {
498
21
                int bpc, color;
499
21
                static const png_color_16 bg = { 0, 65535, 65535, 65535, 65535 };
500
21
                png_get_IHDR(png->png, png->png_info,
501
21
                             &png->width,
502
21
                             &png->height,
503
21
                             &bpc,
504
21
                             &color,
505
21
                             &png->interlaced,
506
21
                             NULL /* compression */,
507
21
                             NULL /* filter */);
508
21
                switch (color) {
509
64
                case PNG_COLOR_TYPE_GRAY_ALPHA:
510
248
                case PNG_COLOR_TYPE_GRAY:
511
248
                    png->num_comps = 1;
512
248
                    break;
513
53
                case PNG_COLOR_TYPE_PALETTE:
514
53
                    png_set_palette_to_rgb(png->png);
515
53
                    png->num_comps = 3;
516
53
                    break;
517
125
                case PNG_COLOR_TYPE_RGB:
518
189
                case PNG_COLOR_TYPE_RGB_ALPHA:
519
189
                    png->num_comps = 3;
520
189
                    break;
521
0
                default:
522
0
                    png->state = ii_state_flush;
523
0
                    png_longjmp(png->png, 1);
524
0
                    break;
525
21
                }
526
490
                png->passes = png_set_interlace_handling(png->png);
527
490
                png_set_background(png->png, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1);
528
490
            }
529
530
0
            png->xresolution = png_get_x_pixels_per_inch(png->png, png->png_info);
531
490
            png->yresolution = png_get_y_pixels_per_inch(png->png, png->png_info);
532
490
            if (png->xresolution == 0)
533
480
                png->xresolution = png->yresolution;
534
490
            if (png->yresolution == 0)
535
480
                png->yresolution = png->xresolution;
536
490
            if (png->xresolution == 0)
537
480
                png->xresolution = png->yresolution = 72;
538
539
490
            cs = (png->num_comps == 1 ? png->gray : png->rgb);
540
541
            /* Read the updated info */
542
490
            png_read_update_info(png->png, png->png_info);
543
490
            png->bpp = png_get_bit_depth(png->png, png->png_info) * png->num_comps;
544
545
            /* Scale to fit, if too large. */
546
490
            scale = 1.0f;
547
490
            if (png->width * png->dev->HWResolution[0] > png->dev->width * png->xresolution)
548
26
                scale = ((float)png->dev->width * png->xresolution) / (png->width * png->dev->HWResolution[0]);
549
490
            if (scale * png->height * png->dev->HWResolution[1] > png->dev->height * png->yresolution)
550
9
                scale = ((float)png->dev->height * png->yresolution) / (png->height * png->dev->HWResolution[1]);
551
552
            /* Centre - Extents and offsets are all calculated in points (1/72 of an inch) */
553
490
            xext = ((float)png->width * 72 * scale / png->xresolution);
554
490
            xoffset = (png->dev->width * 72 / png->dev->HWResolution[0] - xext)/2;
555
490
            yext = ((float)png->height * 72 * scale / png->yresolution);
556
490
            yoffset = (png->dev->height * 72 / png->dev->HWResolution[1] - yext)/2;
557
558
            /* Now we've got the data from the image header, we can
559
             * make the gs image instance */
560
490
            png->byte_width = png_get_rowbytes(png->png, png->png_info);
561
562
490
            png->nulldev = gs_currentdevice(png->pgs);
563
490
            rc_increment(png->nulldev);
564
490
            code = gs_setdevice_no_erase(png->pgs, png->dev);
565
490
            if (code < 0) {
566
0
                png->state = ii_state_flush;
567
0
                break;
568
0
            }
569
490
            gs_initmatrix(png->pgs);
570
571
            /* By default the ctm is set to:
572
             *   xres/72   0
573
             *   0         -yres/72
574
             *   0         dev->height * yres/72
575
             * i.e. it moves the origin from being top right to being bottom left.
576
             * We want to move it back, as without this, the image will be displayed
577
             * upside down.
578
             */
579
490
            code = gs_translate(png->pgs, 0.0, png->dev->height * 72 / png->dev->HWResolution[1]);
580
490
            if (code >= 0)
581
490
                code = gs_translate(png->pgs, xoffset, -yoffset);
582
490
            if (code >= 0)
583
490
                code = gs_scale(png->pgs, scale, -scale);
584
            /* At this point, the ctm is set to:
585
             *   xres/72  0
586
             *   0        yres/72
587
             *   0        0
588
             */
589
490
            if (code >= 0)
590
490
                code = gs_erasepage(png->pgs);
591
490
            if (code < 0) {
592
0
                png->state = ii_state_flush;
593
0
                break;
594
0
            }
595
596
490
            if (SIZE_MAX / png->byte_width < (png->interlaced ? png->height : 1))
597
0
            {
598
0
                code = gs_note_error(gs_error_VMerror);
599
0
                png->state = ii_state_flush;
600
0
                break;
601
0
            }
602
603
490
            png->samples = gs_alloc_bytes(png->memory,
604
490
                                          (size_t)png->byte_width * (png->interlaced ? png->height : 1),
605
490
                                          "png_impl_process(samples)");
606
490
            if (png->samples == NULL) {
607
0
                png->state = ii_state_flush;
608
0
                break;
609
0
            }
610
611
490
            memset(&png->image, 0, sizeof(png->image));
612
490
            gs_image_t_init(&png->image, cs);
613
490
            png->image.BitsPerComponent = png->bpp/png->num_comps;
614
490
            png->image.Width = png->width;
615
490
            png->image.Height = png->height;
616
617
490
            png->image.ImageMatrix.xx = png->xresolution / 72.0f;
618
490
            png->image.ImageMatrix.yy = png->yresolution / 72.0f;
619
620
490
            png->penum = gs_image_enum_alloc(png->memory, "png_impl_process(penum)");
621
490
            if (png->penum == NULL) {
622
0
                code = gs_note_error(gs_error_VMerror);
623
0
                png->state = ii_state_flush;
624
0
                return code;
625
0
            }
626
627
490
            code = gs_image_init(png->penum,
628
490
                                 &png->image,
629
490
                                 false,
630
490
                                 false,
631
490
                                 png->pgs);
632
490
            if (code < 0) {
633
0
                png->state = ii_state_flush;
634
0
                return code;
635
0
            }
636
637
490
            {
638
490
                int i, j;
639
640
490
                if (png->interlaced) {
641
                    /* Collect the results from all but the last pass */
642
962
                    for (j = png->passes-1; j > 0; j--)
643
20.4k
                        for (i = 0; i < png->height; i++)
644
19.7k
                            png_read_row(png->png, &png->samples[i*png->byte_width], NULL);
645
646
                    /* And actually process the last pass */
647
573
                    for (i = 0; i < png->height; i++) {
648
295
                        uint used;
649
650
295
                        png_read_row(png->png, &png->samples[i*png->byte_width], NULL);
651
652
295
                        code = gs_image_next(png->penum, &png->samples[i*png->byte_width], png->byte_width, &used);
653
295
                        if (code < 0) {
654
0
                            png->state = ii_state_flush;
655
0
                            break;
656
0
                        }
657
295
                    }
658
278
                } else {
659
8.93k
                    for (i = 0; i < png->height; i++) {
660
8.72k
                        uint used;
661
662
8.72k
                        png_read_row(png->png, png->samples, NULL);
663
664
8.72k
                        code = gs_image_next(png->penum, png->samples, png->byte_width, &used);
665
8.72k
                        if (code < 0) {
666
0
                            png->state = ii_state_flush;
667
0
                            break;
668
0
                        }
669
8.72k
                    }
670
212
                }
671
490
            }
672
673
490
            code = gs_image_cleanup_and_free_enum(png->penum, png->pgs);
674
490
            png->penum = NULL;
675
490
            if (code < 0) {
676
0
                png->state = ii_state_flush;
677
0
                break;
678
0
            }
679
490
            code = pl_finish_page(png->memory->gs_lib_ctx->top_of_system,
680
490
                                  png->pgs, 1, true);
681
490
            if (code < 0) {
682
0
                png->state = ii_state_flush;
683
0
                break;
684
0
            }
685
686
490
            png->state = ii_state_flush;
687
490
            break;
688
490
        }
689
0
        default:
690
2.74k
        case ii_state_flush:
691
2.74k
            if (png->png)
692
2.74k
            {
693
2.74k
                png_destroy_read_struct(&png->png, &png->png_info, NULL);
694
2.74k
                png->png = NULL;
695
2.74k
                png->png_info = NULL;
696
2.74k
            }
697
698
2.74k
            if (png->penum) {
699
469
                (void)gs_image_cleanup_and_free_enum(png->penum, png->pgs);
700
469
                png->penum = NULL;
701
469
            }
702
703
2.74k
            gs_free_object(png->memory, png->buffer, "png_impl_process(buffer)");
704
2.74k
            png->buffer = NULL;
705
2.74k
            gs_free_object(png->memory, png->samples, "png_impl_process(samples)");
706
2.74k
            png->samples = NULL;
707
            /* We want to bin any data we get up to, but not including
708
             * a UEL. */
709
2.74k
            return flush_to_uel(pr);
710
19.4k
        }
711
16.7k
        advanced |= (ostate != png->state);
712
16.7k
        advanced |= (bytes_in != pr->limit - pr->ptr);
713
16.7k
    } while (advanced);
714
715
4.29k
    if (!advanced && bytes == 0)
716
4.29k
        code = gs_note_error(gs_error_NeedInput);
717
718
4.29k
    return code;
719
7.03k
}
720
721
static int
722
png_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
723
4.29k
{
724
4.29k
    png_interp_instance_t *png = (png_interp_instance_t *)impl->interp_client_data;
725
726
4.29k
    return do_impl_process(png, pr, 0);
727
4.29k
}
728
729
static int
730
png_impl_process_end(pl_interp_implementation_t * impl)
731
2.74k
{
732
2.74k
    return 0;
733
2.74k
}
734
735
/* Not implemented */
736
static int
737
png_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
738
0
{
739
0
    const byte *p = cursor->ptr;
740
0
    const byte *rlimit = cursor->limit;
741
742
    /* Skip to, but leave UEL in buffer for PJL to find later */
743
0
    for (; p < rlimit; ++p)
744
0
        if (p[1] == '\033') {
745
0
            uint avail = rlimit - p;
746
747
0
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
748
0
                continue;
749
0
            if (avail < 9)
750
0
                break;
751
0
            cursor->ptr = p;
752
0
            return 1;           /* found eoj */
753
0
        }
754
0
    cursor->ptr = p;
755
0
    return 0;                   /* need more */
756
0
}
757
758
/* Parser action for end-of-file */
759
static int
760
png_impl_process_eof(pl_interp_implementation_t *impl)
761
2.74k
{
762
2.74k
    png_interp_instance_t *png = (png_interp_instance_t *)impl->interp_client_data;
763
2.74k
    stream_cursor_read cursor;
764
765
2.74k
    cursor.ptr = NULL;
766
2.74k
    cursor.limit = NULL;
767
768
2.74k
    return do_impl_process(png, &cursor, 1);
769
2.74k
}
770
771
/* Report any errors after running a job */
772
static int
773
png_impl_report_errors(pl_interp_implementation_t *impl,          /* interp instance to wrap up job in */
774
                       int                         code,          /* prev termination status */
775
                       long                        file_position, /* file position of error, -1 if unknown */
776
                       bool                        force_to_cout  /* force errors to cout */
777
)
778
0
{
779
0
    return 0;
780
0
}
781
782
/* Wrap up interp instance after a "job" */
783
static int
784
png_impl_dnit_job(pl_interp_implementation_t *impl)
785
2.74k
{
786
2.74k
    png_interp_instance_t *png = (png_interp_instance_t *)impl->interp_client_data;
787
788
2.74k
    if (png->nulldev) {
789
490
        int code = gs_setdevice(png->pgs, png->nulldev);
790
490
        png->dev = NULL;
791
490
        rc_decrement(png->nulldev, "png_impl_dnit_job(nulldevice)");
792
490
        png->nulldev = NULL;
793
490
        return code;
794
490
    }
795
2.25k
    return 0;
796
2.74k
}
797
798
/* Parser implementation descriptor */
799
const pl_interp_implementation_t png_implementation = {
800
  png_impl_characteristics,
801
  png_impl_allocate_interp_instance,
802
  png_impl_get_device_memory,
803
  NULL, /* png_impl_set_param */
804
  NULL, /* png_impl_add_path */
805
  NULL, /* png_impl_post_args_init */
806
  png_impl_init_job,
807
  NULL, /* png_impl_run_prefix_commands */
808
  NULL, /* png_impl_process_file */
809
  png_impl_process_begin,
810
  png_impl_process,
811
  png_impl_process_end,
812
  png_impl_flush_to_eoj,
813
  png_impl_process_eof,
814
  png_impl_report_errors,
815
  png_impl_dnit_job,
816
  png_impl_deallocate_interp_instance,
817
  NULL, /* png_impl_reset */
818
  NULL  /* interp_client_data */
819
};