1#include "mupdf/fitz.h"
2
3#include <stdio.h>
4#include <jpeglib.h>
5
6#ifndef SHARE_JPEG
7typedef void * backing_store_ptr;
8#include "jmemcust.h"
9#endif
10
11typedef struct fz_dctd_s fz_dctd;
12
13struct fz_dctd_s
14{
15 fz_stream *chain;
16 fz_stream *jpegtables;
17 fz_stream *curr_stm;
18 fz_context *ctx;
19 int color_transform;
20 int init;
21 int stride;
22 int l2factor;
23 unsigned char *scanline;
24 unsigned char *rp, *wp;
25 struct jpeg_decompress_struct cinfo;
26 struct jpeg_source_mgr srcmgr;
27 struct jpeg_error_mgr errmgr;
28 jmp_buf jb;
29 char msg[JMSG_LENGTH_MAX];
30
31 unsigned char buffer[4096];
32};
33
34#ifdef SHARE_JPEG
35
36#define JZ_DCT_STATE_FROM_CINFO(c) (fz_dctd *)((c)->client_data)
37
38static void fz_dct_mem_init(struct jpeg_decompress_struct *cinfo, fz_dctd *state)
39{
40 cinfo->client_data = state;
41}
42
43#define fz_dct_mem_term(cinfo)
44
45#else /* SHARE_JPEG */
46
47#define JZ_DCT_STATE_FROM_CINFO(c) (fz_dctd *)(GET_CUST_MEM_DATA(c)->priv)
48
49static void *
50fz_dct_mem_alloc(j_common_ptr cinfo, size_t size)
51{
52 fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo);
53 return fz_malloc_no_throw(state->ctx, size);
54}
55
56static void
57fz_dct_mem_free(j_common_ptr cinfo, void *object, size_t size)
58{
59 fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo);
60 fz_free(state->ctx, object);
61}
62
63static void
64fz_dct_mem_init(struct jpeg_decompress_struct *cinfo, fz_dctd *state)
65{
66 jpeg_cust_mem_data *custmptr;
67 custmptr = fz_malloc_struct(state->ctx, jpeg_cust_mem_data);
68 if (!jpeg_cust_mem_init(custmptr, (void *) state, NULL, NULL, NULL,
69 fz_dct_mem_alloc, fz_dct_mem_free,
70 fz_dct_mem_alloc, fz_dct_mem_free, NULL))
71 {
72 fz_free(state->ctx, custmptr);
73 fz_throw(state->ctx, FZ_ERROR_GENERIC, "cannot initialize custom JPEG memory handler");
74 }
75 cinfo->client_data = custmptr;
76}
77
78static void
79fz_dct_mem_term(struct jpeg_decompress_struct *cinfo)
80{
81 if (cinfo->client_data)
82 {
83 fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo);
84 fz_free(state->ctx, cinfo->client_data);
85 cinfo->client_data = NULL;
86 }
87}
88
89#endif /* SHARE_JPEG */
90
91static void error_exit_dct(j_common_ptr cinfo)
92{
93 char msg[JMSG_LENGTH_MAX];
94 fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo);
95 fz_context *ctx = state->ctx;
96 cinfo->err->format_message(cinfo, msg);
97 fz_throw(ctx, FZ_ERROR_GENERIC, "jpeg error: %s", msg);
98}
99
100static void init_source_dct(j_decompress_ptr cinfo)
101{
102 /* nothing to do */
103}
104
105static void term_source_dct(j_decompress_ptr cinfo)
106{
107 /* nothing to do */
108}
109
110static boolean fill_input_buffer_dct(j_decompress_ptr cinfo)
111{
112 struct jpeg_source_mgr *src = cinfo->src;
113 fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo);
114 fz_context *ctx = state->ctx;
115 fz_stream *curr_stm = state->curr_stm;
116
117 curr_stm->rp = curr_stm->wp;
118 fz_try(ctx)
119 {
120 src->bytes_in_buffer = fz_available(ctx, curr_stm, 1);
121 }
122 fz_catch(ctx)
123 {
124 return 0;
125 }
126 src->next_input_byte = curr_stm->rp;
127
128 if (src->bytes_in_buffer == 0)
129 {
130 static unsigned char eoi[2] = { 0xFF, JPEG_EOI };
131 fz_warn(state->ctx, "premature end of file in jpeg");
132 src->next_input_byte = eoi;
133 src->bytes_in_buffer = 2;
134 }
135
136 return 1;
137}
138
139static void skip_input_data_dct(j_decompress_ptr cinfo, long num_bytes)
140{
141 struct jpeg_source_mgr *src = cinfo->src;
142 if (num_bytes > 0)
143 {
144 while ((size_t)num_bytes > src->bytes_in_buffer)
145 {
146 num_bytes -= (long)src->bytes_in_buffer;
147 (void) src->fill_input_buffer(cinfo);
148 }
149 src->next_input_byte += num_bytes;
150 src->bytes_in_buffer -= num_bytes;
151 }
152}
153
154static int
155next_dctd(fz_context *ctx, fz_stream *stm, size_t max)
156{
157 fz_dctd *state = stm->state;
158 j_decompress_ptr cinfo = &state->cinfo;
159 unsigned char *p = state->buffer;
160 unsigned char *ep;
161 int c;
162
163 if (max > sizeof(state->buffer))
164 max = sizeof(state->buffer);
165 ep = state->buffer + max;
166
167 fz_try(ctx)
168 {
169 if (!state->init)
170 {
171 state->init = 1;
172
173 /* Skip over any stray whitespace at the start of the stream */
174 while ((c = fz_peek_byte(ctx, state->chain)) == '\n' || c == '\r' || c == ' ')
175 (void)fz_read_byte(ctx, state->chain);
176
177 jpeg_create_decompress(cinfo);
178
179 cinfo->src = &state->srcmgr;
180 cinfo->src->init_source = init_source_dct;
181 cinfo->src->fill_input_buffer = fill_input_buffer_dct;
182 cinfo->src->skip_input_data = skip_input_data_dct;
183 cinfo->src->resync_to_restart = jpeg_resync_to_restart;
184 cinfo->src->term_source = term_source_dct;
185
186 /* optionally load additional JPEG tables first */
187 if (state->jpegtables)
188 {
189 state->curr_stm = state->jpegtables;
190 cinfo->src->next_input_byte = state->curr_stm->rp;
191 cinfo->src->bytes_in_buffer = state->curr_stm->wp - state->curr_stm->rp;
192 jpeg_read_header(cinfo, 0);
193 state->curr_stm->rp = state->curr_stm->wp - state->cinfo.src->bytes_in_buffer;
194 state->curr_stm = state->chain;
195 }
196
197 cinfo->src->next_input_byte = state->curr_stm->rp;
198 cinfo->src->bytes_in_buffer = state->curr_stm->wp - state->curr_stm->rp;
199
200 jpeg_read_header(cinfo, 1);
201
202 /* default value if ColorTransform is not set */
203 if (state->color_transform == -1)
204 {
205 if (state->cinfo.num_components == 3)
206 state->color_transform = 1;
207 else
208 state->color_transform = 0;
209 }
210
211 if (cinfo->saw_Adobe_marker)
212 state->color_transform = cinfo->Adobe_transform;
213
214 /* Guess the input colorspace, and set output colorspace accordingly */
215 switch (cinfo->num_components)
216 {
217 case 3:
218 if (state->color_transform)
219 cinfo->jpeg_color_space = JCS_YCbCr;
220 else
221 cinfo->jpeg_color_space = JCS_RGB;
222 break;
223 case 4:
224 if (state->color_transform)
225 cinfo->jpeg_color_space = JCS_YCCK;
226 else
227 cinfo->jpeg_color_space = JCS_CMYK;
228 break;
229 }
230
231 cinfo->scale_num = 8/(1<<state->l2factor);
232 cinfo->scale_denom = 8;
233
234 jpeg_start_decompress(cinfo);
235
236 state->stride = cinfo->output_width * cinfo->output_components;
237 state->scanline = fz_malloc(ctx, state->stride);
238 state->rp = state->scanline;
239 state->wp = state->scanline;
240 }
241
242 while (state->rp < state->wp && p < ep)
243 *p++ = *state->rp++;
244
245 while (p < ep)
246 {
247 if (cinfo->output_scanline == cinfo->output_height)
248 break;
249
250 if (p + state->stride <= ep)
251 {
252 jpeg_read_scanlines(cinfo, &p, 1);
253 p += state->stride;
254 }
255 else
256 {
257 jpeg_read_scanlines(cinfo, &state->scanline, 1);
258 state->rp = state->scanline;
259 state->wp = state->scanline + state->stride;
260 }
261
262 while (state->rp < state->wp && p < ep)
263 *p++ = *state->rp++;
264 }
265 stm->rp = state->buffer;
266 stm->wp = p;
267 stm->pos += (p - state->buffer);
268 }
269 fz_catch(ctx)
270 {
271 if (cinfo->src)
272 state->curr_stm->rp = state->curr_stm->wp - cinfo->src->bytes_in_buffer;
273 fz_rethrow(ctx);
274 }
275
276 if (p == stm->rp)
277 return EOF;
278
279 return *stm->rp++;
280}
281
282static void
283close_dctd(fz_context *ctx, void *state_)
284{
285 fz_dctd *state = (fz_dctd *)state_;
286
287 if (state->init)
288 {
289 /* We call jpeg_abort rather than the more usual
290 * jpeg_finish_decompress here. This has the same effect,
291 * but doesn't spew warnings if we didn't read enough data etc.
292 * Annoyingly jpeg_abort can throw
293 */
294 fz_try(ctx)
295 jpeg_abort((j_common_ptr)&state->cinfo);
296 fz_catch(ctx)
297 {
298 /* Ignore any errors here */
299 }
300
301 jpeg_destroy_decompress(&state->cinfo);
302 }
303
304 fz_dct_mem_term(&state->cinfo);
305
306 if (state->cinfo.src)
307 state->curr_stm->rp = state->curr_stm->wp - state->cinfo.src->bytes_in_buffer;
308
309 fz_free(ctx, state->scanline);
310 fz_drop_stream(ctx, state->chain);
311 fz_drop_stream(ctx, state->jpegtables);
312 fz_free(ctx, state);
313}
314
315/* Default: color_transform = -1 (unset), l2factor = 0, jpegtables = NULL */
316fz_stream *
317fz_open_dctd(fz_context *ctx, fz_stream *chain, int color_transform, int l2factor, fz_stream *jpegtables)
318{
319 fz_dctd *state = fz_malloc_struct(ctx, fz_dctd);
320 j_decompress_ptr cinfo = &state->cinfo;
321
322 state->ctx = ctx;
323
324 fz_try(ctx)
325 fz_dct_mem_init(cinfo, state);
326 fz_catch(ctx)
327 {
328 fz_free(ctx, state);
329 fz_rethrow(ctx);
330 }
331
332 state->color_transform = color_transform;
333 state->init = 0;
334 state->l2factor = l2factor;
335 state->chain = fz_keep_stream(ctx, chain);
336 state->jpegtables = fz_keep_stream(ctx, jpegtables);
337 state->curr_stm = state->chain;
338
339 cinfo->src = NULL;
340 cinfo->err = &state->errmgr;
341 jpeg_std_error(cinfo->err);
342 cinfo->err->error_exit = error_exit_dct;
343
344 return fz_new_stream(ctx, state, next_dctd, close_dctd);
345}
346