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