Coverage Report

Created: 2025-11-16 07:40

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