/src/ghostpdl/base/sjpegc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 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 | | /* Interface routines for IJG code, common to encode/decode. */ |
18 | | #include "stdio_.h" |
19 | | #include "string_.h" |
20 | | #include "jpeglib_.h" |
21 | | #include "jerror_.h" |
22 | | #include "gx.h" |
23 | | #include "gserrors.h" |
24 | | #include "strimpl.h" |
25 | | #include "sdct.h" |
26 | | #include "sjpeg.h" |
27 | | #include "gsmchunk.h" |
28 | | #include "setjmp_.h" |
29 | | |
30 | | #if !defined(SHARE_JPEG) || SHARE_JPEG==0 |
31 | | #include "jmemcust.h" |
32 | | #endif |
33 | | |
34 | | /* |
35 | | Ghostscript uses a non-public interface to libjpeg in order to |
36 | | override the library's default memory manager implementation. |
37 | | Since many users will want to compile Ghostscript using the |
38 | | shared jpeg library, we provide these prototypes so that a copy |
39 | | of the libjpeg source distribution is not needed. |
40 | | |
41 | | The presence of the jmemsys.h header file is detected in |
42 | | unix-aux.mak, and written to gconfig_.h |
43 | | */ |
44 | | |
45 | | #include "gconfig_.h" |
46 | | |
47 | | /* |
48 | | * Error handling routines (these replace corresponding IJG routines from |
49 | | * jpeg/jerror.c). These are used for both compression and decompression. |
50 | | * We assume |
51 | | * offset_of(jpeg_compress_data, cinfo)==offset_of(jpeg_decompress_data, dinfo) |
52 | | */ |
53 | | |
54 | | OPTIMIZE_SETJMP |
55 | | static void |
56 | | gs_jpeg_error_exit(j_common_ptr cinfo) |
57 | 4.16k | { |
58 | 4.16k | jpeg_stream_data *jcomdp = |
59 | 4.16k | (jpeg_stream_data *) ((char *)cinfo - |
60 | 4.16k | offset_of(jpeg_compress_data, cinfo)); |
61 | | |
62 | 4.16k | longjmp(find_jmp_buf(jcomdp->exit_jmpbuf), 1); |
63 | 4.16k | } |
64 | | |
65 | | static void |
66 | | gs_jpeg_emit_message(j_common_ptr cinfo, int msg_level) |
67 | 548k | { |
68 | 548k | if (msg_level < 0) { /* GS policy is to ignore IJG warnings when Picky=0, |
69 | | * treat them as errors when Picky=1. |
70 | | */ |
71 | 154k | jpeg_stream_data *jcomdp = |
72 | 154k | (jpeg_stream_data *) ((char *)cinfo - |
73 | 154k | offset_of(jpeg_compress_data, cinfo)); |
74 | | |
75 | 154k | if (jcomdp->Picky) |
76 | 0 | gs_jpeg_error_exit(cinfo); |
77 | 154k | } |
78 | | /* Trace messages are always ignored. */ |
79 | 548k | } |
80 | | |
81 | | /* |
82 | | * This routine initializes the error manager fields in the JPEG object. |
83 | | * It is based on jpeg_std_error from jpeg/jerror.c. |
84 | | */ |
85 | | |
86 | | void |
87 | | gs_jpeg_error_setup(stream_DCT_state * st) |
88 | 19.5k | { |
89 | 19.5k | struct jpeg_error_mgr *err = &st->data.common->err; |
90 | | |
91 | | /* Initialize the JPEG compression object with default error handling */ |
92 | 19.5k | jpeg_std_error(err); |
93 | | |
94 | | /* Replace some methods with our own versions */ |
95 | 19.5k | err->error_exit = gs_jpeg_error_exit; |
96 | 19.5k | err->emit_message = gs_jpeg_emit_message; |
97 | | |
98 | 19.5k | st->data.compress->cinfo.err = err; /* works for decompress case too */ |
99 | 19.5k | } |
100 | | |
101 | | /* Stuff the IJG error message into errorinfo after an error exit. */ |
102 | | |
103 | | int |
104 | | gs_jpeg_log_error(stream_DCT_state * st) |
105 | 4.16k | { |
106 | 4.16k | j_common_ptr cinfo = (j_common_ptr) & st->data.compress->cinfo; |
107 | 4.16k | char buffer[JMSG_LENGTH_MAX]; |
108 | | |
109 | | /* Format the error message */ |
110 | 4.16k | (*cinfo->err->format_message) (cinfo, buffer); |
111 | 4.16k | (*st->report_error) ((stream_state *) st, buffer); |
112 | 4.16k | return_error(gs_error_ioerror); /* caller will do return_error() */ |
113 | 4.16k | } |
114 | | |
115 | | /* |
116 | | * Interface routines. This layer of routines exists solely to limit |
117 | | * side-effects from using setjmp. |
118 | | */ |
119 | | |
120 | | OPTIMIZE_SETJMP |
121 | | JQUANT_TBL * |
122 | | gs_jpeg_alloc_quant_table(stream_DCT_state * st) |
123 | 0 | { |
124 | 0 | if (setjmp(find_jmp_buf(st->data.common->exit_jmpbuf))) { |
125 | 0 | gs_jpeg_log_error(st); |
126 | 0 | return NULL; |
127 | 0 | } |
128 | 0 | return jpeg_alloc_quant_table((j_common_ptr) |
129 | 0 | & st->data.compress->cinfo); |
130 | 0 | } |
131 | | |
132 | | OPTIMIZE_SETJMP |
133 | | JHUFF_TBL * |
134 | | gs_jpeg_alloc_huff_table(stream_DCT_state * st) |
135 | 0 | { |
136 | 0 | if (setjmp(find_jmp_buf(st->data.common->exit_jmpbuf))) { |
137 | 0 | gs_jpeg_log_error(st); |
138 | 0 | return NULL; |
139 | 0 | } |
140 | 0 | return jpeg_alloc_huff_table((j_common_ptr) |
141 | 0 | & st->data.compress->cinfo); |
142 | 0 | } |
143 | | |
144 | | OPTIMIZE_SETJMP |
145 | | int |
146 | | gs_jpeg_destroy(stream_DCT_state * st) |
147 | 19.5k | { |
148 | 19.5k | if (st->data.common && setjmp(find_jmp_buf(st->data.common->exit_jmpbuf))) |
149 | 0 | return_error(gs_jpeg_log_error(st)); |
150 | | |
151 | 19.5k | if (st->data.compress){ |
152 | 19.5k | jpeg_destroy((j_common_ptr) & st->data.compress->cinfo); |
153 | 19.5k | gs_jpeg_mem_term((j_common_ptr) & st->data.compress->cinfo); |
154 | 19.5k | } |
155 | 19.5k | return 0; |
156 | 19.5k | } |
157 | | |
158 | | #if !defined(SHARE_JPEG) || SHARE_JPEG==0 |
159 | | static void *gs_j_mem_alloc(j_common_ptr cinfo, size_t size) |
160 | 137k | { |
161 | 137k | gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv); |
162 | | |
163 | 137k | return(gs_alloc_bytes(mem, size, "JPEG allocation")); |
164 | 137k | } |
165 | | |
166 | | static void gs_j_mem_free(j_common_ptr cinfo, void *object, size_t size) |
167 | 137k | { |
168 | 137k | gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv); |
169 | | |
170 | 137k | gs_free_object(mem, object, "JPEG free"); |
171 | 137k | } |
172 | | |
173 | | static long gs_j_mem_init (j_common_ptr cinfo) |
174 | 19.5k | { |
175 | 19.5k | gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv); |
176 | 19.5k | gs_memory_t *cmem = NULL; |
177 | | |
178 | 19.5k | if (gs_memory_chunk_wrap(&(cmem), mem) < 0) { |
179 | 0 | return (-1); |
180 | 0 | } |
181 | | |
182 | 19.5k | (void)jpeg_cust_mem_set_private(GET_CUST_MEM_DATA(cinfo), cmem); |
183 | | |
184 | 19.5k | return 0; |
185 | 19.5k | } |
186 | | |
187 | | static void gs_j_mem_term (j_common_ptr cinfo) |
188 | 19.5k | { |
189 | 19.5k | gs_memory_t *cmem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv); |
190 | 19.5k | gs_memory_t *mem = gs_memory_chunk_unwrap(cmem); |
191 | | |
192 | 19.5k | if (mem == cmem) |
193 | 0 | return; |
194 | | |
195 | 19.5k | (void)jpeg_cust_mem_set_private(GET_CUST_MEM_DATA(cinfo), mem); |
196 | 19.5k | } |
197 | | #endif /* SHAREJPEG == 0 */ |
198 | | |
199 | | |
200 | | int gs_jpeg_mem_init (gs_memory_t *mem, j_common_ptr cinfo) |
201 | 19.5k | { |
202 | 19.5k | int code = 0; |
203 | 19.5k | #if !defined(SHARE_JPEG) || SHARE_JPEG==0 |
204 | 19.5k | jpeg_cust_mem_data custm, *custmptr; |
205 | | |
206 | 19.5k | memset(&custm, 0x00, sizeof(custm)); |
207 | | |
208 | | /* JPEG allocated chunks don't need to be subject to gc. */ |
209 | 19.5k | mem = mem->non_gc_memory; |
210 | | |
211 | 19.5k | if (!jpeg_cust_mem_init(&custm, (void *) mem, gs_j_mem_init, gs_j_mem_term, NULL, |
212 | 19.5k | gs_j_mem_alloc, gs_j_mem_free, |
213 | 19.5k | gs_j_mem_alloc, gs_j_mem_free, NULL)) { |
214 | 0 | code = gs_note_error(gs_error_VMerror); |
215 | 0 | } |
216 | 19.5k | if (code == 0) { |
217 | 19.5k | custmptr = (jpeg_cust_mem_data *)gs_alloc_bytes(mem, sizeof(custm) + sizeof(void *), "JPEG custom memory descriptor"); |
218 | 19.5k | if (!custmptr) { |
219 | 0 | code = gs_note_error(gs_error_VMerror); |
220 | 0 | } |
221 | 19.5k | else { |
222 | 19.5k | memcpy(custmptr, &custm, sizeof(custm)); |
223 | 19.5k | cinfo->client_data = custmptr; |
224 | 19.5k | } |
225 | 19.5k | } |
226 | 19.5k | #endif /* SHAREJPEG == 0 */ |
227 | 19.5k | return code; |
228 | 19.5k | } |
229 | | |
230 | | void |
231 | | gs_jpeg_mem_term(j_common_ptr cinfo) |
232 | 19.5k | { |
233 | 19.5k | #if !defined(SHARE_JPEG) || SHARE_JPEG==0 |
234 | 19.5k | if (cinfo->client_data) { |
235 | 19.5k | jpeg_cust_mem_data *custmptr = (jpeg_cust_mem_data *)cinfo->client_data; |
236 | 19.5k | gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv); |
237 | | |
238 | 19.5k | gs_free_object(mem, custmptr, "gs_jpeg_mem_term"); |
239 | 19.5k | cinfo->client_data = NULL; |
240 | 19.5k | } |
241 | 19.5k | #endif /* SHAREJPEG == 0 */ |
242 | 19.5k | } |