/src/ghostpdl/base/sdctd.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 | | /* 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 | 13.2k | { |
34 | 13.2k | } |
35 | | static const JOCTET fake_eoi[2] = |
36 | | {0xFF, JPEG_EOI}; |
37 | | static boolean |
38 | | dctd_fill_input_buffer(j_decompress_ptr dinfo) |
39 | 112k | { |
40 | 112k | jpeg_decompress_data *jddp = |
41 | 112k | (jpeg_decompress_data *) ((char *)dinfo - |
42 | 112k | offset_of(jpeg_decompress_data, dinfo)); |
43 | | |
44 | 112k | if (!jddp->input_eod) |
45 | 111k | return FALSE; /* normal case: suspend processing */ |
46 | | /* Reached end of source data without finding EOI */ |
47 | 1.42k | WARNMS(dinfo, JWRN_JPEG_EOF); |
48 | | /* Insert a fake EOI marker */ |
49 | 1.42k | dinfo->src->next_input_byte = fake_eoi; |
50 | 1.42k | dinfo->src->bytes_in_buffer = 2; |
51 | 1.42k | jddp->faked_eoi = true; /* so process routine doesn't use next_input_byte */ |
52 | 1.42k | return TRUE; |
53 | 112k | } |
54 | | static void |
55 | | dctd_skip_input_data(j_decompress_ptr dinfo, long num_bytes) |
56 | 12.3k | { |
57 | 12.3k | struct jpeg_source_mgr *src = dinfo->src; |
58 | 12.3k | jpeg_decompress_data *jddp = |
59 | 12.3k | (jpeg_decompress_data *) ((char *)dinfo - |
60 | 12.3k | offset_of(jpeg_decompress_data, dinfo)); |
61 | | |
62 | 12.3k | if (num_bytes > 0) { |
63 | 12.3k | if (num_bytes > src->bytes_in_buffer) { |
64 | 8.10k | jddp->skip += num_bytes - src->bytes_in_buffer; |
65 | 8.10k | src->next_input_byte += src->bytes_in_buffer; |
66 | 8.10k | src->bytes_in_buffer = 0; |
67 | 8.10k | return; |
68 | 8.10k | } |
69 | 4.20k | src->next_input_byte += num_bytes; |
70 | 4.20k | src->bytes_in_buffer -= num_bytes; |
71 | 4.20k | } |
72 | 12.3k | } |
73 | | |
74 | | static void |
75 | | dctd_term_source(j_decompress_ptr dinfo) |
76 | 8.88k | { |
77 | 8.88k | jpeg_decompress_data *jddp = |
78 | 8.88k | (jpeg_decompress_data *) ((char *)dinfo - |
79 | 8.88k | offset_of(jpeg_decompress_data, dinfo)); |
80 | | |
81 | 8.88k | stream_dct_end_passthrough(jddp); |
82 | 8.88k | return; |
83 | 8.88k | } |
84 | | |
85 | | /* Set the defaults for the DCTDecode filter. */ |
86 | | static void |
87 | | s_DCTD_set_defaults(stream_state * st) |
88 | 26.7k | { |
89 | 26.7k | s_DCT_set_defaults(st); |
90 | 26.7k | } |
91 | | |
92 | | /* Initialize DCTDecode filter */ |
93 | | static int |
94 | | s_DCTD_init(stream_state * st) |
95 | 13.3k | { |
96 | 13.3k | stream_DCT_state *const ss = (stream_DCT_state *) st; |
97 | 13.3k | struct jpeg_source_mgr *src = &ss->data.decompress->source; |
98 | | |
99 | 13.3k | src->init_source = dctd_init_source; |
100 | 13.3k | src->fill_input_buffer = dctd_fill_input_buffer; |
101 | 13.3k | src->skip_input_data = dctd_skip_input_data; |
102 | 13.3k | src->term_source = dctd_term_source; |
103 | 13.3k | src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ |
104 | 13.3k | ss->data.common->memory = ss->jpeg_memory; |
105 | 13.3k | ss->data.decompress->dinfo.src = src; |
106 | 13.3k | ss->data.decompress->skip = 0; |
107 | 13.3k | ss->data.decompress->input_eod = false; |
108 | 13.3k | ss->data.decompress->faked_eoi = false; |
109 | 13.3k | ss->phase = 0; |
110 | 13.3k | return 0; |
111 | 13.3k | } |
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 | 26.7k | { |
150 | 26.7k | int marker_len; |
151 | | |
152 | 96.2k | for (d += 2; len > 9 && d[0] == 0xFF; d += marker_len) |
153 | 73.9k | { |
154 | 73.9k | int declared_height; |
155 | | |
156 | 73.9k | marker_len = 2 + (d[2] << 8) + d[3]; |
157 | 73.9k | if (marker_len > len) |
158 | 4.38k | break; |
159 | 69.5k | len -= marker_len; |
160 | | |
161 | | /* We can only safely rewrite non-differential SOF markers */ |
162 | 69.5k | if (d[1] < 0xC0 || (0xC3 < d[1] && d[1] < 0xC9) || 0xCB < d[1]) |
163 | 60.7k | continue; |
164 | | |
165 | 8.77k | declared_height = (d[5]<<8) | d[6]; |
166 | 8.77k | if (declared_height == 0 || declared_height > height) |
167 | 188 | { |
168 | 188 | d[5] = height>>8; |
169 | 188 | d[6] = height; |
170 | 188 | } |
171 | 8.77k | } |
172 | 26.7k | } |
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 | 2.12M | { |
179 | 2.12M | stream_DCT_state *const ss = (stream_DCT_state *) st; |
180 | 2.12M | jpeg_decompress_data *jddp = ss->data.decompress; |
181 | 2.12M | struct jpeg_source_mgr *src = jddp->dinfo.src; |
182 | 2.12M | int code; |
183 | 2.12M | byte *Buf; |
184 | | |
185 | 2.12M | if_debug3m('w', st->memory, "[wdd]process avail=%u, skip=%u, last=%d\n", |
186 | 2.12M | (uint) (pr->limit - pr->ptr), (uint) jddp->skip, last); |
187 | 2.12M | if (jddp->skip != 0) { |
188 | 30.5k | long avail = pr->limit - pr->ptr; |
189 | | |
190 | 30.5k | if (avail < jddp->skip) { |
191 | 22.8k | if (jddp->PassThrough && jddp->PassThroughfn) |
192 | 5.18k | (jddp->PassThroughfn)(jddp->device, (byte *)pr->ptr + 1, (byte *)pr->limit - (byte *)pr->ptr); |
193 | | |
194 | 22.8k | jddp->skip -= avail; |
195 | 22.8k | pr->ptr = pr->limit; |
196 | 22.8k | if (!last) |
197 | 22.6k | return 0; /* need more data */ |
198 | 196 | jddp->skip = 0; /* don't skip past input EOD */ |
199 | 196 | } |
200 | 7.88k | Buf = (byte *)pr->ptr + 1; |
201 | 7.88k | pr->ptr += jddp->skip; |
202 | 7.88k | if (jddp->PassThrough && jddp->PassThroughfn) |
203 | 2.31k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
204 | | |
205 | 7.88k | jddp->skip = 0; |
206 | 7.88k | } |
207 | 2.10M | src->next_input_byte = pr->ptr + 1; |
208 | 2.10M | src->bytes_in_buffer = pr->limit - pr->ptr; |
209 | 2.10M | Buf = (byte *)pr->ptr + 1; |
210 | 2.10M | jddp->input_eod = last; |
211 | 2.10M | switch (ss->phase) { |
212 | 26.6k | 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 | 26.6k | if (jddp->PassThrough && jddp->PassThroughfn && !jddp->StartedPassThrough) { |
219 | 3.01k | jddp->StartedPassThrough = 1; |
220 | 3.01k | (jddp->PassThroughfn)(jddp->device, NULL, 1); |
221 | 3.01k | } |
222 | 36.2k | while (pr->ptr < pr->limit && pr->ptr[1] != 0xff) |
223 | 9.58k | pr->ptr++; |
224 | 26.6k | if (pr->ptr == pr->limit) { |
225 | 13.3k | if (jddp->PassThrough && jddp->PassThroughfn) |
226 | 3.02k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
227 | 13.3k | return 0; |
228 | 13.3k | } |
229 | 13.2k | src->next_input_byte = pr->ptr + 1; |
230 | 13.2k | src->bytes_in_buffer = pr->limit - pr->ptr; |
231 | 13.2k | ss->phase = 1; |
232 | | /* falls through */ |
233 | 26.8k | case 1: /* reading header markers */ |
234 | 26.8k | if (ss->data.common->Height != 0) |
235 | 26.7k | { |
236 | | /* Deliberate and naughty. We cast away a const pointer |
237 | | * here and write to a supposedly read-only stream. */ |
238 | 26.7k | union { const byte *c; byte *u; } u; |
239 | 26.7k | u.c = pr->ptr+1; |
240 | 26.7k | update_jpeg_header_height(u.u, src->bytes_in_buffer, ss->data.common->Height); |
241 | 26.7k | } |
242 | 26.8k | if ((code = gs_jpeg_read_header(ss, TRUE)) < 0) { |
243 | 3.22k | code = ERRC; |
244 | 3.22k | goto error_out; |
245 | 3.22k | } |
246 | 23.6k | pr->ptr = |
247 | 23.6k | (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1); |
248 | 23.6k | switch (code) { |
249 | 13.6k | case JPEG_SUSPENDED: |
250 | 13.6k | if (jddp->PassThrough && jddp->PassThroughfn) |
251 | 4.24k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
252 | 13.6k | return 0; |
253 | | /*case JPEG_HEADER_OK: */ |
254 | 23.6k | } |
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 | 10.0k | if (ss->ColorTransform == -1) { |
262 | 10.0k | if (jddp->dinfo.num_components == 3) |
263 | 8.64k | ss->ColorTransform = 1; |
264 | 1.35k | else |
265 | 1.35k | ss->ColorTransform = 0; |
266 | 10.0k | } |
267 | | |
268 | 10.0k | if (jddp->dinfo.saw_Adobe_marker) |
269 | 5.96k | ss->ColorTransform = jddp->dinfo.Adobe_transform; |
270 | | |
271 | 10.0k | switch (jddp->dinfo.num_components) { |
272 | 8.64k | case 3: |
273 | 8.64k | jddp->dinfo.jpeg_color_space = |
274 | 8.64k | (ss->ColorTransform ? JCS_YCbCr : JCS_RGB); |
275 | | /* out_color_space will default to JCS_RGB */ |
276 | 8.64k | break; |
277 | 415 | case 4: |
278 | 415 | jddp->dinfo.jpeg_color_space = |
279 | 415 | (ss->ColorTransform ? JCS_YCCK : JCS_CMYK); |
280 | | /* out_color_space will default to JCS_CMYK */ |
281 | 415 | break; |
282 | 10.0k | } |
283 | 10.0k | ss->phase = 2; |
284 | | /* falls through */ |
285 | 17.2k | case 2: /* start_decompress */ |
286 | 17.2k | if ((code = gs_jpeg_start_decompress(ss)) < 0) { |
287 | 46 | code = ERRC; |
288 | 46 | goto error_out; |
289 | 46 | } |
290 | 17.1k | pr->ptr = |
291 | 17.1k | (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1); |
292 | 17.1k | if (code == 0) { |
293 | 7.23k | if (jddp->PassThrough && jddp->PassThroughfn) |
294 | 2.84k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
295 | 7.23k | return 0; |
296 | 7.23k | } |
297 | 9.94k | ss->scan_line_size = |
298 | 9.94k | jddp->dinfo.output_width * jddp->dinfo.output_components; |
299 | 9.94k | if_debug4m('w', ss->memory, "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n", |
300 | 9.94k | jddp->dinfo.output_width, |
301 | 9.94k | jddp->dinfo.output_components, |
302 | 9.94k | ss->scan_line_size, jddp->templat.min_out_size); |
303 | 9.94k | if (ss->scan_line_size > (uint) jddp->templat.min_out_size) { |
304 | | /* Create a spare buffer for oversize scanline */ |
305 | 424 | jddp->scanline_buffer = |
306 | 424 | gs_alloc_bytes_immovable(gs_memory_stable(jddp->memory), |
307 | 424 | ss->scan_line_size, |
308 | 424 | "s_DCTD_process(scanline_buffer)"); |
309 | 424 | if (jddp->scanline_buffer == NULL) { |
310 | 0 | code = ERRC; |
311 | 0 | goto error_out; |
312 | 0 | } |
313 | 424 | } |
314 | 9.94k | jddp->bytes_in_scanline = 0; |
315 | 9.94k | ss->phase = 3; |
316 | | /* falls through */ |
317 | 2.06M | case 3: /* reading data */ |
318 | 2.67M | dumpbuffer: |
319 | 2.67M | if (jddp->bytes_in_scanline != 0) { |
320 | 1.49M | uint avail = pw->limit - pw->ptr; |
321 | 1.49M | uint tomove = min(jddp->bytes_in_scanline, |
322 | 1.49M | avail); |
323 | | |
324 | 1.49M | if_debug2m('w', ss->memory, "[wdd]moving %u/%u\n", |
325 | 1.49M | tomove, avail); |
326 | 1.49M | memcpy(pw->ptr + 1, jddp->scanline_buffer + |
327 | 1.49M | (ss->scan_line_size - jddp->bytes_in_scanline), |
328 | 1.49M | tomove); |
329 | 1.49M | pw->ptr += tomove; |
330 | 1.49M | 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.49M | avail -= tomove; |
338 | 1.49M | if ((jddp->bytes_in_scanline != 0) || /* no room for complete scan */ |
339 | 1.49M | ((jddp->bytes_in_scanline == 0) && (tomove > 0) && /* 1 scancopy completed */ |
340 | 609k | (avail < tomove) && /* still room for 1 more scan */ |
341 | 609k | (jddp->dinfo.output_height > jddp->dinfo.output_scanline))) /* more scans to do */ |
342 | 1.22M | { |
343 | 1.22M | if (jddp->PassThrough && jddp->PassThroughfn) { |
344 | 78.1k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
345 | 78.1k | } |
346 | 1.22M | return 1; /* need more room */ |
347 | 1.22M | } |
348 | 1.49M | } |
349 | | /* while not done with image, decode 1 scan, otherwise fall into phase 4 */ |
350 | 3.01M | while (jddp->dinfo.output_height > jddp->dinfo.output_scanline) { |
351 | 3.00M | int read; |
352 | 3.00M | byte *samples; |
353 | | |
354 | 3.00M | if (jddp->scanline_buffer != NULL) |
355 | 630k | samples = jddp->scanline_buffer; |
356 | 2.37M | else { |
357 | 2.37M | if ((uint) (pw->limit - pw->ptr) < ss->scan_line_size) { |
358 | 739k | if (jddp->PassThrough && jddp->PassThroughfn) { |
359 | 144k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
360 | 144k | } |
361 | 739k | return 1; /* need more room */ |
362 | 739k | } |
363 | 1.63M | samples = pw->ptr + 1; |
364 | 1.63M | } |
365 | 2.26M | read = gs_jpeg_read_scanlines(ss, &samples, 1); |
366 | 2.26M | if (read < 0) { |
367 | 0 | code = ERRC; |
368 | 0 | goto error_out; |
369 | 0 | } |
370 | 2.26M | if_debug3m('w', ss->memory, "[wdd]read returns %d, used=%u, faked_eoi=%d\n", |
371 | 2.26M | read, |
372 | 2.26M | (uint) (src->next_input_byte - 1 - pr->ptr), |
373 | 2.26M | (int)jddp->faked_eoi); |
374 | 2.26M | pr->ptr = |
375 | 2.26M | (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1); |
376 | 2.26M | 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 | 87.5k | if ((src->next_input_byte-1 == pr->ptr) && |
390 | 87.5k | (pr->limit - pr->ptr >= ss->templat->min_in_size) && |
391 | 87.5k | (compact_jpeg_buffer(pr) == 0)) { |
392 | 0 | code = ERRC; |
393 | 0 | goto error_out; |
394 | 0 | } |
395 | 87.5k | if (jddp->PassThrough && jddp->PassThroughfn) { |
396 | 14.0k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
397 | 14.0k | } |
398 | 87.5k | return 0; /* need more data */ |
399 | 87.5k | } |
400 | 2.17M | if (jddp->scanline_buffer != NULL) { |
401 | 609k | jddp->bytes_in_scanline = ss->scan_line_size; |
402 | 609k | goto dumpbuffer; |
403 | 609k | } |
404 | 1.56M | pw->ptr += ss->scan_line_size; |
405 | 1.56M | } |
406 | 9.75k | ss->phase = 4; |
407 | | /* falls through */ |
408 | 12.6k | case 4: /* end of image; scan for EOI */ |
409 | 12.6k | if (jddp->PassThrough && jddp->PassThroughfn) |
410 | 2.15k | (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1)); |
411 | 12.6k | if ((code = gs_jpeg_finish_decompress(ss)) < 0) { |
412 | 862 | code = ERRC; |
413 | 862 | goto error_out; |
414 | 862 | } |
415 | 11.8k | pr->ptr = |
416 | 11.8k | (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1); |
417 | 11.8k | if (code == 0) |
418 | 2.92k | return 0; |
419 | 8.88k | ss->phase = 5; |
420 | | /* falls through */ |
421 | 8.88k | case 5: /* we are DONE */ |
422 | 8.88k | return EOFC; |
423 | 2.10M | } |
424 | | /* Default case can't happen.... */ |
425 | 0 | return ERRC; |
426 | | |
427 | 4.13k | error_out: |
428 | 4.13k | stream_dct_end_passthrough(jddp); |
429 | 4.13k | return code; |
430 | 2.10M | } |
431 | | |
432 | | /* Stream template */ |
433 | | const stream_template s_DCTD_template = |
434 | | {&st_DCT_state, s_DCTD_init, s_DCTD_process, 2000, 4000, NULL, |
435 | | s_DCTD_set_defaults |
436 | | }; |