/src/ghostpdl/base/spngp.c
Line | Count | Source (jump to first uncovered line) |
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 | 7.97M | #define cNone 10 |
28 | 4.93M | #define cSub 11 |
29 | 1.49M | #define cUp 12 |
30 | 128k | #define cAverage 13 |
31 | 515k | #define cPaeth 14 |
32 | 3.11M | #define cOptimum 15 |
33 | 3.95M | #define cEncode -10 |
34 | 7.97M | #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 | 54.4k | { |
43 | 54.4k | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
44 | | |
45 | 54.4k | s_PNGP_set_defaults_inline(ss); |
46 | 54.4k | } |
47 | | |
48 | | /* Common (re)initialization. */ |
49 | | static int |
50 | | s_PNGP_reinit(stream_state * st) |
51 | 54.4k | { |
52 | 54.4k | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
53 | | |
54 | 54.4k | if (ss->prev_row != 0) |
55 | 54.4k | memset(ss->prev_row + ss->bpp, 0, ss->row_count); |
56 | 54.4k | ss->row_left = 0; |
57 | 54.4k | return 0; |
58 | 54.4k | } |
59 | | |
60 | | /* Common initialization. */ |
61 | | static int |
62 | | s_pngp_init(stream_state * st, bool need_prev) |
63 | 54.4k | { |
64 | 54.4k | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
65 | 54.4k | int bits_per_pixel = ss->Colors * ss->BitsPerComponent; |
66 | 54.4k | long bits_per_row = (long)bits_per_pixel * ss->Columns; |
67 | 54.4k | byte *prev_row = 0; |
68 | | |
69 | 54.4k | #if ARCH_SIZEOF_LONG > ARCH_SIZEOF_INT |
70 | 54.4k | if (bits_per_row > max_uint * 7L) |
71 | 0 | return ERRC; /****** WRONG ******/ |
72 | 54.4k | #endif |
73 | 54.4k | ss->row_count = (uint) ((bits_per_row + 7) >> 3); |
74 | 54.4k | ss->end_mask = (1 << (-bits_per_row & 7)) - 1; |
75 | | |
76 | 54.4k | if (ss->Colors > s_PNG_max_Colors) |
77 | 0 | return ERRC; /* Too many colorants */ |
78 | | |
79 | 54.4k | if (bits_per_row < 1) |
80 | 0 | return ERRC; |
81 | | |
82 | 54.4k | ss->bpp = (bits_per_pixel + 7) >> 3; |
83 | 54.4k | if (need_prev) { |
84 | 54.4k | prev_row = gs_alloc_bytes(st->memory, ss->bpp + ss->row_count, |
85 | 54.4k | "PNGPredictor prev row"); |
86 | 54.4k | if (prev_row == 0) |
87 | 0 | return ERRC; /****** WRONG ******/ |
88 | 54.4k | memset(prev_row, 0, ss->bpp); |
89 | 54.4k | } |
90 | 54.4k | ss->prev_row = prev_row; |
91 | | /* case_index is only preset for encoding */ |
92 | 54.4k | return s_PNGP_reinit(st); |
93 | 54.4k | } |
94 | | |
95 | | /* Initialize PNGPredictorEncode filter. */ |
96 | | static int |
97 | | s_PNGPE_init(stream_state * st) |
98 | 11.3k | { |
99 | 11.3k | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
100 | | |
101 | 11.3k | return s_pngp_init(st, pngp_case_needs_prev[ss->Predictor - cNone]); |
102 | 11.3k | } |
103 | | |
104 | | /* Initialize PNGPredictorDecode filter. */ |
105 | | static int |
106 | | s_PNGPD_init(stream_state * st) |
107 | 43.0k | { |
108 | 43.0k | return s_pngp_init(st, true); |
109 | 43.0k | } |
110 | | |
111 | | /* Release a PNGPredictor filter. */ |
112 | | static void |
113 | | s_PNGP_release(stream_state *st) |
114 | 54.4k | { |
115 | 54.4k | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
116 | | |
117 | 54.4k | if (ss->prev_row) |
118 | 54.4k | gs_free_object(st->memory, ss->prev_row, "PNGPredictor prev row"); |
119 | 54.4k | } |
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 | 61.4M | { |
133 | | /* The definitions of ac and bc are correct, not a typo. */ |
134 | 61.4M | int ac = b - c, bc = a - c, abcc = ac + bc; |
135 | 61.4M | int pa = (ac < 0 ? -ac : ac), pb = (bc < 0 ? -bc : bc), |
136 | 61.4M | pc = (abcc < 0 ? -abcc : abcc); |
137 | | |
138 | 61.4M | return (pa <= pb && pa <= pc ? a : pb <= pc ? b : c); |
139 | 61.4M | } |
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 | 8.82M | { |
145 | 8.82M | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
146 | 8.82M | byte *q = pw->ptr + 1; |
147 | 8.82M | const byte *p = pr->ptr + 1; |
148 | | |
149 | 8.82M | pr->ptr += count; |
150 | 8.82M | pw->ptr += count; |
151 | 8.82M | ss->row_left -= count; |
152 | 8.82M | switch (ss->case_index) { |
153 | 0 | case cEncode + cNone: |
154 | 2.41M | case cDecode + cNone: |
155 | 2.41M | memcpy(q, p, count); |
156 | 2.41M | break; |
157 | 3.29M | case cEncode + cSub: |
158 | 135M | for (; count; ++q, ++dprev, ++p, --count) |
159 | 131M | *q = (byte) (*p - *dprev); |
160 | 3.29M | break; |
161 | 980k | case cDecode + cSub: |
162 | 273M | for (; count; ++q, ++dprev, ++p, --count) |
163 | 272M | *q = (byte) (*p + *dprev); |
164 | 980k | break; |
165 | 0 | case cEncode + cUp: |
166 | 0 | for (; count; ++q, ++up, ++p, --count) |
167 | 0 | *q = (byte) (*p - *up); |
168 | 0 | break; |
169 | 1.49M | case cDecode + cUp: |
170 | 24.4M | for (; count; ++q, ++up, ++p, --count) |
171 | 22.9M | *q = (byte) (*p + *up); |
172 | 1.49M | 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 | 128k | case cDecode + cAverage: |
178 | 15.1M | for (; count; ++q, ++dprev, ++up, ++p, --count) |
179 | 15.0M | *q = (byte) (*p + arith_rshift_1((int)*dprev + (int)*up)); |
180 | 128k | 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 | 515k | case cDecode + cPaeth: |
186 | 61.9M | for (; count; ++q, ++dprev, ++up, ++upprev, ++p, --count) |
187 | 61.4M | *q = (byte) (*p + paeth_predictor(*dprev, *up, *upprev)); |
188 | 515k | break; |
189 | 8.82M | } |
190 | 8.82M | } |
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 | 5.74M | { |
198 | 5.74M | const stream_PNGP_state *const ss_const = |
199 | 5.74M | (const stream_PNGP_state *)st_const; |
200 | 5.74M | uint rcount = pr->limit - pr->ptr; |
201 | 5.74M | uint wcount = pw->limit - pw->ptr; |
202 | 5.74M | uint row_left = ss_const->row_left; |
203 | | |
204 | 5.74M | if (rcount < row_left) |
205 | 1.97M | row_left = rcount; |
206 | 5.74M | if (wcount < row_left) |
207 | 1.93M | row_left = wcount; |
208 | 5.74M | return row_left; |
209 | 5.74M | } |
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 | 661k | { |
228 | 661k | return cSub; |
229 | 661k | } |
230 | | static int |
231 | | s_PNGPE_process(stream_state * st, stream_cursor_read * pr, |
232 | | stream_cursor_write * pw, bool last) |
233 | 1.54M | { |
234 | 1.54M | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
235 | 1.54M | int bpp = ss->bpp; |
236 | 1.54M | int status = 0; |
237 | | |
238 | 3.85M | while (pr->ptr < pr->limit) { |
239 | 3.33M | uint count; |
240 | | |
241 | 3.33M | if (ss->row_left == 0) { |
242 | | /* Beginning of row, write algorithm byte. */ |
243 | 680k | int predictor; |
244 | | |
245 | 680k | if (pw->ptr >= pw->limit) { |
246 | 19.2k | status = 1; |
247 | 19.2k | break; |
248 | 19.2k | } |
249 | 661k | predictor = |
250 | 661k | (ss->Predictor == cOptimum ? |
251 | 661k | optimum_predictor(st, pr) : |
252 | 661k | ss->Predictor); |
253 | 661k | *++(pw->ptr) = (byte) predictor - cNone; |
254 | 661k | ss->case_index = predictor + cEncode; |
255 | 661k | ss->row_left = ss->row_count; |
256 | 661k | memset(ss->prev, 0, bpp); |
257 | 661k | continue; |
258 | 680k | } |
259 | 2.65M | count = s_pngp_count(st, pr, pw); |
260 | 2.65M | if (count == 0) { |
261 | | /* We know we have input, so output must be full. */ |
262 | 1.00M | status = 1; |
263 | 1.00M | break; |
264 | 1.65M | } { |
265 | 1.65M | byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left; |
266 | 1.65M | uint n = min(count, bpp); |
267 | | |
268 | | /* Process bytes whose predecessors are in prev. */ |
269 | 1.65M | s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n); |
270 | 1.65M | if (ss->row_left == 0) { |
271 | 8.12k | if (ss->prev_row) { |
272 | 8.12k | memcpy(up - bpp, ss->prev, bpp); |
273 | 8.12k | memcpy(up, pr->ptr - (n - 1), n); |
274 | 8.12k | } |
275 | 8.12k | continue; |
276 | 8.12k | } |
277 | 1.64M | if (ss->prev_row) |
278 | 1.64M | memcpy(up - bpp, ss->prev, n); |
279 | 1.64M | 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 | 8.52k | int prev_left = bpp - n; |
286 | | |
287 | 8.52k | memmove(ss->prev, ss->prev + n, prev_left); |
288 | 8.52k | memcpy(ss->prev + prev_left, pr->ptr - (n - 1), n); |
289 | 8.52k | if (pw->ptr >= pw->limit && pr->ptr < pr->limit) |
290 | 2.40k | status = 1; |
291 | 8.52k | break; |
292 | 8.52k | } |
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 | 1.63M | count -= bpp; |
297 | 1.63M | s_pngp_process(st, pw, pr->ptr - (bpp - 1), pr, |
298 | 1.63M | up, up + bpp, count); |
299 | 1.63M | memcpy(ss->prev, pr->ptr - (bpp - 1), bpp); |
300 | 1.63M | if (ss->prev_row) { |
301 | 1.63M | memcpy(up, pr->ptr - (bpp + count - 1), count); |
302 | 1.63M | if (ss->row_left == 0) |
303 | 649k | memcpy(up + count, ss->prev, bpp); |
304 | 1.63M | } |
305 | 1.63M | } |
306 | 1.63M | } |
307 | 1.54M | return status; |
308 | 1.54M | } |
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 | 526k | { |
328 | 526k | stream_PNGP_state *const ss = (stream_PNGP_state *) st; |
329 | 526k | int bpp = ss->bpp; |
330 | 526k | int status = 0; |
331 | | |
332 | 5.83M | while (pr->ptr < pr->limit) { |
333 | 5.53M | uint count; |
334 | | |
335 | 5.53M | if (ss->row_left == 0) { |
336 | | /* Beginning of row, read algorithm byte. */ |
337 | 2.44M | int predictor = pr->ptr[1]; |
338 | | |
339 | 2.44M | if (predictor >= cOptimum - cNone) { |
340 | 10.6k | status = ERRC; |
341 | 10.6k | break; |
342 | 10.6k | } |
343 | 2.43M | pr->ptr++; |
344 | 2.43M | ss->case_index = predictor + cNone + cDecode; |
345 | 2.43M | ss->row_left = ss->row_count; |
346 | 2.43M | memset(ss->prev, 0, bpp); |
347 | 2.43M | continue; |
348 | 2.44M | } |
349 | 3.09M | count = s_pngp_count(st, pr, pw); |
350 | 3.09M | if (count == 0) { |
351 | | /* We know we have input, so output must be full. */ |
352 | 214k | status = 1; |
353 | 214k | break; |
354 | 2.87M | } { |
355 | 2.87M | byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left; |
356 | 2.87M | uint n = min(count, bpp); |
357 | | |
358 | | /* Process bytes whose predecessors are in prev. */ |
359 | 2.87M | s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n); |
360 | 2.87M | if (ss->row_left == 0) { |
361 | 212k | if (ss->prev_row) { |
362 | 212k | memcpy(up - bpp, ss->prev, bpp); |
363 | 212k | memcpy(up, pw->ptr - (n - 1), n); |
364 | 212k | } |
365 | 212k | continue; |
366 | 212k | } |
367 | 2.66M | if (ss->prev_row) |
368 | 2.66M | memcpy(up - bpp, ss->prev, n); |
369 | 2.66M | 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 | 3.16k | int prev_left = bpp - n; |
376 | | |
377 | 3.16k | memmove(ss->prev, ss->prev + n, prev_left); |
378 | 3.16k | memcpy(ss->prev + prev_left, pw->ptr - (n - 1), n); |
379 | 3.16k | if (pw->ptr >= pw->limit && pr->ptr < pr->limit) |
380 | 181 | status = 1; |
381 | 3.16k | break; |
382 | 3.16k | } |
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 | 2.66M | count -= bpp; |
387 | 2.66M | s_pngp_process(st, pw, pw->ptr - (bpp - 1), pr, |
388 | 2.66M | up, up + bpp, count); |
389 | 2.66M | memcpy(ss->prev, pw->ptr - (bpp - 1), bpp); |
390 | 2.66M | if (ss->prev_row) { |
391 | 2.66M | memcpy(up, pw->ptr - (bpp + count - 1), count); |
392 | 2.66M | if (ss->row_left == 0) |
393 | 2.22M | memcpy(up + count, ss->prev, bpp); |
394 | 2.66M | } |
395 | 2.66M | } |
396 | 2.66M | } |
397 | 526k | return status; |
398 | 526k | } |
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 | | }; |