Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/base/spngp.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* PNG pixel prediction filters */
18
#include "memory_.h"
19
#include "strimpl.h"
20
#include "spngpx.h"
21
22
/* ------ PNGPredictorEncode/Decode ------ */
23
24
private_st_PNGP_state();
25
26
/* Define values for case dispatch. */
27
0
#define cNone 10
28
0
#define cSub 11
29
0
#define cUp 12
30
0
#define cAverage 13
31
0
#define cPaeth 14
32
0
#define cOptimum 15
33
0
#define cEncode -10
34
0
#define cDecode -4
35
static const byte pngp_case_needs_prev[] = {
36
    0, 0, 1, 1, 1, 1
37
};
38
39
/* Set defaults */
40
static void
41
s_PNGP_set_defaults(stream_state * st)
42
0
{
43
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
44
45
0
    s_PNGP_set_defaults_inline(ss);
46
0
}
47
48
/* Common (re)initialization. */
49
static int
50
s_PNGP_reinit(stream_state * st)
51
0
{
52
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
53
54
0
    if (ss->prev_row != 0)
55
0
        memset(ss->prev_row + ss->bpp, 0, ss->row_count);
56
0
    ss->row_left = 0;
57
0
    return 0;
58
0
}
59
60
/* Common initialization. */
61
static int
62
s_pngp_init(stream_state * st, bool need_prev)
63
0
{
64
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
65
0
    int bits_per_pixel = ss->Colors * ss->BitsPerComponent;
66
0
    long bits_per_row = (long)bits_per_pixel * ss->Columns;
67
0
    byte *prev_row = 0;
68
69
0
#if ARCH_SIZEOF_LONG > ARCH_SIZEOF_INT
70
0
    if (bits_per_row > max_uint * 7L)
71
0
        return ERRC; /****** WRONG ******/
72
0
#endif
73
0
    ss->row_count = (uint) ((bits_per_row + 7) >> 3);
74
0
    ss->end_mask = (1 << (-bits_per_row & 7)) - 1;
75
76
0
    if (ss->Colors > s_PNG_max_Colors)
77
0
        return ERRC; /* Too many colorants */
78
79
0
    ss->bpp = (bits_per_pixel + 7) >> 3;
80
0
    if (need_prev) {
81
0
        prev_row = gs_alloc_bytes(st->memory, ss->bpp + ss->row_count,
82
0
                                  "PNGPredictor prev row");
83
0
        if (prev_row == 0)
84
0
            return ERRC; /****** WRONG ******/
85
0
        memset(prev_row, 0, ss->bpp);
86
0
    }
87
0
    ss->prev_row = prev_row;
88
    /* case_index is only preset for encoding */
89
0
    return s_PNGP_reinit(st);
90
0
}
91
92
/* Initialize PNGPredictorEncode filter. */
93
static int
94
s_PNGPE_init(stream_state * st)
95
0
{
96
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
97
98
0
    return s_pngp_init(st, pngp_case_needs_prev[ss->Predictor - cNone]);
99
0
}
100
101
/* Initialize PNGPredictorDecode filter. */
102
static int
103
s_PNGPD_init(stream_state * st)
104
0
{
105
0
    return s_pngp_init(st, true);
106
0
}
107
108
/* Release a PNGPredictor filter. */
109
static void
110
s_PNGP_release(stream_state *st)
111
0
{
112
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
113
114
0
    if (ss->prev_row)
115
0
        gs_free_object(st->memory, ss->prev_row, "PNGPredictor prev row");
116
0
}
117
118
/*
119
 * Process a partial buffer.  We pass in current and previous pointers
120
 * to both the current and preceding scan line.  Note that dprev is
121
 * p - bpp for encoding, q - bpp for decoding; similarly, the 'up' row
122
 * is the raw data for encoding, the filtered (encoded) data for decoding.
123
 * Note also that the case_index cannot be cOptimum.
124
 *
125
 * Uses ss->case_index; uses and updates ss->row_left, pr->ptr, pw->ptr.
126
 */
127
static int
128
paeth_predictor(int a, int b, int c)
129
0
{
130
    /* The definitions of ac and bc are correct, not a typo. */
131
0
    int ac = b - c, bc = a - c, abcc = ac + bc;
132
0
    int pa = (ac < 0 ? -ac : ac), pb = (bc < 0 ? -bc : bc),
133
0
        pc = (abcc < 0 ? -abcc : abcc);
134
135
0
    return (pa <= pb && pa <= pc ? a : pb <= pc ? b : c);
136
0
}
137
static void
138
s_pngp_process(stream_state * st, stream_cursor_write * pw,
139
               const byte * dprev, stream_cursor_read * pr,
140
               const byte * upprev, const byte * up, uint count)
141
0
{
142
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
143
0
    byte *q = pw->ptr + 1;
144
0
    const byte *p = pr->ptr + 1;
145
146
0
    pr->ptr += count;
147
0
    pw->ptr += count;
148
0
    ss->row_left -= count;
149
0
    switch (ss->case_index) {
150
0
        case cEncode + cNone:
151
0
        case cDecode + cNone:
152
0
            memcpy(q, p, count);
153
0
            break;
154
0
        case cEncode + cSub:
155
0
            for (; count; ++q, ++dprev, ++p, --count)
156
0
                *q = (byte) (*p - *dprev);
157
0
            break;
158
0
        case cDecode + cSub:
159
0
            for (; count; ++q, ++dprev, ++p, --count)
160
0
                *q = (byte) (*p + *dprev);
161
0
            break;
162
0
        case cEncode + cUp:
163
0
            for (; count; ++q, ++up, ++p, --count)
164
0
                *q = (byte) (*p - *up);
165
0
            break;
166
0
        case cDecode + cUp:
167
0
            for (; count; ++q, ++up, ++p, --count)
168
0
                *q = (byte) (*p + *up);
169
0
            break;
170
0
        case cEncode + cAverage:
171
0
            for (; count; ++q, ++dprev, ++up, ++p, --count)
172
0
                *q = (byte) (*p - arith_rshift_1((int)*dprev + (int)*up));
173
0
            break;
174
0
        case cDecode + cAverage:
175
0
            for (; count; ++q, ++dprev, ++up, ++p, --count)
176
0
                *q = (byte) (*p + arith_rshift_1((int)*dprev + (int)*up));
177
0
            break;
178
0
        case cEncode + cPaeth:
179
0
            for (; count; ++q, ++dprev, ++up, ++upprev, ++p, --count)
180
0
                *q = (byte) (*p - paeth_predictor(*dprev, *up, *upprev));
181
0
            break;
182
0
        case cDecode + cPaeth:
183
0
            for (; count; ++q, ++dprev, ++up, ++upprev, ++p, --count)
184
0
                *q = (byte) (*p + paeth_predictor(*dprev, *up, *upprev));
185
0
            break;
186
0
    }
187
0
}
188
189
/* Calculate the number of bytes for the next processing step, */
190
/* the min of (input data, output data, remaining row length). */
191
static uint
192
s_pngp_count(const stream_state * st_const, const stream_cursor_read * pr,
193
             const stream_cursor_write * pw)
194
0
{
195
0
    const stream_PNGP_state *const ss_const =
196
0
        (const stream_PNGP_state *)st_const;
197
0
    uint rcount = pr->limit - pr->ptr;
198
0
    uint wcount = pw->limit - pw->ptr;
199
0
    uint row_left = ss_const->row_left;
200
201
0
    if (rcount < row_left)
202
0
        row_left = rcount;
203
0
    if (wcount < row_left)
204
0
        row_left = wcount;
205
0
    return row_left;
206
0
}
207
208
/*
209
 * Encode a buffer.  Let N = ss->row_count, P = N - ss->row_left,
210
 * and B = ss->bpp.  Consider that bytes [-B .. -1] of every row are zero.
211
 * Then:
212
 *      prev_row[0 .. P - 1] contain bytes -B .. P - B - 1
213
 *        of the current input row.
214
 *      ss->prev[0 .. B - 1] contain bytes P - B .. P - 1
215
 *        of the current input row.
216
 *      prev_row[P .. N + B - 1] contain bytes P - B .. N - 1
217
 *        of the previous input row.
218
 * We must handle the edges of each row specially, by clearing ss->prev at
219
 * the beginning of each row, and copying trailing bytes from ss->prev (and
220
 * possibly the input) to prev_row at the end of each row.
221
 */
222
static int
223
optimum_predictor(const stream_state * st, const stream_cursor_read * pr)
224
0
{
225
0
    return cSub;
226
0
}
227
static int
228
s_PNGPE_process(stream_state * st, stream_cursor_read * pr,
229
                stream_cursor_write * pw, bool last)
230
0
{
231
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
232
0
    int bpp = ss->bpp;
233
0
    int status = 0;
234
235
0
    while (pr->ptr < pr->limit) {
236
0
        uint count;
237
238
0
        if (ss->row_left == 0) {
239
            /* Beginning of row, write algorithm byte. */
240
0
            int predictor;
241
242
0
            if (pw->ptr >= pw->limit) {
243
0
                status = 1;
244
0
                break;
245
0
            }
246
0
            predictor =
247
0
                (ss->Predictor == cOptimum ?
248
0
                 optimum_predictor(st, pr) :
249
0
                 ss->Predictor);
250
0
            *++(pw->ptr) = (byte) predictor - cNone;
251
0
            ss->case_index = predictor + cEncode;
252
0
            ss->row_left = ss->row_count;
253
0
            memset(ss->prev, 0, bpp);
254
0
            continue;
255
0
        }
256
0
        count = s_pngp_count(st, pr, pw);
257
0
        if (count == 0) {
258
            /* We know we have input, so output must be full. */
259
0
            status = 1;
260
0
            break;
261
0
        } {
262
0
            byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left;
263
0
            uint n = min(count, bpp);
264
265
            /* Process bytes whose predecessors are in prev. */
266
0
            s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n);
267
0
            if (ss->row_left == 0) {
268
0
                if (ss->prev_row) {
269
0
                    memcpy(up - bpp, ss->prev, bpp);
270
0
                    memcpy(up, pr->ptr - (n - 1), n);
271
0
                }
272
0
                continue;
273
0
            }
274
0
            if (ss->prev_row)
275
0
                memcpy(up - bpp, ss->prev, n);
276
0
            if (n < bpp) {
277
                /*
278
                 * We didn't have both enough input data and enough output
279
                 * space to use up all of prev.  Shift more data into prev
280
                 * and exit.
281
                 */
282
0
                int prev_left = bpp - n;
283
284
0
                memmove(ss->prev, ss->prev + n, prev_left);
285
0
                memcpy(ss->prev + prev_left, pr->ptr - (n - 1), n);
286
0
                if (pw->ptr >= pw->limit && pr->ptr < pr->limit)
287
0
                    status = 1;
288
0
                break;
289
0
            }
290
            /* Process bytes whose predecessors are in the input. */
291
            /* We know we have at least bpp input and output bytes, */
292
            /* and that n = bpp. */
293
0
            count -= bpp;
294
0
            s_pngp_process(st, pw, pr->ptr - (bpp - 1), pr,
295
0
                           up, up + bpp, count);
296
0
            memcpy(ss->prev, pr->ptr - (bpp - 1), bpp);
297
0
            if (ss->prev_row) {
298
0
                memcpy(up, pr->ptr - (bpp + count - 1), count);
299
0
                if (ss->row_left == 0)
300
0
                    memcpy(up + count, ss->prev, bpp);
301
0
            }
302
0
        }
303
0
    }
304
0
    return status;
305
0
}
306
307
/*
308
 * Decode a buffer.  Let N = ss->row_count, P = N - ss->row_left,
309
 * and B = ss->bpp.  Consider that bytes [-B .. -1] of every row are zero.
310
 * Then:
311
 *      prev_row[0 .. P - 1] contain bytes -B .. P - B - 1
312
 *        of the current output row.
313
 *      ss->prev[0 .. B - 1] contain bytes P - B .. P - 1
314
 *        of the current output row.
315
 *      prev_row[P .. N + B - 1] contain bytes P - B .. N - 1
316
 *        of the previous output row.
317
 * We must handle the edges of each row specially, by clearing ss->prev at
318
 * the beginning of each row, and copying trailing bytes from ss->prev (and
319
 * possibly the output) to prev_row at the end of each row.
320
 */
321
static int
322
s_PNGPD_process(stream_state * st, stream_cursor_read * pr,
323
                stream_cursor_write * pw, bool last)
324
0
{
325
0
    stream_PNGP_state *const ss = (stream_PNGP_state *) st;
326
0
    int bpp = ss->bpp;
327
0
    int status = 0;
328
329
0
    while (pr->ptr < pr->limit) {
330
0
        uint count;
331
332
0
        if (ss->row_left == 0) {
333
            /* Beginning of row, read algorithm byte. */
334
0
            int predictor = pr->ptr[1];
335
336
0
            if (predictor >= cOptimum - cNone) {
337
0
                status = ERRC;
338
0
                break;
339
0
            }
340
0
            pr->ptr++;
341
0
            ss->case_index = predictor + cNone + cDecode;
342
0
            ss->row_left = ss->row_count;
343
0
            memset(ss->prev, 0, bpp);
344
0
            continue;
345
0
        }
346
0
        count = s_pngp_count(st, pr, pw);
347
0
        if (count == 0) {
348
            /* We know we have input, so output must be full. */
349
0
            status = 1;
350
0
            break;
351
0
        } {
352
0
            byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left;
353
0
            uint n = min(count, bpp);
354
355
            /* Process bytes whose predecessors are in prev. */
356
0
            s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n);
357
0
            if (ss->row_left == 0) {
358
0
                if (ss->prev_row) {
359
0
                    memcpy(up - bpp, ss->prev, bpp);
360
0
                    memcpy(up, pw->ptr - (n - 1), n);
361
0
                }
362
0
                continue;
363
0
            }
364
0
            if (ss->prev_row)
365
0
                memcpy(up - bpp, ss->prev, n);
366
0
            if (n < bpp) {
367
                /*
368
                 * We didn't have both enough input data and enough output
369
                 * space to use up all of prev.  Shift more data into prev
370
                 * and exit.
371
                 */
372
0
                int prev_left = bpp - n;
373
374
0
                memmove(ss->prev, ss->prev + n, prev_left);
375
0
                memcpy(ss->prev + prev_left, pw->ptr - (n - 1), n);
376
0
                if (pw->ptr >= pw->limit && pr->ptr < pr->limit)
377
0
                    status = 1;
378
0
                break;
379
0
            }
380
            /* Process bytes whose predecessors are in the output. */
381
            /* We know we have at least bpp input and output bytes, */
382
            /* and that n = bpp. */
383
0
            count -= bpp;
384
0
            s_pngp_process(st, pw, pw->ptr - (bpp - 1), pr,
385
0
                           up, up + bpp, count);
386
0
            memcpy(ss->prev, pw->ptr - (bpp - 1), bpp);
387
0
            if (ss->prev_row) {
388
0
                memcpy(up, pw->ptr - (bpp + count - 1), count);
389
0
                if (ss->row_left == 0)
390
0
                    memcpy(up + count, ss->prev, bpp);
391
0
            }
392
0
        }
393
0
    }
394
0
    return status;
395
0
}
396
397
/* Stream templates */
398
const stream_template s_PNGPE_template = {
399
    &st_PNGP_state, s_PNGPE_init, s_PNGPE_process, 1, 1, s_PNGP_release,
400
    s_PNGP_set_defaults, s_PNGP_reinit
401
};
402
const stream_template s_PNGPD_template = {
403
    &st_PNGP_state, s_PNGPD_init, s_PNGPD_process, 1, 1, s_PNGP_release,
404
    s_PNGP_set_defaults, s_PNGP_reinit
405
};