Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/sdctd.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 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
17
/* DCT decoding filter stream */
18
#include "memory_.h"
19
#include "stdio_.h"
20
#include "jpeglib_.h"
21
#include "jerror_.h"
22
#include "gdebug.h"
23
#include "gsmemory.h"
24
#include "strimpl.h"
25
#include "sdct.h"
26
#include "sjpeg.h"
27
28
/* ------ DCTDecode ------ */
29
30
/* JPEG source manager procedures */
31
static void
32
dctd_init_source(j_decompress_ptr dinfo)
33
10.5k
{
34
10.5k
}
35
static const JOCTET fake_eoi[2] =
36
{0xFF, JPEG_EOI};
37
static boolean
38
dctd_fill_input_buffer(j_decompress_ptr dinfo)
39
98.1k
{
40
98.1k
    jpeg_decompress_data *jddp =
41
98.1k
    (jpeg_decompress_data *) ((char *)dinfo -
42
98.1k
                              offset_of(jpeg_decompress_data, dinfo));
43
44
98.1k
    if (!jddp->input_eod)
45
96.9k
        return FALSE;    /* normal case: suspend processing */
46
    /* Reached end of source data without finding EOI */
47
1.27k
    WARNMS(dinfo, JWRN_JPEG_EOF);
48
    /* Insert a fake EOI marker */
49
1.27k
    dinfo->src->next_input_byte = fake_eoi;
50
1.27k
    dinfo->src->bytes_in_buffer = 2;
51
1.27k
    jddp->faked_eoi = true; /* so process routine doesn't use next_input_byte */
52
1.27k
    return TRUE;
53
98.1k
}
54
static void
55
dctd_skip_input_data(j_decompress_ptr dinfo, long num_bytes)
56
6.97k
{
57
6.97k
    struct jpeg_source_mgr *src = dinfo->src;
58
6.97k
    jpeg_decompress_data *jddp =
59
6.97k
    (jpeg_decompress_data *) ((char *)dinfo -
60
6.97k
                              offset_of(jpeg_decompress_data, dinfo));
61
62
6.97k
    if (num_bytes > 0) {
63
6.97k
        if (num_bytes > src->bytes_in_buffer) {
64
3.53k
            jddp->skip += num_bytes - src->bytes_in_buffer;
65
3.53k
            src->next_input_byte += src->bytes_in_buffer;
66
3.53k
            src->bytes_in_buffer = 0;
67
3.53k
            return;
68
3.53k
        }
69
3.43k
        src->next_input_byte += num_bytes;
70
3.43k
        src->bytes_in_buffer -= num_bytes;
71
3.43k
    }
72
6.97k
}
73
74
static void
75
dctd_term_source(j_decompress_ptr dinfo)
76
6.65k
{
77
6.65k
    jpeg_decompress_data *jddp =
78
6.65k
    (jpeg_decompress_data *) ((char *)dinfo -
79
6.65k
                              offset_of(jpeg_decompress_data, dinfo));
80
81
6.65k
    stream_dct_end_passthrough(jddp);
82
6.65k
    return;
83
6.65k
}
84
85
/* Set the defaults for the DCTDecode filter. */
86
static void
87
s_DCTD_set_defaults(stream_state * st)
88
21.3k
{
89
21.3k
    s_DCT_set_defaults(st);
90
21.3k
}
91
92
/* Initialize DCTDecode filter */
93
static int
94
s_DCTD_init(stream_state * st)
95
10.6k
{
96
10.6k
    stream_DCT_state *const ss = (stream_DCT_state *) st;
97
10.6k
    struct jpeg_source_mgr *src = &ss->data.decompress->source;
98
99
10.6k
    src->init_source = dctd_init_source;
100
10.6k
    src->fill_input_buffer = dctd_fill_input_buffer;
101
10.6k
    src->skip_input_data = dctd_skip_input_data;
102
10.6k
    src->term_source = dctd_term_source;
103
10.6k
    src->resync_to_restart = jpeg_resync_to_restart;  /* use default method */
104
10.6k
    ss->data.common->memory = ss->jpeg_memory;
105
10.6k
    ss->data.decompress->dinfo.src = src;
106
10.6k
    ss->data.decompress->skip = 0;
107
10.6k
    ss->data.decompress->input_eod = false;
108
10.6k
    ss->data.decompress->faked_eoi = false;
109
10.6k
    ss->phase = 0;
110
10.6k
    return 0;
111
10.6k
}
112
113
static int
114
compact_jpeg_buffer(stream_cursor_read *pr)
115
0
{
116
0
    byte *o, *i;
117
118
    /* Search backwards from the end for 2 consecutive 0xFFs */
119
0
    o = (byte *)pr->limit;
120
0
    while (o - pr->ptr >= 2) {
121
0
        if (*o-- == 0xFF) {
122
0
            if (*o == 0xFF)
123
0
                goto compact;
124
0
            o--;
125
0
        }
126
0
    }
127
0
    return 0;
128
0
compact:
129
0
    i = o-1;
130
0
    do {
131
        /* Skip i backwards over 0xFFs */
132
0
        while ((i != pr->ptr) && (*i == 0xFF))
133
0
            i--;
134
        /* Repeatedly copy from i to o */
135
0
        while (i != pr->ptr) {
136
0
            byte c = *i--;
137
0
            *o-- = c;
138
0
            if (c == 0xFF)
139
0
                break;
140
0
        }
141
0
    } while (i != pr->ptr);
142
143
0
    pr->ptr = o;
144
0
    return o - i;
145
0
}
146
147
static void
148
update_jpeg_header_height(JOCTET *d, size_t len, int height)
149
18.0k
{
150
18.0k
    int marker_len;
151
152
76.0k
    for (d += 2; len > 9 && d[0] == 0xFF; d += marker_len)
153
60.3k
    {
154
60.3k
        int declared_height;
155
156
60.3k
        marker_len = 2 + (d[2] << 8) + d[3];
157
60.3k
        if (marker_len > len)
158
2.36k
            break;
159
57.9k
        len -= marker_len;
160
161
        /* We can only safely rewrite non-differential SOF markers */
162
57.9k
        if (d[1] < 0xC0 || (0xC3 < d[1] && d[1] < 0xC9) || 0xCB < d[1])
163
50.2k
            continue;
164
165
7.69k
        declared_height = (d[5]<<8) | d[6];
166
7.69k
        if (declared_height == 0 || declared_height > height)
167
186
        {
168
186
            d[5] = height>>8;
169
186
            d[6] = height;
170
186
        }
171
7.69k
    }
172
18.0k
}
173
174
/* Process a buffer */
175
static int
176
s_DCTD_process(stream_state * st, stream_cursor_read * pr,
177
               stream_cursor_write * pw, bool last)
178
1.69M
{
179
1.69M
    stream_DCT_state *const ss = (stream_DCT_state *) st;
180
1.69M
    jpeg_decompress_data *jddp = ss->data.decompress;
181
1.69M
    struct jpeg_source_mgr *src = jddp->dinfo.src;
182
1.69M
    int code;
183
1.69M
    byte *Buf;
184
185
1.69M
    if_debug3m('w', st->memory, "[wdd]process avail=%u, skip=%u, last=%d\n",
186
1.69M
               (uint) (pr->limit - pr->ptr), (uint) jddp->skip, last);
187
1.69M
    if (jddp->skip != 0) {
188
14.5k
        long avail = pr->limit - pr->ptr;
189
190
14.5k
        if (avail < jddp->skip) {
191
11.3k
            if (jddp->PassThrough && jddp->PassThroughfn)
192
767
                (jddp->PassThroughfn)(jddp->device, (byte *)pr->ptr + 1, (byte *)pr->limit - (byte *)pr->ptr);
193
194
11.3k
            jddp->skip -= avail;
195
11.3k
            pr->ptr = pr->limit;
196
11.3k
            if (!last)
197
11.1k
                return 0;  /* need more data */
198
133
            jddp->skip = 0; /* don't skip past input EOD */
199
133
        }
200
3.33k
        Buf = (byte *)pr->ptr + 1;
201
3.33k
        pr->ptr += jddp->skip;
202
3.33k
        if (jddp->PassThrough && jddp->PassThroughfn)
203
262
            (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
204
205
3.33k
        jddp->skip = 0;
206
3.33k
    }
207
1.68M
    src->next_input_byte = pr->ptr + 1;
208
1.68M
    src->bytes_in_buffer = pr->limit - pr->ptr;
209
1.68M
    Buf = (byte *)pr->ptr + 1;
210
1.68M
    jddp->input_eod = last;
211
1.68M
    switch (ss->phase) {
212
21.0k
        case 0:   /* not initialized yet */
213
            /*
214
             * Adobe implementations seem to ignore leading garbage bytes,
215
             * even though neither the standard nor Adobe's own
216
             * documentation mention this.
217
             */
218
21.0k
            if (jddp->PassThrough && jddp->PassThroughfn && !jddp->StartedPassThrough) {
219
2.23k
                jddp->StartedPassThrough = 1;
220
2.23k
                (jddp->PassThroughfn)(jddp->device, NULL, 1);
221
2.23k
            }
222
31.1k
            while (pr->ptr < pr->limit && pr->ptr[1] != 0xff)
223
10.1k
                pr->ptr++;
224
21.0k
            if (pr->ptr == pr->limit) {
225
10.5k
                if (jddp->PassThrough && jddp->PassThroughfn)
226
2.23k
                    (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
227
10.5k
                return 0;
228
10.5k
            }
229
10.5k
            src->next_input_byte = pr->ptr + 1;
230
10.5k
            src->bytes_in_buffer = pr->limit - pr->ptr;
231
10.5k
            ss->phase = 1;
232
            /* falls through */
233
18.2k
        case 1:   /* reading header markers */
234
18.2k
            if (ss->data.common->Height != 0)
235
18.0k
            {
236
               /* Deliberate and naughty. We cast away a const pointer
237
                * here and write to a supposedly read-only stream. */
238
18.0k
                union { const byte *c; byte *u; } u;
239
18.0k
                u.c = pr->ptr+1;
240
18.0k
                update_jpeg_header_height(u.u, src->bytes_in_buffer, ss->data.common->Height);
241
18.0k
            }
242
18.2k
            if ((code = gs_jpeg_read_header(ss, TRUE)) < 0) {
243
2.69k
                code = ERRC;
244
2.69k
                goto error_out;
245
2.69k
            }
246
15.5k
            pr->ptr =
247
15.5k
                (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
248
15.5k
            switch (code) {
249
7.74k
                case JPEG_SUSPENDED:
250
7.74k
                    if (jddp->PassThrough && jddp->PassThroughfn)
251
973
                        (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
252
7.74k
                    return 0;
253
                    /*case JPEG_HEADER_OK: */
254
15.5k
            }
255
256
            /*
257
             * Default the color transform if not set and check for
258
             * the Adobe marker and use Adobe's transform if the
259
             * marker is set.
260
             */
261
7.77k
            if (ss->ColorTransform == -1) {
262
7.77k
                if (jddp->dinfo.num_components == 3)
263
6.71k
                    ss->ColorTransform = 1;
264
1.06k
                else
265
1.06k
                    ss->ColorTransform = 0;
266
7.77k
            }
267
268
7.77k
            if (jddp->dinfo.saw_Adobe_marker)
269
4.58k
                ss->ColorTransform = jddp->dinfo.Adobe_transform;
270
271
7.77k
            switch (jddp->dinfo.num_components) {
272
6.71k
            case 3:
273
6.71k
                jddp->dinfo.jpeg_color_space =
274
6.71k
                    (ss->ColorTransform ? JCS_YCbCr : JCS_RGB);
275
                        /* out_color_space will default to JCS_RGB */
276
6.71k
                        break;
277
534
            case 4:
278
534
                jddp->dinfo.jpeg_color_space =
279
534
                    (ss->ColorTransform ? JCS_YCCK : JCS_CMYK);
280
                /* out_color_space will default to JCS_CMYK */
281
534
                break;
282
7.77k
            }
283
7.77k
            ss->phase = 2;
284
            /* falls through */
285
12.9k
        case 2:   /* start_decompress */
286
12.9k
            if ((code = gs_jpeg_start_decompress(ss)) < 0) {
287
68
                code = ERRC;
288
68
                goto error_out;
289
68
            }
290
12.8k
            pr->ptr =
291
12.8k
                (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
292
12.8k
            if (code == 0) {
293
5.14k
                if (jddp->PassThrough && jddp->PassThroughfn)
294
2.03k
                    (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
295
5.14k
                return 0;
296
5.14k
            }
297
7.69k
            ss->scan_line_size =
298
7.69k
                jddp->dinfo.output_width * jddp->dinfo.output_components;
299
7.69k
            if_debug4m('w', ss->memory, "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n",
300
7.69k
                       jddp->dinfo.output_width,
301
7.69k
                       jddp->dinfo.output_components,
302
7.69k
                       ss->scan_line_size, jddp->templat.min_out_size);
303
7.69k
            if (ss->scan_line_size > (uint) jddp->templat.min_out_size) {
304
                /* Create a spare buffer for oversize scanline */
305
349
                jddp->scanline_buffer =
306
349
                    gs_alloc_bytes_immovable(gs_memory_stable(jddp->memory),
307
349
                                             ss->scan_line_size,
308
349
                                         "s_DCTD_process(scanline_buffer)");
309
349
                if (jddp->scanline_buffer == NULL) {
310
0
                    code = ERRC;
311
0
                    goto error_out;
312
0
                }
313
349
            }
314
7.69k
            jddp->bytes_in_scanline = 0;
315
7.69k
            ss->phase = 3;
316
            /* falls through */
317
1.65M
        case 3:   /* reading data */
318
2.10M
          dumpbuffer:
319
2.10M
            if (jddp->bytes_in_scanline != 0) {
320
1.11M
                uint avail = pw->limit - pw->ptr;
321
1.11M
                uint tomove = min(jddp->bytes_in_scanline,
322
1.11M
                                  avail);
323
324
1.11M
                if_debug2m('w', ss->memory, "[wdd]moving %u/%u\n",
325
1.11M
                           tomove, avail);
326
1.11M
                memcpy(pw->ptr + 1, jddp->scanline_buffer +
327
1.11M
                       (ss->scan_line_size - jddp->bytes_in_scanline),
328
1.11M
                       tomove);
329
1.11M
                pw->ptr += tomove;
330
1.11M
                jddp->bytes_in_scanline -= tomove;
331
                /* calculate room after the copy,
332
                 * PXL typically provides room 1 exactly 1 scan, so avail == 0
333
                 * PDF/PS provide enough room, so avail >= 0
334
                 * XPS provides room ro complete image, and expects complet image copied
335
                 * PCL,PXL,PDF,PS copy 1 scan at a time.
336
                 */
337
1.11M
                avail -= tomove;
338
1.11M
                if ((jddp->bytes_in_scanline != 0) || /* no room for complete scan */
339
453k
                    ((jddp->bytes_in_scanline == 0) && (tomove > 0) && /* 1 scancopy completed */
340
453k
                     (avail < tomove) && /* still room for 1 more scan */
341
255k
                     (jddp->dinfo.output_height > jddp->dinfo.output_scanline))) /* more scans to do */
342
915k
                {
343
915k
                     if (jddp->PassThrough && jddp->PassThroughfn) {
344
68.9k
                        (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
345
68.9k
                    }
346
915k
                    return 1; /* need more room */
347
915k
                }
348
1.11M
            }
349
            /* while not done with image, decode 1 scan, otherwise fall into phase 4 */
350
2.37M
            while (jddp->dinfo.output_height > jddp->dinfo.output_scanline) {
351
2.36M
                int read;
352
2.36M
                byte *samples;
353
354
2.36M
                if (jddp->scanline_buffer != NULL)
355
469k
                    samples = jddp->scanline_buffer;
356
1.89M
                else {
357
1.89M
                    if ((uint) (pw->limit - pw->ptr) < ss->scan_line_size) {
358
648k
                        if (jddp->PassThrough && jddp->PassThroughfn) {
359
115k
                            (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
360
115k
                        }
361
648k
                        return 1; /* need more room */
362
648k
                    }
363
1.24M
                    samples = pw->ptr + 1;
364
1.24M
                }
365
1.71M
                read = gs_jpeg_read_scanlines(ss, &samples, 1);
366
1.71M
                if (read < 0) {
367
0
                    code = ERRC;
368
0
                    goto error_out;
369
0
                }
370
1.71M
                if_debug3m('w', ss->memory, "[wdd]read returns %d, used=%u, faked_eoi=%d\n",
371
1.71M
                           read,
372
1.71M
                           (uint) (src->next_input_byte - 1 - pr->ptr),
373
1.71M
                           (int)jddp->faked_eoi);
374
1.71M
                pr->ptr =
375
1.71M
                    (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
376
1.71M
                if (!read) {
377
                    /* We are suspending. If nothing was consumed, and the
378
                     * buffer was full, compact the data in the buffer. If
379
                     * this fails to save anything, then we'll never succeed;
380
                     * throw an error to avoid an infinite loop.
381
                     * The tricky part here is knowing "if the buffer is
382
                     * full"; we do that by comparing the number of bytes in
383
                     * the buffer with the min_in_size set for the stream.
384
                     */
385
                    /* TODO: If we ever find a file with valid data that trips
386
                     * this test, we should implement a scheme whereby we keep
387
                     * a local buffer and copy the data into it. The local
388
                     * buffer can be grown as required. */
389
80.6k
                    if ((src->next_input_byte-1 == pr->ptr) &&
390
80.6k
                        (pr->limit - pr->ptr >= ss->templat->min_in_size) &&
391
0
                        (compact_jpeg_buffer(pr) == 0)) {
392
0
                        code = ERRC;
393
0
                        goto error_out;
394
0
                    }
395
80.6k
                    if (jddp->PassThrough && jddp->PassThroughfn) {
396
10.6k
                        (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
397
10.6k
                    }
398
80.6k
                    return 0; /* need more data */
399
80.6k
                }
400
1.63M
                if (jddp->scanline_buffer != NULL) {
401
453k
                    jddp->bytes_in_scanline = ss->scan_line_size;
402
453k
                    goto dumpbuffer;
403
453k
                }
404
1.18M
                pw->ptr += ss->scan_line_size;
405
1.18M
            }
406
7.50k
            ss->phase = 4;
407
            /* falls through */
408
10.8k
        case 4:   /* end of image; scan for EOI */
409
10.8k
            {
410
                /* Slightly hacky: We want dctd_term_source() to call stream_dct_end_passthrough()
411
                 * to cope with certain error conditions, BUT not at this stage, because gs_jpeg_finish_decompress()
412
                 * is what can prompt libjpeg to flush through the last its input data, and we need the last of
413
                 * that input data pushed to the PassThroughfn call.
414
                 * Setting PassThrough to zero will prevent the final PassThroughfn happening during gs_jpeg_finish_decompress()
415
                 */
416
10.8k
                int pt = jddp->PassThrough;
417
10.8k
                jddp->PassThrough = 0;
418
10.8k
                if ((code = gs_jpeg_finish_decompress(ss)) < 0) {
419
848
                    code = ERRC;
420
848
                    goto error_out;
421
848
                }
422
10.0k
                pr->ptr =
423
10.0k
                    (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
424
10.0k
                jddp->PassThrough = pt;
425
10.0k
                if (jddp->PassThrough && jddp->PassThroughfn)
426
1.37k
                    (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
427
10.0k
                stream_dct_end_passthrough(jddp);
428
10.0k
                if (code == 0)
429
3.38k
                    return 0;
430
10.0k
            }
431
6.65k
            ss->phase = 5;
432
            /* falls through */
433
6.65k
        case 5:   /* we are DONE */
434
6.65k
            return EOFC;
435
1.68M
    }
436
    /* Default case can't happen.... */
437
0
    return ERRC;
438
439
3.61k
error_out:
440
3.61k
    stream_dct_end_passthrough(jddp);
441
3.61k
    return code;
442
1.68M
}
443
444
/* Stream template */
445
const stream_template s_DCTD_template =
446
{&st_DCT_state, s_DCTD_init, s_DCTD_process, 2000, 4000, NULL,
447
 s_DCTD_set_defaults
448
};