1 : /******************************************************************************
2 : * $Id: vsidataio.cpp 24269 2012-04-20 20:52:55Z rouault $
3 : *
4 : * Project: JPEG JFIF Driver
5 : * Purpose: Implement JPEG read/write io indirection through VSI.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : * Code partially derived from libjpeg jdatasrc.c and jdatadst.c.
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "vsidataio.h"
32 :
33 : CPL_CVSID("$Id: vsidataio.cpp 24269 2012-04-20 20:52:55Z rouault $");
34 :
35 : CPL_C_START
36 : #include "jerror.h"
37 : CPL_C_END
38 :
39 :
40 : /* Expanded data source object for stdio input */
41 :
42 : typedef struct {
43 : struct jpeg_source_mgr pub; /* public fields */
44 :
45 : VSILFILE * infile; /* source stream */
46 : JOCTET * buffer; /* start of buffer */
47 : boolean start_of_file; /* have we gotten any data yet? */
48 : } my_source_mgr;
49 :
50 : typedef my_source_mgr * my_src_ptr;
51 :
52 : #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
53 :
54 :
55 : /*
56 : * Initialize source --- called by jpeg_read_header
57 : * before any data is actually read.
58 : */
59 :
60 : METHODDEF(void)
61 362 : init_source (j_decompress_ptr cinfo)
62 : {
63 362 : my_src_ptr src = (my_src_ptr) cinfo->src;
64 :
65 : /* We reset the empty-input-file flag for each image,
66 : * but we don't clear the input buffer.
67 : * This is correct behavior for reading a series of images from one source.
68 : */
69 362 : src->start_of_file = TRUE;
70 362 : }
71 :
72 :
73 : /*
74 : * Fill the input buffer --- called whenever buffer is emptied.
75 : *
76 : * In typical applications, this should read fresh data into the buffer
77 : * (ignoring the current state of next_input_byte & bytes_in_buffer),
78 : * reset the pointer & count to the start of the buffer, and return TRUE
79 : * indicating that the buffer has been reloaded. It is not necessary to
80 : * fill the buffer entirely, only to obtain at least one more byte.
81 : *
82 : * There is no such thing as an EOF return. If the end of the file has been
83 : * reached, the routine has a choice of ERREXIT() or inserting fake data into
84 : * the buffer. In most cases, generating a warning message and inserting a
85 : * fake EOI marker is the best course of action --- this will allow the
86 : * decompressor to output however much of the image is there. However,
87 : * the resulting error message is misleading if the real problem is an empty
88 : * input file, so we handle that case specially.
89 : *
90 : * In applications that need to be able to suspend compression due to input
91 : * not being available yet, a FALSE return indicates that no more data can be
92 : * obtained right now, but more may be forthcoming later. In this situation,
93 : * the decompressor will return to its caller (with an indication of the
94 : * number of scanlines it has read, if any). The application should resume
95 : * decompression after it has loaded more data into the input buffer. Note
96 : * that there are substantial restrictions on the use of suspension --- see
97 : * the documentation.
98 : *
99 : * When suspending, the decompressor will back up to a convenient restart point
100 : * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
101 : * indicate where the restart point will be if the current call returns FALSE.
102 : * Data beyond this point must be rescanned after resumption, so move it to
103 : * the front of the buffer rather than discarding it.
104 : */
105 :
106 : METHODDEF(boolean)
107 1724 : fill_input_buffer (j_decompress_ptr cinfo)
108 : {
109 1724 : my_src_ptr src = (my_src_ptr) cinfo->src;
110 : size_t nbytes;
111 :
112 1724 : nbytes = VSIFReadL(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
113 :
114 1724 : if (nbytes <= 0) {
115 0 : if (src->start_of_file) /* Treat empty input file as fatal error */
116 0 : ERREXIT(cinfo, JERR_INPUT_EMPTY);
117 0 : WARNMS(cinfo, JWRN_JPEG_EOF);
118 : /* Insert a fake EOI marker */
119 0 : src->buffer[0] = (JOCTET) 0xFF;
120 0 : src->buffer[1] = (JOCTET) JPEG_EOI;
121 0 : nbytes = 2;
122 : }
123 :
124 1724 : src->pub.next_input_byte = src->buffer;
125 1724 : src->pub.bytes_in_buffer = nbytes;
126 1724 : src->start_of_file = FALSE;
127 :
128 1724 : return TRUE;
129 : }
130 :
131 : /*
132 : * The Intel IPP performance libraries do not necessarily read the
133 : * entire contents of the buffer with each pass, so each re-fill
134 : * copies the remaining buffer bytes to the front of the buffer,
135 : * then fills up the rest with new data.
136 : */
137 : #ifdef IPPJ_HUFF
138 : METHODDEF(boolean)
139 : fill_input_buffer_ipp (j_decompress_ptr cinfo)
140 : {
141 : my_src_ptr src = (my_src_ptr) cinfo->src;
142 : size_t bytes_left = src->pub.bytes_in_buffer;
143 : size_t bytes_to_read = INPUT_BUF_SIZE - bytes_left;
144 : size_t nbytes;
145 :
146 : if(src->start_of_file || cinfo->progressive_mode)
147 : {
148 : return fill_input_buffer(cinfo);
149 : }
150 :
151 : memmove(src->buffer,src->pub.next_input_byte,bytes_left);
152 :
153 : nbytes = VSIFReadL(src->buffer + bytes_left, 1, bytes_to_read, src->infile);
154 :
155 : if(nbytes <= 0)
156 : {
157 : if(src->start_of_file)
158 : {
159 : /* Treat empty input file as fatal error */
160 : ERREXIT(cinfo, JERR_INPUT_EMPTY);
161 : }
162 :
163 : if(src->pub.bytes_in_buffer == 0 && cinfo->unread_marker == 0)
164 : {
165 : WARNMS(cinfo, JWRN_JPEG_EOF);
166 :
167 : /* Insert a fake EOI marker */
168 : src->buffer[0] = (JOCTET)0xFF;
169 : src->buffer[1] = (JOCTET)JPEG_EOI;
170 : nbytes = 2;
171 : }
172 :
173 : src->pub.next_input_byte = src->buffer;
174 : src->pub.bytes_in_buffer = bytes_left + nbytes;
175 : src->start_of_file = FALSE;
176 :
177 : return TRUE;
178 : }
179 :
180 : src->pub.next_input_byte = src->buffer;
181 : src->pub.bytes_in_buffer = bytes_left + nbytes;
182 : src->start_of_file = FALSE;
183 :
184 : return TRUE;
185 : }
186 : #endif /* IPPJ_HUFF */
187 :
188 :
189 : /*
190 : * Skip data --- used to skip over a potentially large amount of
191 : * uninteresting data (such as an APPn marker).
192 : *
193 : * Writers of suspendable-input applications must note that skip_input_data
194 : * is not granted the right to give a suspension return. If the skip extends
195 : * beyond the data currently in the buffer, the buffer can be marked empty so
196 : * that the next read will cause a fill_input_buffer call that can suspend.
197 : * Arranging for additional bytes to be discarded before reloading the input
198 : * buffer is the application writer's problem.
199 : */
200 :
201 : METHODDEF(void)
202 140 : skip_input_data (j_decompress_ptr cinfo, long num_bytes)
203 : {
204 140 : my_src_ptr src = (my_src_ptr) cinfo->src;
205 :
206 : /* Just a dumb implementation for now. Could use fseek() except
207 : * it doesn't work on pipes. Not clear that being smart is worth
208 : * any trouble anyway --- large skips are infrequent.
209 : */
210 140 : if (num_bytes > 0) {
211 280 : while (num_bytes > (long) src->pub.bytes_in_buffer) {
212 0 : num_bytes -= (long) src->pub.bytes_in_buffer;
213 0 : (void) fill_input_buffer(cinfo);
214 : /* note we assume that fill_input_buffer will never return FALSE,
215 : * so suspension need not be handled.
216 : */
217 : }
218 140 : src->pub.next_input_byte += (size_t) num_bytes;
219 140 : src->pub.bytes_in_buffer -= (size_t) num_bytes;
220 : }
221 140 : }
222 :
223 :
224 : /*
225 : * An additional method that can be provided by data source modules is the
226 : * resync_to_restart method for error recovery in the presence of RST markers.
227 : * For the moment, this source module just uses the default resync method
228 : * provided by the JPEG library. That method assumes that no backtracking
229 : * is possible.
230 : */
231 :
232 :
233 : /*
234 : * Terminate source --- called by jpeg_finish_decompress
235 : * after all data has been read. Often a no-op.
236 : *
237 : * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
238 : * application must deal with any cleanup that should happen even
239 : * for error exit.
240 : */
241 :
242 : METHODDEF(void)
243 16 : term_source (j_decompress_ptr cinfo)
244 : {
245 : /* no work necessary here */
246 16 : }
247 :
248 :
249 : /*
250 : * Prepare for input from a stdio stream.
251 : * The caller must have already opened the stream, and is responsible
252 : * for closing it after finishing decompression.
253 : */
254 :
255 362 : void jpeg_vsiio_src (j_decompress_ptr cinfo, VSILFILE * infile)
256 : {
257 : my_src_ptr src;
258 :
259 : /* The source object and input buffer are made permanent so that a series
260 : * of JPEG images can be read from the same file by calling jpeg_stdio_src
261 : * only before the first one. (If we discarded the buffer at the end of
262 : * one image, we'd likely lose the start of the next one.)
263 : * This makes it unsafe to use this manager and a different source
264 : * manager serially with the same JPEG object. Caveat programmer.
265 : */
266 362 : if (cinfo->src == NULL) { /* first time for this JPEG object? */
267 : cinfo->src = (struct jpeg_source_mgr *)
268 : (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
269 362 : sizeof(my_source_mgr));
270 362 : src = (my_src_ptr) cinfo->src;
271 : src->buffer = (JOCTET *)
272 : (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
273 362 : INPUT_BUF_SIZE * sizeof(JOCTET));
274 : }
275 :
276 362 : src = (my_src_ptr) cinfo->src;
277 362 : src->pub.init_source = init_source;
278 : #ifdef IPPJ_HUFF
279 : src->pub.fill_input_buffer = fill_input_buffer_ipp;
280 : #else
281 362 : src->pub.fill_input_buffer = fill_input_buffer;
282 : #endif
283 362 : src->pub.skip_input_data = skip_input_data;
284 362 : src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
285 362 : src->pub.term_source = term_source;
286 362 : src->infile = infile;
287 362 : src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
288 362 : src->pub.next_input_byte = NULL; /* until buffer loaded */
289 362 : }
290 :
291 :
292 : /* ==================================================================== */
293 : /* The rest was derived from jdatadst.c */
294 : /* ==================================================================== */
295 :
296 : /* Expanded data destination object for stdio output */
297 :
298 : typedef struct {
299 : struct jpeg_destination_mgr pub; /* public fields */
300 :
301 : VSILFILE * outfile; /* target stream */
302 : JOCTET * buffer; /* start of buffer */
303 : } my_destination_mgr;
304 :
305 : typedef my_destination_mgr * my_dest_ptr;
306 :
307 : #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
308 :
309 :
310 : /*
311 : * Initialize destination --- called by jpeg_start_compress
312 : * before any data is actually written.
313 : */
314 :
315 : METHODDEF(void)
316 174 : init_destination (j_compress_ptr cinfo)
317 : {
318 174 : my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
319 :
320 : /* Allocate the output buffer --- it will be released when done with image */
321 : dest->buffer = (JOCTET *)
322 : (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
323 174 : OUTPUT_BUF_SIZE * sizeof(JOCTET));
324 :
325 174 : dest->pub.next_output_byte = dest->buffer;
326 174 : dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
327 174 : }
328 :
329 :
330 : /*
331 : * Empty the output buffer --- called whenever buffer fills up.
332 : *
333 : * In typical applications, this should write the entire output buffer
334 : * (ignoring the current state of next_output_byte & free_in_buffer),
335 : * reset the pointer & count to the start of the buffer, and return TRUE
336 : * indicating that the buffer has been dumped.
337 : *
338 : * In applications that need to be able to suspend compression due to output
339 : * overrun, a FALSE return indicates that the buffer cannot be emptied now.
340 : * In this situation, the compressor will return to its caller (possibly with
341 : * an indication that it has not accepted all the supplied scanlines). The
342 : * application should resume compression after it has made more room in the
343 : * output buffer. Note that there are substantial restrictions on the use of
344 : * suspension --- see the documentation.
345 : *
346 : * When suspending, the compressor will back up to a convenient restart point
347 : * (typically the start of the current MCU). next_output_byte & free_in_buffer
348 : * indicate where the restart point will be if the current call returns FALSE.
349 : * Data beyond this point will be regenerated after resumption, so do not
350 : * write it out when emptying the buffer externally.
351 : */
352 :
353 : METHODDEF(boolean)
354 72 : empty_output_buffer (j_compress_ptr cinfo)
355 : {
356 72 : my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
357 72 : size_t bytes_to_write = OUTPUT_BUF_SIZE;
358 :
359 : #ifdef IPPJ_HUFF
360 : /*
361 : * The Intel IPP performance libraries do not necessarily fill up
362 : * the whole output buffer with each compression pass, so we only
363 : * want to write out the parts of the buffer that are full.
364 : */
365 : if(! cinfo->progressive_mode) {
366 : bytes_to_write -= dest->pub.free_in_buffer;
367 : }
368 : #endif
369 :
370 72 : if (VSIFWriteL(dest->buffer, 1, bytes_to_write, dest->outfile) != bytes_to_write)
371 0 : ERREXIT(cinfo, JERR_FILE_WRITE);
372 :
373 72 : dest->pub.next_output_byte = dest->buffer;
374 72 : dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
375 :
376 72 : return TRUE;
377 : }
378 :
379 : /*
380 : * Terminate destination --- called by jpeg_finish_compress
381 : * after all data has been written. Usually needs to flush buffer.
382 : *
383 : * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
384 : * application must deal with any cleanup that should happen even
385 : * for error exit.
386 : */
387 :
388 : METHODDEF(void)
389 174 : term_destination (j_compress_ptr cinfo)
390 : {
391 174 : my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
392 174 : size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
393 :
394 : /* Write any data remaining in the buffer */
395 174 : if (datacount > 0) {
396 174 : if (VSIFWriteL(dest->buffer, 1, datacount, dest->outfile) != datacount)
397 0 : ERREXIT(cinfo, JERR_FILE_WRITE);
398 : }
399 174 : if( VSIFFlushL(dest->outfile) != 0 )
400 0 : ERREXIT(cinfo, JERR_FILE_WRITE);
401 174 : }
402 :
403 :
404 : /*
405 : * Prepare for output to a stdio stream.
406 : * The caller must have already opened the stream, and is responsible
407 : * for closing it after finishing compression.
408 : */
409 :
410 : void
411 174 : jpeg_vsiio_dest (j_compress_ptr cinfo, VSILFILE * outfile)
412 : {
413 : my_dest_ptr dest;
414 :
415 : /* The destination object is made permanent so that multiple JPEG images
416 : * can be written to the same file without re-executing jpeg_stdio_dest.
417 : * This makes it dangerous to use this manager and a different destination
418 : * manager serially with the same JPEG object, because their private object
419 : * sizes may be different. Caveat programmer.
420 : */
421 174 : if (cinfo->dest == NULL) { /* first time for this JPEG object? */
422 : cinfo->dest = (struct jpeg_destination_mgr *)
423 : (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
424 174 : sizeof(my_destination_mgr));
425 : }
426 :
427 174 : dest = (my_dest_ptr) cinfo->dest;
428 174 : dest->pub.init_destination = init_destination;
429 174 : dest->pub.empty_output_buffer = empty_output_buffer;
430 174 : dest->pub.term_destination = term_destination;
431 174 : dest->outfile = outfile;
432 174 : }
|