Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/gpdl/jpgtop.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
/* jpgtop.c */
17
/* Top-level API implementation of "JPG" 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 "jpeglib.h"
29
#include "setjmp_.h"
30
#include "sjpeg.h"
31
32
/* Forward decls */
33
34
/************************************************************/
35
/******** Language wrapper implementation (see pltop.h) *****/
36
/************************************************************/
37
38
typedef enum
39
{
40
    ii_state_identifying = 0,
41
    ii_state_jpeg,
42
    ii_state_jpeg_header,
43
    ii_state_jpeg_start,
44
    ii_state_jpeg_rows,
45
    ii_state_jpeg_finish,
46
    ii_state_flush
47
} ii_state;
48
49
typedef struct {
50
    struct jpeg_error_mgr pub;
51
    jmp_buf *setjmp_buffer;
52
} jpg_error_mgr;
53
54
/*
55
 * Jpg interpreter instance
56
 */
57
typedef struct jpg_interp_instance_s {
58
    gs_memory_t       *memory;
59
    gs_memory_t       *cmemory;
60
    gx_device         *dev;
61
    gx_device         *nulldev;
62
63
    gs_color_space    *gray;
64
    gs_color_space    *rgb;
65
    gs_color_space    *cmyk;
66
67
    /* Jpg parser state machine */
68
    ii_state           state;
69
70
    int                pages;
71
72
    uint8_t            bpp;
73
    uint8_t            cs;
74
    uint32_t           width;
75
    uint32_t           height;
76
    uint32_t           xresolution;
77
    uint32_t           yresolution;
78
79
    uint32_t           num_comps;
80
    uint32_t           byte_width;
81
    uint32_t           y;
82
83
    uint32_t           bytes_available_on_entry;
84
85
    gs_image_t         image;
86
    gs_image_enum     *penum;
87
    gs_gstate         *pgs;
88
89
    struct jpeg_decompress_struct cinfo;
90
    struct jpeg_source_mgr        jsrc;
91
    size_t             bytes_to_skip;
92
    jpg_error_mgr      jerr;
93
94
    struct
95
    {
96
        jmp_buf setjmp_buffer;
97
        unsigned char pad[16];
98
    } aligned_jmpbuf;
99
100
101
    byte              *samples;
102
103
} jpg_interp_instance_t;
104
105
static int
106
jpg_detect_language(const char *s, int len)
107
31.1k
{
108
31.1k
    const byte *hdr = (const byte *)s;
109
31.1k
    if (len >= 11) {
110
30.3k
        if (hdr[0] == 0xFF && hdr[1] == 0xd8 && hdr[2] == 0xff && hdr[3] == 0xe0 &&
111
66
            strncmp("JFIF", s+6, 5) == 0)
112
55
            return 100;
113
30.3k
    }
114
115
31.1k
    return 0;
116
31.1k
}
117
118
static const pl_interp_characteristics_t jpg_characteristics = {
119
    "JPG",
120
    jpg_detect_language,
121
};
122
123
/* GS's fakakta jpeg integration insists on putting a
124
 * memory structure pointer in the decompress structs client data.
125
 * This is no good to find our instance from. We therefore find
126
 * it by offsetting back from the address of the cinfo. This is
127
 * a nasty bit of casting, so wrap it in a macro. */
128
#define JPG_FROM_CINFO(CINFO) \
129
96
    (jpg_interp_instance_t *)(((char *)(CINFO))-offsetof(jpg_interp_instance_t,cinfo))
130
131
132
/* Get implementation's characteristics */
133
static const pl_interp_characteristics_t * /* always returns a descriptor */
134
jpg_impl_characteristics(const pl_interp_implementation_t *impl)     /* implementation of interpreter to alloc */
135
66.0k
{
136
66.0k
  return &jpg_characteristics;
137
66.0k
}
138
139
static void
140
jpg_deallocate(jpg_interp_instance_t *jpg)
141
16.0k
{
142
16.0k
    if (jpg == NULL)
143
0
        return;
144
145
16.0k
    rc_decrement_cs(jpg->gray, "jpg_deallocate");
146
16.0k
    rc_decrement_cs(jpg->rgb, "jpg_deallocate");
147
16.0k
    rc_decrement_cs(jpg->cmyk, "jpg_deallocate");
148
149
16.0k
    if (jpg->pgs != NULL)
150
16.0k
        gs_gstate_free_chain(jpg->pgs);
151
16.0k
    gs_free_object(jpg->memory, jpg, "jpg_impl_allocate_interp_instance");
152
16.0k
}
153
154
/* Deallocate a interpreter instance */
155
static int
156
jpg_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
157
16.0k
{
158
16.0k
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
159
160
16.0k
    jpg_deallocate(jpg);
161
16.0k
    impl->interp_client_data = NULL;
162
163
16.0k
    return 0;
164
16.0k
}
165
166
/* Do per-instance interpreter allocation/init. */
167
static int
168
jpg_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *mem)
169
16.0k
{
170
16.0k
    int code;
171
16.0k
    jpg_interp_instance_t *jpg
172
16.0k
        = (jpg_interp_instance_t *)gs_alloc_bytes(mem,
173
16.0k
                                                  sizeof(jpg_interp_instance_t),
174
16.0k
                                                  "jpg_impl_allocate_interp_instance");
175
16.0k
    if (!jpg)
176
0
        return_error(gs_error_VMerror);
177
16.0k
    memset(jpg, 0, sizeof(*jpg));
178
179
16.0k
    jpg->memory = mem;
180
16.0k
    jpg->pgs = gs_gstate_alloc(mem);
181
16.0k
    if (jpg->pgs == NULL)
182
0
        goto failVM;
183
184
    /* Push one save level onto the stack to assuage the memory handling */
185
16.0k
    code = gs_gsave(jpg->pgs);
186
16.0k
    if (code < 0)
187
0
        goto fail;
188
189
16.0k
    code = gsicc_init_iccmanager(jpg->pgs);
190
16.0k
    if (code < 0)
191
0
        goto fail;
192
193
16.0k
    jpg->gray = gs_cspace_new_ICC(mem, jpg->pgs, 1);
194
16.0k
    jpg->rgb  = gs_cspace_new_ICC(mem, jpg->pgs, 3);
195
16.0k
    jpg->cmyk = gs_cspace_new_ICC(mem, jpg->pgs, 4);
196
197
16.0k
    impl->interp_client_data = jpg;
198
199
16.0k
    return 0;
200
201
0
failVM:
202
0
    code = gs_note_error(gs_error_VMerror);
203
0
fail:
204
0
    (void)jpg_deallocate(jpg);
205
0
    return code;
206
0
}
207
208
/*
209
 * Get the allocator with which to allocate a device
210
 */
211
static gs_memory_t *
212
jpg_impl_get_device_memory(pl_interp_implementation_t *impl)
213
0
{
214
0
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
215
216
0
    return jpg->dev ? jpg->dev->memory : NULL;
217
0
}
218
219
#if 0 /* UNUSED */
220
static int
221
jpg_impl_set_param(pl_interp_implementation_t *impl,
222
                   pl_set_param_type           type,
223
                   const char                 *param,
224
                   const void                 *val)
225
{
226
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
227
228
    /* No params set here */
229
    return 0;
230
}
231
232
static int
233
jpg_impl_add_path(pl_interp_implementation_t *impl,
234
                  const char                 *path)
235
{
236
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
237
238
    /* No paths to add */
239
    return 0;
240
}
241
242
static int
243
jpg_impl_post_args_init(pl_interp_implementation_t *impl)
244
{
245
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
246
247
    /* No post args processing */
248
    return 0;
249
}
250
#endif
251
252
/* Prepare interp instance for the next "job" */
253
static int
254
jpg_impl_init_job(pl_interp_implementation_t *impl,
255
                  gx_device                  *device)
256
55
{
257
55
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
258
259
55
    jpg->dev = device;
260
55
    jpg->state = ii_state_identifying;
261
262
55
    return 0;
263
55
}
264
265
#if 0 /* UNUSED */
266
static int
267
jpg_impl_run_prefix_commands(pl_interp_implementation_t *impl,
268
                             const char                 *prefix)
269
{
270
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
271
272
    return 0;
273
}
274
275
static int
276
jpg_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
277
{
278
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
279
280
    return 0;
281
}
282
#endif
283
284
/* Do any setup for parser per-cursor */
285
static int                      /* ret 0 or +ve if ok, else -ve error code */
286
jpg_impl_process_begin(pl_interp_implementation_t * impl)
287
55
{
288
55
    return 0;
289
55
}
290
291
/* Ensure we have 'required' bytes to read, and further ensure
292
 * that we have no UEL's within those bytes. */
293
static int
294
ensure_bytes(jpg_interp_instance_t *jpg, stream_cursor_read *pr, int required)
295
55
{
296
55
    int n;
297
55
    const uint8_t *p = pr->ptr+1;
298
55
    const uint8_t *q;
299
55
    int avail;
300
301
    /* Find out how many bytes we need to check */
302
55
    n = pr->limit - pr->ptr;
303
55
    if (n > required)
304
55
        n = required;
305
306
    /* Make sure there are no UELs in that block */
307
55
    q = p + n;
308
55
    while (p != q) {
309
660
        while (p != q && *p != '\033')
310
605
            p++;
311
55
        if (p == q)
312
55
            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 */
316
0
            return avail < 9 ? gs_error_NeedInput : gs_error_InterpreterExit;
317
0
        }
318
0
        p++;
319
0
    }
320
321
    /* If we have enough bytes, great, if not, get some more */
322
55
    return (n < required) ? gs_error_NeedInput : 0;
323
55
}
324
325
static int
326
flush_to_uel(stream_cursor_read *pr)
327
58
{
328
58
    const uint8_t *p = pr->ptr+1;
329
58
    const uint8_t *q = pr->limit+1;
330
58
    int avail;
331
332
133
    while (p != q) {
333
54.8k
        while (p != q && *p != '\033')
334
54.7k
            p++;
335
122
        if (p == q)
336
47
            break;
337
75
        avail = pr->limit - pr->ptr;
338
75
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
339
            /* At least a partial match to a UEL. Bin everything to
340
             * the start of the match. */
341
0
            pr->ptr = p-1;
342
0
            if (avail == 9) /* Complete match. Exit! */
343
0
                return gs_error_InterpreterExit;
344
            /* Partial match. Get more data. */
345
0
            return gs_error_NeedInput;
346
0
        }
347
75
        p++;
348
75
    }
349
350
58
    pr->ptr = pr->limit;
351
352
58
    return 0;
353
58
}
354
355
static int
356
bytes_until_uel(const stream_cursor_read *pr)
357
1.83k
{
358
1.83k
    const uint8_t *p = pr->ptr+1;
359
1.83k
    const uint8_t *q = pr->limit+1;
360
1.83k
    int avail;
361
362
1.93k
    while (p != q) {
363
159k
        while (p != q && *p != '\033')
364
158k
            p++;
365
1.48k
        if (p == q)
366
1.37k
            break;
367
106
        avail = q - p;
368
106
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
369
            /* At least a partial match to a UEL. Everything up to
370
             * the start of the match is up for grabs. */
371
0
            return p - (pr->ptr+1);
372
0
        }
373
106
        p++;
374
106
    }
375
376
1.83k
    return pr->limit - pr->ptr;
377
1.83k
}
378
379
static void
380
jpg_jpeg_init_source(j_decompress_ptr cinfo)
381
55
{
382
    /* We've already inited the source */
383
55
}
384
385
static boolean
386
jpg_fill_input_buffer(j_decompress_ptr cinfo)
387
85
{
388
85
    return FALSE; /* We've filled the buffer already */
389
85
}
390
391
static void
392
jpg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
393
96
{
394
96
    jpg_interp_instance_t *jpg = JPG_FROM_CINFO(cinfo);
395
96
    size_t n = cinfo->src->bytes_in_buffer;
396
397
96
    if (n > num_bytes)
398
68
        n = num_bytes;
399
96
    jpg->jsrc.next_input_byte += num_bytes;
400
96
    jpg->jsrc.bytes_in_buffer -= n;
401
96
}
402
403
static boolean
404
jpg_resync_to_restart(j_decompress_ptr cinfo, int desired)
405
0
{
406
0
    return FALSE;
407
0
}
408
409
static void
410
jpg_term_source(j_decompress_ptr cinfo)
411
23
{
412
23
}
413
414
OPTIMIZE_SETJMP
415
static void
416
jpg_error_exit(j_common_ptr cinfo)
417
11
{
418
11
    jpg_error_mgr *jerr = (jpg_error_mgr *)cinfo->err;
419
420
11
    longjmp(*jerr->setjmp_buffer, 1);
421
11
}
422
423
static int
424
fill_jpeg_source(jpg_interp_instance_t *jpg, stream_cursor_read * pr)
425
1.83k
{
426
1.83k
    size_t n = bytes_until_uel(pr);
427
1.83k
    size_t skip = jpg->bytes_to_skip;
428
429
    /* Skip any bytes we are supposed to be skipping. */
430
1.83k
    if (skip > 0) {
431
49
        if (skip > n)
432
34
            skip = n;
433
49
        pr->ptr += skip;
434
49
        n -= skip;
435
49
        jpg->bytes_to_skip -= skip;
436
49
        if (jpg->bytes_to_skip != 0)
437
34
            return 1; /* Still more to skip */
438
49
    }
439
440
    /* Set up for the call into the jpeg lib */
441
1.79k
    jpg->jsrc.next_input_byte = pr->ptr+1;
442
1.79k
    jpg->jsrc.bytes_in_buffer = pr->limit - pr->ptr;
443
1.79k
    jpg->bytes_available_on_entry = jpg->jsrc.bytes_in_buffer;
444
445
1.79k
    return 0;
446
1.83k
}
447
448
static int
449
consume_jpeg_data(jpg_interp_instance_t *jpg, stream_cursor_read *pr)
450
1.78k
{
451
1.78k
    size_t bytes_read = jpg->jsrc.next_input_byte - (pr->ptr+1);
452
1.78k
    size_t n = pr->limit - pr->ptr;
453
454
1.78k
    if (n > bytes_read)
455
1.31k
        n = bytes_read;
456
1.78k
    pr->ptr += n;
457
1.78k
    bytes_read -= n;
458
459
    /* We need to skip the next bytes_read bytes */
460
1.78k
    jpg->bytes_to_skip = bytes_read;
461
462
1.78k
    return (pr->limit - pr->ptr == jpg->bytes_available_on_entry);
463
1.78k
}
464
465
/* Horrible hack. Windows appears to expect the jmpbuf to be 16 byte
466
 * aligned. Most 64bit platforms appear to return blocks from malloc
467
 * that are aligned to 16 byte boundaries. Our malloc routines only
468
 * return things to be 8 byte aligned on 64bit platforms, so we may
469
 * fail. Accordingly, we allocate the jmpbuf in a larger structure,
470
 * and align it.
471
 *
472
 * This is only a calculation we have to do once, so we just do it on
473
 * all platforms. */
474
static jmp_buf *
475
align_setjmp_buffer(void *ptr)
476
55
{
477
55
    intptr_t offset = (intptr_t)ptr;
478
55
    char *aligned;
479
55
    offset &= 15;
480
55
    offset = (16-offset) & 15;
481
482
55
    aligned = ((char *)ptr) + offset;
483
484
55
    return (jmp_buf *)(void *)aligned;
485
55
}
486
487
OPTIMIZE_SETJMP
488
static int
489
jpg_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
490
121
{
491
121
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
492
121
    int code = 0;
493
121
    int need_more_data;
494
495
121
    do
496
2.00k
    {
497
2.00k
        need_more_data = 0;
498
2.00k
        switch(jpg->state)
499
2.00k
        {
500
55
        case ii_state_identifying:
501
55
        {
502
55
            const byte *hdr;
503
504
55
            jpg->jerr.setjmp_buffer = align_setjmp_buffer(&jpg->aligned_jmpbuf);
505
506
            /* Try and get us 11 bytes */
507
55
            code = ensure_bytes(jpg, pr, 11);
508
55
            if (code < 0)
509
0
                return code;
510
55
            hdr = pr->ptr+1;
511
55
            if (hdr[0] == 0xFF && hdr[1] == 0xd8 && hdr[2] == 0xff && hdr[3] == 0xe0 &&
512
55
                memcmp("JFIF", hdr+6, 5) == 0)
513
55
            {
514
55
                jpg->state = ii_state_jpeg;
515
55
                break;
516
55
            }
517
0
            jpg->state = ii_state_flush;
518
0
            break;
519
55
        }
520
55
        case ii_state_jpeg:
521
55
            code = gs_jpeg_mem_init(jpg->memory, (j_common_ptr)&jpg->cinfo);
522
55
            if (code < 0) {
523
0
                jpg->state = ii_state_flush;
524
0
                break;
525
0
            }
526
527
55
            jpg->cinfo.err = jpeg_std_error(&jpg->jerr.pub);
528
55
            jpg->jerr.pub.error_exit = jpg_error_exit;
529
55
            if (setjmp(*jpg->jerr.setjmp_buffer)) {
530
0
                jpg->state = ii_state_flush;
531
0
                break;
532
0
            }
533
534
55
            jpeg_create_decompress(&jpg->cinfo);
535
536
55
            jpg->cinfo.src = &jpg->jsrc;
537
55
            jpg->jsrc.init_source = jpg_jpeg_init_source;
538
55
            jpg->jsrc.fill_input_buffer = jpg_fill_input_buffer;
539
55
            jpg->jsrc.skip_input_data = jpg_skip_input_data;
540
55
            jpg->jsrc.resync_to_restart = jpg_resync_to_restart;
541
55
            jpg->jsrc.term_source = jpg_term_source;
542
543
55
            jpg->state = ii_state_jpeg_header;
544
55
            jpg->y = 0;
545
55
            break;
546
113
        case ii_state_jpeg_header:
547
113
        {
548
113
            int ok;
549
113
            gs_color_space *cs;
550
113
            float scale, xext, yext, xoffset, yoffset;
551
552
113
            if (fill_jpeg_source(jpg, pr)) {
553
34
                need_more_data = 1;
554
34
                break; /* No bytes left after skipping */
555
34
            }
556
79
            if (setjmp(*jpg->jerr.setjmp_buffer)) {
557
4
                jpeg_destroy_decompress(&jpg->cinfo);
558
4
                jpg->state = ii_state_flush;
559
4
                break;
560
4
            }
561
75
            ok = jpeg_read_header(&jpg->cinfo, TRUE);
562
75
            need_more_data = consume_jpeg_data(jpg, pr);
563
75
            if (ok == JPEG_SUSPENDED)
564
45
                break;
565
30
            need_more_data = 0;
566
567
30
            jpg->width = jpg->cinfo.image_width;
568
30
            jpg->height = jpg->cinfo.image_height;
569
30
            jpg->num_comps = jpg->cinfo.num_components;
570
30
            jpg->bpp = 8 * jpg->num_comps;
571
30
            switch(jpg->num_comps) {
572
0
            default:
573
1
            case 1:
574
1
                cs = jpg->gray;
575
1
                jpg->cinfo.out_color_space = JCS_GRAYSCALE;
576
1
                break;
577
28
            case 3:
578
28
                cs = jpg->rgb;
579
28
                jpg->cinfo.out_color_space = JCS_RGB;
580
28
                break;
581
1
            case 4:
582
1
                cs = jpg->cmyk;
583
1
                jpg->cinfo.out_color_space = JCS_CMYK;
584
1
                break;
585
30
            }
586
587
            /* Find us some X and Y resolutions */
588
30
            jpg->xresolution = jpg->cinfo.X_density;
589
30
            jpg->yresolution = jpg->cinfo.Y_density;
590
30
            if (jpg->xresolution == 0)
591
3
                jpg->xresolution = jpg->yresolution;
592
30
            if (jpg->yresolution == 0)
593
1
                jpg->yresolution = jpg->xresolution;
594
30
            if (jpg->xresolution == 0)
595
0
                jpg->xresolution = 72;
596
30
            if (jpg->yresolution == 0)
597
0
                jpg->yresolution = 72;
598
599
            /* Scale to fit, if too large. */
600
30
            scale = 1.0f;
601
30
            if (jpg->width * jpg->dev->HWResolution[0] > jpg->dev->width * jpg->xresolution)
602
2
                scale = ((float)jpg->dev->width * jpg->xresolution) / (jpg->width * jpg->dev->HWResolution[0]);
603
30
            if (scale * jpg->height * jpg->dev->HWResolution[1] > jpg->dev->height * jpg->yresolution)
604
0
                scale = ((float)jpg->dev->height * jpg->yresolution) / (jpg->height * jpg->dev->HWResolution[1]);
605
606
            /* Centre - Extents and offsets are all calculated in points (1/72 of an inch) */
607
30
            xext = ((float)jpg->width * 72 * scale / jpg->xresolution);
608
30
            xoffset = (jpg->dev->width * 72 / jpg->dev->HWResolution[0] - xext)/2;
609
30
            yext = ((float)jpg->height * 72 * scale / jpg->yresolution);
610
30
            yoffset = (jpg->dev->height * 72 / jpg->dev->HWResolution[1] - yext)/2;
611
612
            /* Now we've got the data from the image header, we can
613
             * make the gs image instance */
614
30
            jpg->byte_width = (jpg->bpp>>3)*jpg->width;
615
30
            if (jpg->width != 0 && jpg->byte_width / (jpg->bpp>>3) != jpg->width)
616
0
                return gs_note_error(gs_error_undefinedresult);
617
618
30
            jpg->nulldev = gs_currentdevice(jpg->pgs);
619
30
            rc_increment(jpg->nulldev);
620
30
            code = gs_setdevice_no_erase(jpg->pgs, jpg->dev);
621
30
            if (code < 0) {
622
0
                jpg->state = ii_state_flush;
623
0
                break;
624
0
            }
625
30
            gs_initmatrix(jpg->pgs);
626
627
            /* By default the ctm is set to:
628
             *   xres/72   0
629
             *   0         -yres/72
630
             *   0         dev->height * yres/72
631
             * i.e. it moves the origin from being top right to being bottom left.
632
             * We want to move it back, as without this, the image will be displayed
633
             * upside down.
634
             */
635
30
            code = gs_translate(jpg->pgs, 0.0, jpg->dev->height * 72 / jpg->dev->HWResolution[1]);
636
30
            if (code >= 0)
637
30
                code = gs_translate(jpg->pgs, xoffset, -yoffset);
638
30
            if (code >= 0)
639
30
                code = gs_scale(jpg->pgs, scale, -scale);
640
            /* At this point, the ctm is set to:
641
             *   xres/72  0
642
             *   0        yres/72
643
             *   0        0
644
             */
645
30
            if (code >= 0)
646
30
                code = gs_erasepage(jpg->pgs);
647
30
            if (code < 0) {
648
0
                jpg->state = ii_state_flush;
649
0
                break;
650
0
            }
651
652
30
            jpg->samples = gs_alloc_bytes(jpg->memory, jpg->byte_width, "jpg_impl_process(samples)");
653
30
            if (jpg->samples == NULL) {
654
0
                jpg->state = ii_state_flush;
655
0
                break;
656
0
            }
657
658
30
            memset(&jpg->image, 0, sizeof(jpg->image));
659
30
            gs_image_t_init(&jpg->image, cs);
660
30
            jpg->image.BitsPerComponent = jpg->bpp/jpg->num_comps;
661
30
            jpg->image.Width = jpg->width;
662
30
            jpg->image.Height = jpg->height;
663
664
30
            jpg->image.ImageMatrix.xx = jpg->xresolution / 72.0f;
665
30
            jpg->image.ImageMatrix.yy = jpg->yresolution / 72.0f;
666
667
30
            jpg->penum = gs_image_enum_alloc(jpg->memory, "jpg_impl_process(penum)");
668
30
            if (jpg->penum == NULL) {
669
0
                code = gs_note_error(gs_error_VMerror);
670
0
                jpg->state = ii_state_flush;
671
0
                return code;
672
0
            }
673
674
30
            code = gs_image_init(jpg->penum,
675
30
                                 &jpg->image,
676
30
                                 false,
677
30
                                 false,
678
30
                                 jpg->pgs);
679
30
            if (code < 0) {
680
0
                jpg->state = ii_state_flush;
681
0
                return code;
682
0
            }
683
684
30
            jpg->state = ii_state_jpeg_start;
685
30
            break;
686
30
        }
687
70
        case ii_state_jpeg_start:
688
70
        {
689
70
            int ok;
690
70
            if (fill_jpeg_source(jpg, pr)) {
691
0
                need_more_data = 1;
692
0
                break; /* No bytes left after skipping */
693
0
            }
694
70
            if (setjmp(*jpg->jerr.setjmp_buffer)) {
695
7
                jpeg_destroy_decompress(&jpg->cinfo);
696
7
                jpg->state = ii_state_flush;
697
7
                break;
698
7
            }
699
63
            ok = jpeg_start_decompress(&jpg->cinfo);
700
63
            (void)consume_jpeg_data(jpg, pr);
701
63
            if (ok == FALSE) {
702
40
                if (jpg->jsrc.bytes_in_buffer == jpg->bytes_available_on_entry)
703
20
                    need_more_data = 1;
704
40
                break;
705
40
            }
706
23
            jpg->state = ii_state_jpeg_rows;
707
23
            break;
708
63
        }
709
1.62k
        case ii_state_jpeg_rows:
710
1.62k
        {
711
1.62k
            int rows_decoded;
712
1.62k
            unsigned int used;
713
714
1.62k
            if (fill_jpeg_source(jpg, pr)) {
715
0
                need_more_data = 1;
716
0
                break; /* No bytes left after skipping */
717
0
            }
718
1.62k
            if (setjmp(*jpg->jerr.setjmp_buffer)) {
719
0
                jpeg_destroy_decompress(&jpg->cinfo);
720
0
                jpg->state = ii_state_flush;
721
0
                break;
722
0
            }
723
1.62k
            rows_decoded = jpeg_read_scanlines(&jpg->cinfo, &jpg->samples, 1);
724
1.62k
            need_more_data = consume_jpeg_data(jpg, pr);
725
1.62k
            if (rows_decoded == 0)
726
0
                break; /* Not enough data for a scanline yet */
727
1.62k
            need_more_data = 0;
728
729
1.62k
            code = gs_image_next(jpg->penum, jpg->samples, jpg->byte_width, &used);
730
1.62k
            if (code < 0) {
731
0
                jpg->state = ii_state_flush;
732
0
                break;
733
0
            }
734
1.62k
            jpg->y++;
735
1.62k
            if (jpg->y == jpg->height) {
736
23
                code = gs_image_cleanup_and_free_enum(jpg->penum, jpg->pgs);
737
23
                jpg->penum = NULL;
738
23
                if (code < 0) {
739
0
                    jpg->state = ii_state_flush;
740
0
                    break;
741
0
                }
742
23
                code = pl_finish_page(jpg->memory->gs_lib_ctx->top_of_system,
743
23
                                      jpg->pgs, 1, true);
744
23
                if (code < 0) {
745
0
                    jpg->state = ii_state_flush;
746
0
                    break;
747
0
                }
748
23
                jpg->state = ii_state_jpeg_finish;
749
23
            }
750
1.62k
            break;
751
1.62k
        }
752
1.62k
        case ii_state_jpeg_finish:
753
23
        {
754
23
            int ok;
755
756
23
            if (fill_jpeg_source(jpg, pr)) {
757
0
                need_more_data = 1;
758
0
                break; /* No bytes left after skipping */
759
0
            }
760
23
            if (setjmp(*jpg->jerr.setjmp_buffer)) {
761
0
                jpeg_destroy_decompress(&jpg->cinfo);
762
0
                jpg->state = ii_state_flush;
763
0
                break;
764
0
            }
765
23
            ok = jpeg_finish_decompress(&jpg->cinfo);
766
23
            need_more_data = consume_jpeg_data(jpg, pr);
767
23
            if (ok == FALSE)
768
0
                break;
769
23
            need_more_data = 0;
770
23
            jpg->state = ii_state_flush;
771
23
            break;
772
23
        }
773
0
        default:
774
58
        case ii_state_flush:
775
58
            if (setjmp(*jpg->jerr.setjmp_buffer))
776
0
                break;
777
58
            jpeg_destroy_decompress(&jpg->cinfo);
778
779
58
            gs_jpeg_mem_term((j_common_ptr)&jpg->cinfo);
780
781
58
            if (jpg->penum) {
782
7
                (void)gs_image_cleanup_and_free_enum(jpg->penum, jpg->pgs);
783
7
                jpg->penum = NULL;
784
7
            }
785
786
58
            gs_free_object(jpg->memory, jpg->samples, "jpg_impl_process(samples)");
787
58
            jpg->samples = NULL;
788
            /* We want to bin any data we get up to, but not including
789
             * a UEL. */
790
58
            return flush_to_uel(pr);
791
2.00k
        }
792
2.00k
    } while (!need_more_data);
793
794
63
    return code;
795
121
}
796
797
static int
798
jpg_impl_process_end(pl_interp_implementation_t * impl)
799
55
{
800
55
    return 0;
801
55
}
802
803
/* Not implemented */
804
static int
805
jpg_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
806
0
{
807
0
    const byte *p = cursor->ptr;
808
0
    const byte *rlimit = cursor->limit;
809
810
    /* Skip to, but leave UEL in buffer for PJL to find later */
811
0
    for (; p < rlimit; ++p)
812
0
        if (p[1] == '\033') {
813
0
            uint avail = rlimit - p;
814
815
0
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
816
0
                continue;
817
0
            if (avail < 9)
818
0
                break;
819
0
            cursor->ptr = p;
820
0
            return 1;           /* found eoj */
821
0
        }
822
0
    cursor->ptr = p;
823
0
    return 0;                   /* need more */
824
0
}
825
826
/* Parser action for end-of-file */
827
static int
828
jpg_impl_process_eof(pl_interp_implementation_t *impl)
829
55
{
830
55
    return 0;
831
55
}
832
833
/* Report any errors after running a job */
834
static int
835
jpg_impl_report_errors(pl_interp_implementation_t *impl,          /* interp instance to wrap up job in */
836
                       int                         code,          /* prev termination status */
837
                       long                        file_position, /* file position of error, -1 if unknown */
838
                       bool                        force_to_cout  /* force errors to cout */
839
)
840
0
{
841
0
    return 0;
842
0
}
843
844
/* Wrap up interp instance after a "job" */
845
static int
846
jpg_impl_dnit_job(pl_interp_implementation_t *impl)
847
55
{
848
55
    jpg_interp_instance_t *jpg = (jpg_interp_instance_t *)impl->interp_client_data;
849
850
55
    if (jpg->nulldev) {
851
30
        int code = gs_setdevice(jpg->pgs, jpg->nulldev);
852
30
        jpg->dev = NULL;
853
30
        rc_decrement(jpg->nulldev, "jpg_impl_dnit_job(nulldevice)");
854
30
        jpg->nulldev = NULL;
855
30
        return code;
856
30
    }
857
25
    return 0;
858
55
}
859
860
/* Parser implementation descriptor */
861
const pl_interp_implementation_t jpg_implementation = {
862
  jpg_impl_characteristics,
863
  jpg_impl_allocate_interp_instance,
864
  jpg_impl_get_device_memory,
865
  NULL, /* jpg_impl_set_param */
866
  NULL, /* jpg_impl_add_path */
867
  NULL, /* jpg_impl_post_args_init */
868
  jpg_impl_init_job,
869
  NULL, /* jpg_impl_run_prefix_commands */
870
  NULL, /* jpg_impl_process_file */
871
  jpg_impl_process_begin,
872
  jpg_impl_process,
873
  jpg_impl_process_end,
874
  jpg_impl_flush_to_eoj,
875
  jpg_impl_process_eof,
876
  jpg_impl_report_errors,
877
  jpg_impl_dnit_job,
878
  jpg_impl_deallocate_interp_instance,
879
  NULL, /* jpg_impl_reset */
880
  NULL  /* interp_client_data */
881
};