1 /*
2 * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <setjmp.h>
29 #include <assert.h>
30 #include <string.h>
31
32 #include "jni.h"
33
34 #include "com_sun_javafx_iio_jpeg_JPEGImageLoader.h"
35
36 /* headers from libjpeg */
37 #include <jpeglib.h>
38 #include <jerror.h>
39
40 #if defined (_LP64) || defined(_WIN64)
41 #define jlong_to_ptr(a) ((void*)(a))
42 #define ptr_to_jlong(a) ((jlong)(a))
43 #else
44 #define jlong_to_ptr(a) ((void*)(int)(a))
45 #define ptr_to_jlong(a) ((jlong)(int)(a))
46 #endif
47
48 #ifdef __APPLE__
49
50 #include <TargetConditionals.h>
51
52 /* RT-37125: use setjmp/longjmp versions that do not save/restore the signal mask */
53 #define longjmp _longjmp
54 #define setjmp _setjmp
55
56 #endif
57
58 static jboolean checkAndClearException(JNIEnv *env) {
59 if (!(*env)->ExceptionCheck(env)) {
60 return JNI_FALSE;
61 }
62 (*env)->ExceptionClear(env);
63 return JNI_TRUE;
64 }
65
66 /***************** Begin verbatim copy from jni_util.c ***************/
67
68 /**
69 * Throw a Java exception by name. Similar to SignalError.
70 */
71 JNIEXPORT void JNICALL
72 ThrowByName(JNIEnv *env, const char *name, const char *msg) {
73 jclass cls = (*env)->FindClass(env, name);
74 if (!(*env)->ExceptionCheck(env) && cls != 0) {/* Otherwise an exception has already been thrown */
75 (*env)->ThrowNew(env, cls, msg);
76 }
77 }
78
79 JNIEXPORT void * JNICALL
80 GetEnv(JavaVM *vm, jint version) {
81 void *env;
82 (*vm)->GetEnv(vm, &env, version);
83 return env;
84 }
85
86 /***************** Begin verbatim copy from jni_util.c ***************/
87
88 #undef MAX
89 #define MAX(a,b) ((a) > (b) ? (a) : (b))
90
91 /* Cached Java method IDs */
92 static jmethodID InputStream_readID;
93 static jmethodID InputStream_skipID;
94 static jmethodID JPEGImageLoader_setInputAttributesID;
95 static jmethodID JPEGImageLoader_setOutputAttributesID;
96 static jmethodID JPEGImageLoader_updateImageProgressID;
97 static jmethodID JPEGImageLoader_emitWarningID;
98
99 /* Initialize the Java VM instance variable when the library is
100 first loaded */
101 static JavaVM *jvm;
102
103 #ifdef STATIC_BUILD
104
105 JNIEXPORT jint JNICALL
106 JNI_OnLoad_javafx_iio(JavaVM *vm, void *reserved) {
107 jvm = vm;
108 #ifdef JNI_VERSION_1_8
109 //min. returned JNI_VERSION required by JDK8 for builtin libraries
110 JNIEnv *env;
111 if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
112 return JNI_VERSION_1_2;
113 }
114 return JNI_VERSION_1_8;
115 #else
116 return JNI_VERSION_1_2;
117 #endif
118 }
119
120 #else
121
122 JNIEXPORT jint JNICALL
123 JNI_OnLoad(JavaVM *vm, void *reserved) {
124 jvm = vm;
125 return JNI_VERSION_1_2;
126 }
127
128 #endif // STATIC_BUILD
129
130
131 /*
132 * The following sets of defines must match the warning messages in the
133 * Java code.
134 */
135
136 /* Loader warnings */
137 #define READ_NO_EOI 0
138
139 /* Saver warnings */
140
141 /* Return codes for various ops */
142 #define OK 1
143 #define NOT_OK 0
144
145 /*
146 * First we define two objects, one for the stream and buffer and one
147 * for pixels. Both contain references to Java objects and pointers to
148 * pinned arrays. These objects can be used for either input or
149 * output. Pixels can be accessed as either INT32s or bytes.
150 * Every I/O operation will have one of each these objects, one for
151 * the stream and the other to hold pixels, regardless of the I/O direction.
152 */
153
154 /******************** StreamBuffer definition ************************/
155
156 typedef struct streamBufferStruct {
157 jobject stream; // ImageInputStream or ImageOutputStream
158 jbyteArray hstreamBuffer; // Handle to a Java buffer for the stream
159 JOCTET *buf; // Pinned buffer pointer */
160 int bufferOffset; // holds offset between unpin and the next pin
161 int bufferLength; // Allocated, nut just used
162 int suspendable; // Set to true to suspend input
163 long remaining_skip; // Used only on input
164 } streamBuffer, *streamBufferPtr;
165
166 /*
167 * This buffer size was set to 64K in the old classes, 4K by default in the
168 * IJG library, with the comment "an efficiently freadable size", and 1K
169 * in AWT.
170 * Unlike in the other Java designs, these objects will persist, so 64K
171 * seems too big and 1K seems too small. If 4K was good enough for the
172 * IJG folks, it's good enough for me.
173 */
174 #define STREAMBUF_SIZE 4096
175
176 /*
177 * Used to signal that no data need be restored from an unpin to a pin.
178 * I.e. the buffer is empty.
179 */
180 #define NO_DATA -1
181
182 // Forward reference
183 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb);
184
185 /*
186 * Initialize a freshly allocated StreamBuffer object. The stream is left
187 * null, as it will be set from Java by setSource, but the buffer object
188 * is created and a global reference kept. Returns OK on success, NOT_OK
189 * if allocating the buffer or getting a global reference for it failed.
190 */
191 static int initStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
192 /* Initialize a new buffer */
193 jbyteArray hInputBuffer = (*env)->NewByteArray(env, STREAMBUF_SIZE);
194 if (hInputBuffer == NULL) {
195 return NOT_OK;
196 }
197 sb->bufferLength = (*env)->GetArrayLength(env, hInputBuffer);
198 sb->hstreamBuffer = (*env)->NewGlobalRef(env, hInputBuffer);
199 if (sb->hstreamBuffer == NULL) {
200 return NOT_OK;
201 }
202
203
204 sb->stream = NULL;
205
206 sb->buf = NULL;
207
208 resetStreamBuffer(env, sb);
209
210 return OK;
211 }
212
213 /*
214 * Free all resources associated with this streamBuffer. This must
215 * be called to dispose the object to avoid leaking global references, as
216 * resetStreamBuffer does not release the buffer reference.
217 */
218 static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
219 resetStreamBuffer(env, sb);
220 if (sb->hstreamBuffer != NULL) {
221 (*env)->DeleteGlobalRef(env, sb->hstreamBuffer);
222 }
223 }
224
225 // Forward reference
226 static void unpinStreamBuffer(JNIEnv *env,
227 streamBufferPtr sb,
228 const JOCTET *next_byte);
229
230 /*
231 * Resets the state of a streamBuffer object that has been in use.
232 * The global reference to the stream is released, but the reference
233 * to the buffer is retained. The buffer is unpinned if it was pinned.
234 * All other state is reset.
235 */
236 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
237 if (sb->stream != NULL) {
238 (*env)->DeleteGlobalRef(env, sb->stream);
239 sb->stream = NULL;
240 }
241 unpinStreamBuffer(env, sb, NULL);
242 sb->bufferOffset = NO_DATA;
243 sb->suspendable = FALSE;
244 sb->remaining_skip = 0;
245 }
246
247 /*
248 * Pins the data buffer associated with this stream. Returns OK on
249 * success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail.
250 */
251 static int pinStreamBuffer(JNIEnv *env,
252 streamBufferPtr sb,
253 const JOCTET **next_byte) {
254 if (sb->hstreamBuffer != NULL) {
255 assert(sb->buf == NULL);
256 sb->buf =
257 (JOCTET *) (*env)->GetPrimitiveArrayCritical(env,
258 sb->hstreamBuffer,
259 NULL);
260 if (sb->buf == NULL) {
261 return NOT_OK;
262 }
263 if (sb->bufferOffset != NO_DATA) {
264 *next_byte = sb->buf + sb->bufferOffset;
265 }
266 }
267 return OK;
268 }
269
270 /*
271 * Unpins the data buffer associated with this stream.
272 */
273 static void unpinStreamBuffer(JNIEnv *env,
274 streamBufferPtr sb,
275 const JOCTET *next_byte) {
276 if (sb->buf != NULL) {
277 assert(sb->hstreamBuffer != NULL);
278 if (next_byte == NULL) {
279 sb->bufferOffset = NO_DATA;
280 } else {
281 sb->bufferOffset = next_byte - sb->buf;
282 }
283 (*env)->ReleasePrimitiveArrayCritical(env,
284 sb->hstreamBuffer,
285 sb->buf,
286 0);
287 sb->buf = NULL;
288 }
289 }
290
291 /*
292 * Clear out the streamBuffer. This just invalidates the data in the buffer.
293 */
294 static void clearStreamBuffer(streamBufferPtr sb) {
295 sb->bufferOffset = NO_DATA;
296 }
297
298 /*************************** end StreamBuffer definition *************/
299
300 /*************************** Pixel Buffer definition ******************/
301
302 typedef struct pixelBufferStruct {
303 jobject hpixelObject; // Usually a DataBuffer bank as a byte array
304
305 union pixptr {
306 INT32 *ip; // Pinned buffer pointer, as 32-bit ints
307 unsigned char *bp; // Pinned buffer pointer, as bytes
308 } buf;
309 } pixelBuffer, *pixelBufferPtr;
310
311 /*
312 * Initialize a freshly allocated PixelBuffer. All fields are simply
313 * set to NULL, as we have no idea what size buffer we will need.
314 */
315 static void initPixelBuffer(pixelBufferPtr pb) {
316 pb->hpixelObject = NULL;
317 pb->buf.ip = NULL;
318 }
319
320 /*
321 * Set the pixelBuffer to use the given buffer, acquiring a new global
322 * reference for it. Returns OK on success, NOT_OK on failure.
323 */
324 static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) {
325 pb->hpixelObject = (*env)->NewGlobalRef(env, obj);
326
327 if (pb->hpixelObject == NULL) {
328 ThrowByName(env,
329 "java/lang/OutOfMemoryError",
330 "Setting Pixel Buffer");
331 return NOT_OK;
332 }
333 return OK;
334 }
335
336 // Forward reference
337 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb);
338
339 /*
340 * Resets a pixel buffer to its initial state. Unpins any pixel buffer,
341 * releases the global reference, and resets fields to NULL. Use this
342 * method to dispose the object as well (there is no destroyPixelBuffer).
343 */
344 static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
345 if (pb->hpixelObject != NULL) {
346 unpinPixelBuffer(env, pb);
347 (*env)->DeleteGlobalRef(env, pb->hpixelObject);
348 pb->hpixelObject = NULL;
349 }
350 }
351
352 /*
353 * Pins the data buffer. Returns OK on success, NOT_OK on failure.
354 */
355 static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
356 if (pb->hpixelObject != NULL) {
357 assert(pb->buf.ip == NULL);
358 pb->buf.bp = (unsigned char *) (*env)->GetPrimitiveArrayCritical
359 (env, pb->hpixelObject, NULL);
360 if (pb->buf.bp == NULL) {
361 return NOT_OK;
362 }
363 }
364 return OK;
365 }
366
367 /*
368 * Unpins the data buffer.
369 */
370 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
371
372 if (pb->buf.ip != NULL) {
373 assert(pb->hpixelObject != NULL);
374 (*env)->ReleasePrimitiveArrayCritical(env,
375 pb->hpixelObject,
376 pb->buf.ip,
377 0);
378 pb->buf.ip = NULL;
379 }
380 }
381
382 /********************* end PixelBuffer definition *******************/
383
384 /********************* ImageIOData definition ***********************/
385
386 #define MAX_BANDS 4
387 #define JPEG_BAND_SIZE 8
388 #define NUM_BAND_VALUES (1<<JPEG_BAND_SIZE)
389 #define MAX_JPEG_BAND_VALUE (NUM_BAND_VALUES-1)
390 #define HALF_MAX_JPEG_BAND_VALUE (MAX_JPEG_BAND_VALUE>>1)
391
392 /* The number of possible incoming values to be scaled. */
393 #define NUM_INPUT_VALUES (1 << 16)
394
395 /*
396 * The principal imageioData object, opaque to I/O direction.
397 * Each JPEGImageReader will have associated with it a
398 * jpeg_decompress_struct, and similarly each JPEGImageWriter will
399 * have associated with it a jpeg_compress_struct. In order to
400 * ensure that these associations persist from one native call to
401 * the next, and to provide a central locus of imageio-specific
402 * data, we define an imageioData struct containing references
403 * to the Java object and the IJG structs. The functions
404 * that manipulate these objects know whether input or output is being
405 * performed and therefore know how to manipulate the contents correctly.
406 * If for some reason they don't, the direction can be determined by
407 * checking the is_decompressor field of the jpegObj.
408 * In order for lower level code to determine a
409 * Java object given an IJG struct, such as for dispatching warnings,
410 * we use the client_data field of the jpeg object to store a pointer
411 * to the imageIOData object. Maintenance of this pointer is performed
412 * exclusively within the following access functions. If you
413 * change that, you run the risk of dangling pointers.
414 */
415 typedef struct imageIODataStruct {
416 j_common_ptr jpegObj; // Either struct is fine
417 jobject imageIOobj; // A JPEGImageLoader
418
419 streamBuffer streamBuf; // Buffer for the stream
420 pixelBuffer pixelBuf; // Buffer for pixels
421
422 jboolean abortFlag; // Passed down from Java abort method
423 } imageIOData, *imageIODataPtr;
424
425 /*
426 * Allocate and initialize a new imageIOData object to associate the
427 * jpeg object and the Java object. Returns a pointer to the new object
428 * on success, NULL on failure.
429 */
430 static imageIODataPtr initImageioData(JNIEnv *env,
431 j_common_ptr cinfo,
432 jobject obj) {
433 imageIODataPtr data = (imageIODataPtr) malloc(sizeof (imageIOData));
434 if (data == NULL) {
435 return NULL;
436 }
437
438 data->jpegObj = cinfo;
439 cinfo->client_data = data;
440
441 #ifdef DEBUG_IIO_JPEG
442 printf("new structures: data is %p, cinfo is %p\n", data, cinfo);
443 #endif
444
445 data->imageIOobj = (*env)->NewWeakGlobalRef(env, obj);
446 if (data->imageIOobj == NULL) {
447 free(data);
448 return NULL;
449 }
450 if (initStreamBuffer(env, &data->streamBuf) == NOT_OK) {
451 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj);
452 free(data);
453 return NULL;
454 }
455 initPixelBuffer(&data->pixelBuf);
456
457 data->abortFlag = JNI_FALSE;
458
459 return data;
460 }
461
462 /*
463 * Resets the imageIOData object to its initial state, as though
464 * it had just been allocated and initialized.
465 */
466 static void resetImageIOData(JNIEnv *env, imageIODataPtr data) {
467 resetStreamBuffer(env, &data->streamBuf);
468 resetPixelBuffer(env, &data->pixelBuf);
469 data->abortFlag = JNI_FALSE;
470 }
471
472 /*
473 * Releases all resources held by this object and its subobjects,
474 * frees the object, and returns the jpeg object. This method must
475 * be called to avoid leaking global references.
476 * Note that the jpeg object is not freed or destroyed, as that is
477 * the client's responsibility, although the client_data field is
478 * cleared.
479 */
480 static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) {
481 j_common_ptr ret = data->jpegObj;
482 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj);
483 destroyStreamBuffer(env, &data->streamBuf);
484 resetPixelBuffer(env, &data->pixelBuf);
485 ret->client_data = NULL;
486 free(data);
487 return ret;
488 }
489
490 /******************** end ImageIOData definition ***********************/
491
492 /******************** Java array pinning and unpinning *****************/
493
494 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid
495 * the need to copy array elements for the above two objects.
496 *
497 * MAKE SURE TO:
498 *
499 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around
500 * callbacks to Java.
501 * - call RELEASE_ARRAYS before returning to Java.
502 *
503 * Otherwise things will go horribly wrong. There may be memory leaks,
504 * excessive pinning, or even VM crashes!
505 *
506 * Note that GetPrimitiveArrayCritical may fail!
507 */
508
509 /*
510 * Release (unpin) all the arrays in use during a read.
511 */
512 static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte) {
513 unpinStreamBuffer(env, &data->streamBuf, next_byte);
514
515 unpinPixelBuffer(env, &data->pixelBuf);
516
517 }
518
519 /*
520 * Get (pin) all the arrays in use during a read.
521 */
522 static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) {
523 if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) {
524 return NOT_OK;
525 }
526
527 if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) {
528 RELEASE_ARRAYS(env, data, *next_byte);
529 return NOT_OK;
530 }
531 return OK;
532 }
533
534 /****** end of Java array pinning and unpinning ***********/
535
536 /****** Error Handling *******/
537
538 /*
539 * Set up error handling to use setjmp/longjmp. This is the third such
540 * setup, as both the AWT jpeg decoder and the com.sun... JPEG classes
541 * setup thier own. Ultimately these should be integrated, as they all
542 * do pretty much the same thing.
543 */
544
545 struct sun_jpeg_error_mgr {
546 struct jpeg_error_mgr pub; /* "public" fields */
547
548 jmp_buf setjmp_buffer; /* for return to caller */
549 };
550
551 typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr;
552
553 /*
554 * Here's the routine that will replace the standard error_exit method:
555 */
556
557 METHODDEF(void)
558 sun_jpeg_error_exit(j_common_ptr cinfo) {
559 /* cinfo->err really points to a sun_jpeg_error_mgr struct */
560 sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err;
561
562 /* For Java, we will format the message and put it in the error we throw. */
563
564 /* Return control to the setjmp point */
565 longjmp(myerr->setjmp_buffer, 1);
566 }
567
568 /*
569 * Error Message handling
570 *
571 * This overrides the output_message method to send JPEG messages
572 *
573 */
574
575 METHODDEF(void)
576 sun_jpeg_output_message(j_common_ptr cinfo) {
577 char buffer[JMSG_LENGTH_MAX];
578 jstring string;
579 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
580 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
581 jobject theObject;
582 j_decompress_ptr dinfo;
583
584 /* Create the message */
585 (*cinfo->err->format_message) (cinfo, buffer);
586
587 if (cinfo->is_decompressor) {
588 dinfo = (j_decompress_ptr)cinfo;
589 RELEASE_ARRAYS(env, data, dinfo->src->next_input_byte);
590 }
591 // Create a new java string from the message
592 string = (*env)->NewStringUTF(env, buffer);
593
594 theObject = data->imageIOobj;
595
596 if (cinfo->is_decompressor) {
597 (*env)->CallVoidMethod(env, theObject,
598 JPEGImageLoader_emitWarningID,
599 string);
600 checkAndClearException(env);
601 if (!GET_ARRAYS(env, data, &(dinfo->src->next_input_byte))) {
602 cinfo->err->error_exit(cinfo);
603 }
604 }
605 }
606
607 /* End of verbatim copy from jpegdecoder.c */
608
609 /*************** end of error handling *********************/
610
611 /*************** Shared utility code ***********************/
612
613 static void imageio_set_stream(JNIEnv *env,
614 j_common_ptr cinfo,
615 imageIODataPtr data,
616 jobject stream) {
617 streamBufferPtr sb;
618 sun_jpeg_error_ptr jerr;
619
620 sb = &data->streamBuf;
621
622 resetStreamBuffer(env, sb); // Removes any old stream
623
624 /* Now we need a new global reference for the stream */
625 if (stream != NULL) { // Fix for 4411955
626 sb->stream = (*env)->NewGlobalRef(env, stream);
627 if (sb->stream == NULL) {
628 ThrowByName(env,
629 "java/lang/OutOfMemoryError",
630 "Setting Stream");
631 return;
632 }
633 }
634
635 /* And finally reset state */
636 data->abortFlag = JNI_FALSE;
637
638 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
639 jerr = (sun_jpeg_error_ptr) cinfo->err;
640
641 if (setjmp(jerr->setjmp_buffer)) {
642 /* If we get here, the JPEG code has signaled an error
643 while aborting. */
644 if (!(*env)->ExceptionOccurred(env)) {
645 char buffer[JMSG_LENGTH_MAX];
646 (*cinfo->err->format_message) (cinfo,
647 buffer);
648 ThrowByName(env, "java/io/IOException", buffer);
649 }
650 return;
651 }
652
653 jpeg_abort(cinfo); // Frees any markers, but not tables
654
655 }
656
657 static void imageio_dispose(j_common_ptr info) {
658
659 if (info != NULL) {
660 free(info->err);
661 info->err = NULL;
662 if (info->is_decompressor) {
663 j_decompress_ptr dinfo = (j_decompress_ptr) info;
664 free(dinfo->src);
665 dinfo->src = NULL;
666 } else {
667 j_compress_ptr cinfo = (j_compress_ptr) info;
668 free(cinfo->dest);
669 cinfo->dest = NULL;
670 }
671 jpeg_destroy(info);
672 free(info);
673 }
674 }
675
676 static void imageio_abort(JNIEnv *env, jobject this,
677 imageIODataPtr data) {
678 data->abortFlag = JNI_TRUE;
679 }
680
681 static void disposeIIO(JNIEnv *env, imageIODataPtr data) {
682 j_common_ptr info = destroyImageioData(env, data);
683 imageio_dispose(info);
684 }
685
686 /*************** end of shared utility code ****************/
687
688 /********************** Loader Support **************************/
689
690 /********************** Source Management ***********************/
691
692 /*
693 * INPUT HANDLING:
694 *
695 * The JPEG library's input management is defined by the jpeg_source_mgr
696 * structure which contains two fields to convey the information in the
697 * buffer and 5 methods which perform all buffer management. The library
698 * defines a standard input manager that uses stdio for obtaining compressed
699 * jpeg data, but here we need to use Java to get our data.
700 *
701 * We use the library jpeg_source_mgr but our own routines that access
702 * imageio-specific information in the imageIOData structure.
703 */
704
705 /*
706 * Initialize source. This is called by jpeg_read_header() before any
707 * data is actually read. Unlike init_destination(), it may leave
708 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
709 * will occur immediately).
710 */
711
712 GLOBAL(void)
713 imageio_init_source(j_decompress_ptr cinfo) {
714 struct jpeg_source_mgr *src = cinfo->src;
715 src->next_input_byte = NULL;
716 src->bytes_in_buffer = 0;
717 }
718
719 /*
720 * This is called whenever bytes_in_buffer has reached zero and more
721 * data is wanted. In typical applications, it should read fresh data
722 * into the buffer (ignoring the current state of next_input_byte and
723 * bytes_in_buffer), reset the pointer & count to the start of the
724 * buffer, and return TRUE indicating that the buffer has been reloaded.
725 * It is not necessary to fill the buffer entirely, only to obtain at
726 * least one more byte. bytes_in_buffer MUST be set to a positive value
727 * if TRUE is returned. A FALSE return should only be used when I/O
728 * suspension is desired (this mode is discussed in the next section).
729 */
730
731 /*
732 * Note that with I/O suspension turned on, this procedure should not
733 * do any work since the JPEG library has a very simple backtracking
734 * mechanism which relies on the fact that the buffer will be filled
735 * only when it has backed out to the top application level. When
736 * suspendable is turned on, imageio_fill_suspended_buffer will
737 * do the actual work of filling the buffer.
738 */
739
740 GLOBAL(boolean)
741 imageio_fill_input_buffer(j_decompress_ptr cinfo) {
742 struct jpeg_source_mgr *src = cinfo->src;
743 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
744 streamBufferPtr sb = &data->streamBuf;
745 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
746 int ret;
747
748 /* This is where input suspends */
749 if (sb->suspendable) {
750 return FALSE;
751 }
752
753 #ifdef DEBUG_IIO_JPEG
754 printf("Filling input buffer, remaining skip is %ld, ",
755 sb->remaining_skip);
756 printf("Buffer length is %d\n", sb->bufferLength);
757 #endif
758
759 /*
760 * Definitively skips. Could be left over if we tried to skip
761 * more than a buffer's worth but suspended when getting the next
762 * buffer. Now we aren't suspended, so we can catch up.
763 */
764 if (sb->remaining_skip) {
765 src->skip_input_data(cinfo, 0);
766 }
767
768 /*
769 * Now fill a complete buffer, or as much of one as the stream
770 * will give us if we are near the end.
771 */
772 RELEASE_ARRAYS(env, data, src->next_input_byte);
773 ret = (*env)->CallIntMethod(env,
774 sb->stream,
775 InputStream_readID,
776 sb->hstreamBuffer, 0,
777 sb->bufferLength);
778 if (ret > sb->bufferLength) ret = sb->bufferLength;
779 if ((*env)->ExceptionOccurred(env)
780 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
781 cinfo->err->error_exit((j_common_ptr) cinfo);
782 }
783
784 #ifdef DEBUG_IIO_JPEG
785 printf("Buffer filled. ret = %d\n", ret);
786 #endif
787 /*
788 * If we have reached the end of the stream, then the EOI marker
789 * is missing. We accept such streams but generate a warning.
790 * The image is likely to be corrupted, though everything through
791 * the end of the last complete MCU should be usable.
792 */
793 if (ret <= 0) {
794 jobject reader = data->imageIOobj;
795 #ifdef DEBUG_IIO_JPEG
796 printf("YO! Early EOI! ret = %d\n", ret);
797 #endif
798 RELEASE_ARRAYS(env, data, src->next_input_byte);
799 (*env)->CallVoidMethod(env, reader,
800 JPEGImageLoader_emitWarningID,
801 READ_NO_EOI);
802 if ((*env)->ExceptionOccurred(env)
803 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
804 cinfo->err->error_exit((j_common_ptr) cinfo);
805 }
806
807 sb->buf[0] = (JOCTET) 0xFF;
808 sb->buf[1] = (JOCTET) JPEG_EOI;
809 ret = 2;
810 }
811
812 src->next_input_byte = sb->buf;
813 src->bytes_in_buffer = ret;
814
815 return TRUE;
816 }
817
818 /*
819 * With I/O suspension turned on, the JPEG library requires that all
820 * buffer filling be done at the top application level, using this
821 * function. Due to the way that backtracking works, this procedure
822 * saves all of the data that was left in the buffer when suspension
823 * occured and read new data only at the end.
824 */
825
826 GLOBAL(void)
827 imageio_fill_suspended_buffer(j_decompress_ptr cinfo) {
828 struct jpeg_source_mgr *src = cinfo->src;
829 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
830 streamBufferPtr sb = &data->streamBuf;
831 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
832 jint ret;
833 int offset, buflen;
834
835 /*
836 * The original (jpegdecoder.c) had code here that called
837 * InputStream.available and just returned if the number of bytes
838 * available was less than any remaining skip. Presumably this was
839 * to avoid blocking, although the benefit was unclear, as no more
840 * decompression can take place until more data is available, so
841 * the code would block on input a little further along anyway.
842 * ImageInputStreams don't have an available method, so we'll just
843 * block in the skip if we have to.
844 */
845
846 if (sb->remaining_skip) {
847 src->skip_input_data(cinfo, 0);
848 }
849
850 /* Save the data currently in the buffer */
851 offset = src->bytes_in_buffer;
852 if (src->next_input_byte > sb->buf) {
853 memcpy(sb->buf, src->next_input_byte, offset);
854 }
855 RELEASE_ARRAYS(env, data, src->next_input_byte);
856 buflen = sb->bufferLength - offset;
857 if (buflen <= 0) {
858 if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
859 cinfo->err->error_exit((j_common_ptr) cinfo);
860 }
861 return;
862 }
863
864 ret = (*env)->CallIntMethod(env, sb->stream,
865 InputStream_readID,
866 sb->hstreamBuffer,
867 offset, buflen);
868 if (ret > buflen) ret = buflen;
869 if ((*env)->ExceptionOccurred(env)
870 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
871 cinfo->err->error_exit((j_common_ptr) cinfo);
872 }
873 /*
874 * If we have reached the end of the stream, then the EOI marker
875 * is missing. We accept such streams but generate a warning.
876 * The image is likely to be corrupted, though everything through
877 * the end of the last complete MCU should be usable.
878 */
879 if (ret <= 0) {
880 jobject reader = data->imageIOobj;
881 RELEASE_ARRAYS(env, data, src->next_input_byte);
882 (*env)->CallVoidMethod(env, reader,
883 JPEGImageLoader_emitWarningID,
884 READ_NO_EOI);
885 if ((*env)->ExceptionOccurred(env)
886 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
887 cinfo->err->error_exit((j_common_ptr) cinfo);
888 }
889
890 sb->buf[offset] = (JOCTET) 0xFF;
891 sb->buf[offset + 1] = (JOCTET) JPEG_EOI;
892 ret = 2;
893 }
894
895 src->next_input_byte = sb->buf;
896 src->bytes_in_buffer = ret + offset;
897
898 return;
899 }
900
901 /*
902 * Skip num_bytes worth of data. The buffer pointer and count are
903 * advanced over num_bytes input bytes, using the input stream
904 * skipBytes method if the skip is greater than the number of bytes
905 * in the buffer. This is used to skip over a potentially large amount of
906 * uninteresting data (such as an APPn marker). bytes_in_buffer will be
907 * zero on return if the skip is larger than the current contents of the
908 * buffer.
909 *
910 * A negative skip count is treated as a no-op. A zero skip count
911 * skips any remaining skip from a previous skip while suspended.
912 *
913 * Note that with I/O suspension turned on, this procedure does not
914 * call skipBytes since the JPEG library has a very simple backtracking
915 * mechanism which relies on the fact that the application level has
916 * exclusive control over actual I/O.
917 */
918
919 GLOBAL(void)
920 imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
921 struct jpeg_source_mgr *src = cinfo->src;
922 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
923 streamBufferPtr sb = &data->streamBuf;
924 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
925 jlong ret;
926 jobject reader;
927
928 if (num_bytes < 0) {
929 return;
930 }
931 num_bytes += sb->remaining_skip;
932 sb->remaining_skip = 0;
933
934 /* First the easy case where we are skipping <= the current contents. */
935 ret = src->bytes_in_buffer;
936 if (ret >= num_bytes) {
937 src->next_input_byte += num_bytes;
938 src->bytes_in_buffer -= num_bytes;
939 return;
940 }
941
942 /*
943 * We are skipping more than is in the buffer. We empty the buffer and,
944 * if we aren't suspended, call the Java skipBytes method. We always
945 * leave the buffer empty, to be filled by either fill method above.
946 */
947 src->bytes_in_buffer = 0;
948 src->next_input_byte = sb->buf;
949
950 num_bytes -= (long) ret;
951 if (sb->suspendable) {
952 sb->remaining_skip = num_bytes;
953 return;
954 }
955
956 RELEASE_ARRAYS(env, data, src->next_input_byte);
957 ret = (*env)->CallLongMethod(env,
958 sb->stream,
959 InputStream_skipID,
960 (jlong) num_bytes);
961 if ((*env)->ExceptionOccurred(env)
962 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
963 cinfo->err->error_exit((j_common_ptr) cinfo);
964 }
965
966 /*
967 * If we have reached the end of the stream, then the EOI marker
968 * is missing. We accept such streams but generate a warning.
969 * The image is likely to be corrupted, though everything through
970 * the end of the last complete MCU should be usable.
971 */
972 if (ret <= 0) {
973 reader = data->imageIOobj;
974 RELEASE_ARRAYS(env, data, src->next_input_byte);
975 (*env)->CallVoidMethod(env,
976 reader,
977 JPEGImageLoader_emitWarningID,
978 READ_NO_EOI);
979
980 if ((*env)->ExceptionOccurred(env)
981 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
982 cinfo->err->error_exit((j_common_ptr) cinfo);
983 }
984 sb->buf[0] = (JOCTET) 0xFF;
985 sb->buf[1] = (JOCTET) JPEG_EOI;
986 src->bytes_in_buffer = 2;
987 src->next_input_byte = sb->buf;
988 }
989 }
990
991 /*
992 * Terminate source --- called by jpeg_finish_decompress() after all
993 * data for an image has been read. In our case pushes back any
994 * remaining data, as it will be for another image and must be available
995 * for java to find out that there is another image. Also called if
996 * reseting state after reading a tables-only image.
997 */
998
999 GLOBAL(void)
1000 imageio_term_source(j_decompress_ptr cinfo) {
1001 // To pushback, just seek back by src->bytes_in_buffer
1002 struct jpeg_source_mgr *src = cinfo->src;
1003 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
1004 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
1005 jobject reader = data->imageIOobj;
1006 if (src->bytes_in_buffer > 0) {
1007 RELEASE_ARRAYS(env, data, src->next_input_byte);
1008
1009 if ((*env)->ExceptionOccurred(env)
1010 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1011 cinfo->err->error_exit((j_common_ptr) cinfo);
1012 }
1013 src->bytes_in_buffer = 0;
1014 //src->next_input_byte = sb->buf;
1015 }
1016 }
1017
1018 /********************* end of source manager ******************/
1019
1020 /********************* ICC profile support ********************/
1021 /*
1022 * The following routines are modified versions of the ICC
1023 * profile support routines available from the IJG website.
1024 * The originals were written by Todd Newman
1025 * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for
1026 * the IJG. They are further modified to fit in the context
1027 * of the imageio JPEG plug-in.
1028 */
1029
1030 /*
1031 * Since an ICC profile can be larger than the maximum size of a JPEG marker
1032 * (64K), we need provisions to split it into multiple markers. The format
1033 * defined by the ICC specifies one or more APP2 markers containing the
1034 * following data:
1035 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
1036 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
1037 * Number of markers Total number of APP2's used (1 byte)
1038 * Profile data (remainder of APP2 data)
1039 * Decoders should use the marker sequence numbers to reassemble the profile,
1040 * rather than assuming that the APP2 markers appear in the correct sequence.
1041 */
1042
1043 #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
1044 #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
1045 #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
1046 #define MAX_DATA_BYTES_IN_ICC_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
1047
1048 /*
1049 * Handy subroutine to test whether a saved marker is an ICC profile marker.
1050 */
1051
1052 static boolean
1053 marker_is_icc(jpeg_saved_marker_ptr marker) {
1054 return
1055 marker->marker == ICC_MARKER &&
1056 marker->data_length >= ICC_OVERHEAD_LEN &&
1057 /* verify the identifying string */
1058 GETJOCTET(marker->data[0]) == 0x49 &&
1059 GETJOCTET(marker->data[1]) == 0x43 &&
1060 GETJOCTET(marker->data[2]) == 0x43 &&
1061 GETJOCTET(marker->data[3]) == 0x5F &&
1062 GETJOCTET(marker->data[4]) == 0x50 &&
1063 GETJOCTET(marker->data[5]) == 0x52 &&
1064 GETJOCTET(marker->data[6]) == 0x4F &&
1065 GETJOCTET(marker->data[7]) == 0x46 &&
1066 GETJOCTET(marker->data[8]) == 0x49 &&
1067 GETJOCTET(marker->data[9]) == 0x4C &&
1068 GETJOCTET(marker->data[10]) == 0x45 &&
1069 GETJOCTET(marker->data[11]) == 0x0;
1070 }
1071
1072 /*
1073 * See if there was an ICC profile in the JPEG file being read;
1074 * if so, reassemble and return the profile data as a new Java byte array.
1075 * If there was no ICC profile, return NULL.
1076 *
1077 * If the file contains invalid ICC APP2 markers, we throw an IIOException
1078 * with an appropriate message.
1079 */
1080
1081 jbyteArray
1082 read_icc_profile(JNIEnv *env, j_decompress_ptr cinfo) {
1083 jpeg_saved_marker_ptr marker;
1084 int num_markers = 0;
1085 int num_found_markers = 0;
1086 int seq_no;
1087 JOCTET *icc_data;
1088 JOCTET *dst_ptr;
1089 unsigned int total_length;
1090 #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes
1091 jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1];
1092 int first; // index of the first marker in the icc_markers array
1093 int last; // index of the last marker in the icc_markers array
1094 jbyteArray data = NULL;
1095
1096 /* This first pass over the saved markers discovers whether there are
1097 * any ICC markers and verifies the consistency of the marker numbering.
1098 */
1099
1100 for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++)
1101 icc_markers[seq_no] = NULL;
1102
1103
1104 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
1105 if (marker_is_icc(marker)) {
1106 if (num_markers == 0)
1107 num_markers = GETJOCTET(marker->data[13]);
1108 else if (num_markers != GETJOCTET(marker->data[13])) {
1109 ThrowByName(env, "java/io/IOException",
1110 "Invalid icc profile: inconsistent num_markers fields");
1111 return NULL;
1112 }
1113 seq_no = GETJOCTET(marker->data[12]);
1114
1115 /* Some third-party tools produce images with profile chunk
1116 * numeration started from zero. It is inconsistent with ICC
1117 * spec, but seems to be recognized by majority of image
1118 * processing tools, so we should be more tolerant to this
1119 * departure from the spec.
1120 */
1121 if (seq_no < 0 || seq_no > num_markers) {
1122 ThrowByName(env, "java/io/IOException",
1123 "Invalid icc profile: bad sequence number");
1124 return NULL;
1125 }
1126 if (icc_markers[seq_no] != NULL) {
1127 ThrowByName(env, "java/io/IOException",
1128 "Invalid icc profile: duplicate sequence numbers");
1129 return NULL;
1130 }
1131 icc_markers[seq_no] = marker;
1132 num_found_markers++;
1133 }
1134 }
1135
1136 if (num_markers == 0)
1137 return NULL; // There is no profile
1138
1139 if (num_markers != num_found_markers) {
1140 ThrowByName(env, "java/io/IOException",
1141 "Invalid icc profile: invalid number of icc markers");
1142 return NULL;
1143 }
1144
1145 first = icc_markers[0] ? 0 : 1;
1146 last = num_found_markers + first;
1147
1148 /* Check for missing markers, count total space needed.
1149 */
1150 total_length = 0;
1151 for (seq_no = first; seq_no < last; seq_no++) {
1152 unsigned int length;
1153 if (icc_markers[seq_no] == NULL) {
1154 ThrowByName(env, "java/io/IOException",
1155 "Invalid icc profile: missing sequence number");
1156 return NULL;
1157 }
1158 /* check the data length correctness */
1159 length = icc_markers[seq_no]->data_length;
1160 if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) {
1161 ThrowByName(env, "java/io/IOException",
1162 "Invalid icc profile: invalid data length");
1163 return NULL;
1164 }
1165 total_length += (length - ICC_OVERHEAD_LEN);
1166 }
1167
1168 if (total_length <= 0) {
1169 ThrowByName(env, "java/io/IOException",
1170 "Invalid icc profile: found only empty markers");
1171 return NULL;
1172 }
1173
1174 /* Allocate a Java byte array for assembled data */
1175
1176 data = (*env)->NewByteArray(env, total_length);
1177 if (data == NULL) {
1178 ThrowByName(env,
1179 "java/lang/OutOfMemoryError",
1180 "Reading ICC profile");
1181 return NULL;
1182 }
1183
1184 icc_data = (JOCTET *) (*env)->GetPrimitiveArrayCritical(env,
1185 data,
1186 NULL);
1187 if (icc_data == NULL) {
1188 ThrowByName(env, "java/io/IOException",
1189 "Unable to pin icc profile data array");
1190 return NULL;
1191 }
1192
1193 /* and fill it in */
1194 dst_ptr = icc_data;
1195 for (seq_no = first; seq_no < last; seq_no++) {
1196 JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN;
1197 unsigned int length =
1198 icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN;
1199
1200 memcpy(dst_ptr, src_ptr, length);
1201 dst_ptr += length;
1202 }
1203
1204 /* finally, unpin the array */
1205 (*env)->ReleasePrimitiveArrayCritical(env,
1206 data,
1207 icc_data,
1208 0);
1209
1210
1211 return data;
1212 }
1213
1214 /********************* end of ICC profile support *************/
1215
1216 /********************* Loader JNI calls ***********************/
1217
1218 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initJPEGMethodIDs
1219 (JNIEnv *env, jclass cls, jclass InputStreamClass) {
1220 // InputStream methods.
1221 InputStream_readID = (*env)->GetMethodID(env,
1222 InputStreamClass,
1223 "read",
1224 "([BII)I");
1225 if ((*env)->ExceptionCheck(env)) {
1226 return;
1227 }
1228
1229 InputStream_skipID = (*env)->GetMethodID(env,
1230 InputStreamClass,
1231 "skip",
1232 "(J)J");
1233 if ((*env)->ExceptionCheck(env)) {
1234 return;
1235 }
1236
1237 // JPEGImageLoader IDs.
1238 JPEGImageLoader_setInputAttributesID = (*env)->GetMethodID(env,
1239 cls,
1240 "setInputAttributes",
1241 "(IIIII[B)V");
1242 if ((*env)->ExceptionCheck(env)) {
1243 return;
1244 }
1245
1246 JPEGImageLoader_setOutputAttributesID = (*env)->GetMethodID(env,
1247 cls,
1248 "setOutputAttributes",
1249 "(II)V");
1250 if ((*env)->ExceptionCheck(env)) {
1251 return;
1252 }
1253
1254 JPEGImageLoader_updateImageProgressID = (*env)->GetMethodID(env,
1255 cls,
1256 "updateImageProgress",
1257 "(I)V");
1258 if ((*env)->ExceptionCheck(env)) {
1259 return;
1260 }
1261
1262 JPEGImageLoader_emitWarningID = (*env)->GetMethodID(env,
1263 cls,
1264 "emitWarning",
1265 "(Ljava/lang/String;)V");
1266 if ((*env)->ExceptionCheck(env)) {
1267 return;
1268 }
1269
1270 }
1271
1272 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_disposeNative
1273 (JNIEnv *env, jclass cls, jlong ptr) {
1274 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1275 disposeIIO(env, data);
1276 }
1277
1278 #define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */
1279
1280 /*
1281 * For EXIF images, the APP1 will appear immediately after the SOI,
1282 * so it's safe to only look at the first marker in the list.
1283 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58)
1284 */
1285 #define IS_EXIF(c) \
1286 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1))
1287
1288 JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initDecompressor
1289 (JNIEnv *env, jobject this, jobject stream) {
1290 imageIODataPtr data;
1291 struct sun_jpeg_error_mgr *jerr_mgr;
1292
1293 /* This struct contains the JPEG decompression parameters and pointers to
1294 * working space (which is allocated as needed by the JPEG library).
1295 */
1296 struct jpeg_decompress_struct *cinfo;
1297 int jret;
1298 int h_samp0, h_samp1, h_samp2;
1299 int v_samp0, v_samp1, v_samp2;
1300 struct jpeg_source_mgr *src;
1301 sun_jpeg_error_ptr jerr;
1302 jbyteArray profileData = NULL;
1303
1304 cinfo = malloc(sizeof (struct jpeg_decompress_struct));
1305 if (cinfo == NULL) {
1306 ThrowByName(env,
1307 "java/lang/OutOfMemoryError",
1308 "Initializing Reader");
1309 return 0;
1310 }
1311
1312 /* We use our private extension JPEG error handler.
1313 */
1314 jerr_mgr = malloc(sizeof (struct sun_jpeg_error_mgr));
1315 if (jerr_mgr == NULL) {
1316 free(cinfo);
1317 ThrowByName(env,
1318 "java/lang/OutOfMemoryError",
1319 "Initializing Reader");
1320 return 0;
1321 }
1322
1323 /* We set up the normal JPEG error routines, then override error_exit. */
1324 cinfo->err = jpeg_std_error(&(jerr_mgr->pub));
1325 jerr_mgr->pub.error_exit = sun_jpeg_error_exit;
1326 /* We need to setup our own print routines */
1327 jerr_mgr->pub.output_message = sun_jpeg_output_message;
1328 /* Now we can setjmp before every call to the library */
1329
1330 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1331 if (setjmp(jerr_mgr->setjmp_buffer)) {
1332 /* If we get here, the JPEG code has signaled an error. */
1333 char buffer[JMSG_LENGTH_MAX];
1334 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1335 buffer);
1336 free(cinfo->err);
1337 free(cinfo);
1338 ThrowByName(env, "java/io/IOException", buffer);
1339 return 0;
1340 }
1341
1342 /* Perform library initialization */
1343 jpeg_create_decompress(cinfo);
1344
1345 // Set up to keep any APP2 markers, as these might contain ICC profile
1346 // data
1347 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
1348
1349 /*
1350 * Now set up our source.
1351 */
1352 cinfo->src =
1353 (struct jpeg_source_mgr *) malloc(sizeof (struct jpeg_source_mgr));
1354 if (cinfo->src == NULL) {
1355 imageio_dispose((j_common_ptr) cinfo);
1356 ThrowByName(env,
1357 "java/lang/OutOfMemoryError",
1358 "Initializing Reader");
1359 return 0;
1360 }
1361 cinfo->src->bytes_in_buffer = 0;
1362 cinfo->src->next_input_byte = NULL;
1363 cinfo->src->init_source = imageio_init_source;
1364 cinfo->src->fill_input_buffer = imageio_fill_input_buffer;
1365 cinfo->src->skip_input_data = imageio_skip_input_data;
1366 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default
1367 cinfo->src->term_source = imageio_term_source;
1368
1369 /* set up the association to persist for future calls */
1370 data = initImageioData(env, (j_common_ptr) cinfo, this);
1371 if (data == NULL) {
1372 imageio_dispose((j_common_ptr) cinfo);
1373 ThrowByName(env,
1374 "java/lang/OutOfMemoryError",
1375 "Initializing Reader");
1376 return 0;
1377 }
1378
1379 imageio_set_stream(env, (j_common_ptr) cinfo, data, stream);
1380
1381 if ((*env)->ExceptionCheck(env)) {
1382 disposeIIO(env, data);
1383 return 0;
1384 }
1385
1386 imageio_init_source((j_decompress_ptr) cinfo);
1387
1388 src = cinfo->src;
1389 jerr = (sun_jpeg_error_ptr) cinfo->err;
1390
1391 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1392 if (setjmp(jerr->setjmp_buffer)) {
1393 /* If we get here, the JPEG code has signaled an error
1394 while reading the header. */
1395 disposeIIO(env, data);
1396 if (!(*env)->ExceptionOccurred(env)) {
1397 char buffer[JMSG_LENGTH_MAX];
1398 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1399 buffer);
1400 ThrowByName(env, "java/io/IOException", buffer);
1401 }
1402
1403 return 0;
1404 }
1405
1406 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1407 ThrowByName(env,
1408 "java/io/IOException",
1409 "Array pin failed");
1410 disposeIIO(env, data);
1411 return 0;
1412 }
1413
1414 jret = jpeg_read_header(cinfo, FALSE);
1415
1416 if (jret == JPEG_HEADER_TABLES_ONLY) {
1417 imageio_term_source(cinfo); // Pushback remaining buffer contents
1418 #ifdef DEBUG_IIO_JPEG
1419 printf("just read tables-only image; q table 0 at %p\n",
1420 cinfo->quant_tbl_ptrs[0]);
1421 #endif
1422 RELEASE_ARRAYS(env, data, src->next_input_byte);
1423 } else {
1424 /*
1425 * Now adjust the jpeg_color_space variable, which was set in
1426 * default_decompress_parms, to reflect our differences from IJG
1427 */
1428
1429 switch (cinfo->jpeg_color_space) {
1430 default:
1431 break;
1432 case JCS_YCbCr:
1433
1434 /*
1435 * There are several possibilities:
1436 * - we got image with embeded colorspace
1437 * Use it. User knows what he is doing.
1438 * - we got JFIF image
1439 * Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2)
1440 * - we got EXIF image
1441 * Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63)
1442 * - something else
1443 * Apply heuristical rules to identify actual colorspace.
1444 */
1445
1446 if (cinfo->saw_Adobe_marker) {
1447 if (cinfo->Adobe_transform != 1) {
1448 /*
1449 * IJG guesses this is YCbCr and emits a warning
1450 * We would rather not guess. Then the user knows
1451 * To read this as a Raster if at all
1452 */
1453 cinfo->jpeg_color_space = JCS_UNKNOWN;
1454 cinfo->out_color_space = JCS_UNKNOWN;
1455 }
1456 }
1457 break;
1458 #ifdef YCCALPHA
1459 case JCS_YCC:
1460 cinfo->out_color_space = JCS_YCC;
1461 break;
1462 #endif
1463 case JCS_YCCK:
1464 if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) {
1465 /*
1466 * IJG guesses this is YCCK and emits a warning
1467 * We would rather not guess. Then the user knows
1468 * To read this as a Raster if at all
1469 */
1470 cinfo->jpeg_color_space = JCS_UNKNOWN;
1471 cinfo->out_color_space = JCS_UNKNOWN;
1472 } else {
1473 /* There is no support for YCCK on jfx side, so request RGB output */
1474 cinfo->out_color_space = JCS_RGB;
1475 }
1476 break;
1477 case JCS_CMYK:
1478 /*
1479 * IJG assumes all unidentified 4-channels are CMYK.
1480 * We assume that only if the second two channels are
1481 * not subsampled (either horizontally or vertically).
1482 * If they are, we assume YCCK.
1483 */
1484 h_samp0 = cinfo->comp_info[0].h_samp_factor;
1485 h_samp1 = cinfo->comp_info[1].h_samp_factor;
1486 h_samp2 = cinfo->comp_info[2].h_samp_factor;
1487
1488 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1489 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1490 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1491
1492 if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) ||
1493 (v_samp1 > v_samp0) && (v_samp2 > v_samp0)) {
1494 cinfo->jpeg_color_space = JCS_YCCK;
1495 /* Leave the output space as CMYK */
1496 }
1497
1498 /* There is no support for CMYK on jfx side, so request RGB output */
1499 cinfo->out_color_space = JCS_RGB;
1500 }
1501 RELEASE_ARRAYS(env, data, src->next_input_byte);
1502
1503 /* read icc profile data */
1504 profileData = read_icc_profile(env, cinfo);
1505
1506 if ((*env)->ExceptionCheck(env)) {
1507 disposeIIO(env, data);
1508 return 0;
1509 }
1510
1511 (*env)->CallVoidMethod(env, this,
1512 JPEGImageLoader_setInputAttributesID,
1513 cinfo->image_width,
1514 cinfo->image_height,
1515 cinfo->jpeg_color_space,
1516 cinfo->out_color_space,
1517 cinfo->num_components,
1518 profileData);
1519 if ((*env)->ExceptionCheck(env)) {
1520 disposeIIO(env, data);
1521 return 0;
1522 }
1523 }
1524
1525 return ptr_to_jlong(data);
1526 }
1527
1528 JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_startDecompression
1529 (JNIEnv *env, jobject this, jlong ptr, jint outCS, jint dest_width, jint dest_height) {
1530 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1531 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1532 struct jpeg_source_mgr *src = cinfo->src;
1533 sun_jpeg_error_ptr jerr;
1534
1535 jfloat x_scale;
1536 jfloat y_scale;
1537 jfloat max_scale;
1538
1539 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1540 ThrowByName(env,
1541 "java/io/IOException",
1542 "Array pin failed");
1543 return JCS_UNKNOWN;
1544 }
1545
1546 cinfo = (j_decompress_ptr) data->jpegObj;
1547
1548 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1549 jerr = (sun_jpeg_error_ptr) cinfo->err;
1550
1551 if (setjmp(jerr->setjmp_buffer)) {
1552 /* If we get here, the JPEG code has signaled an error
1553 while initializing compression. */
1554 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1555 if (!(*env)->ExceptionOccurred(env)) {
1556 char buffer[JMSG_LENGTH_MAX];
1557 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1558 buffer);
1559 ThrowByName(env, "java/io/IOException", buffer);
1560 }
1561 return JCS_UNKNOWN;
1562 }
1563
1564 cinfo->out_color_space = outCS;
1565
1566 /* decide how much we want to sub-sample the incoming jpeg image.
1567 * The libjpeg docs say:
1568 *
1569 * unsigned int scale_num, scale_denom
1570 *
1571 * Scale the image by the fraction scale_num/scale_denom. Default is
1572 * 1/1, or no scaling. Currently, the only supported scaling ratios
1573 * are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary
1574 * scaling ratios but this is not likely to be implemented any time soon.)
1575 * Smaller scaling ratios permit significantly faster decoding since
1576 * fewer pixels need be processed and a simpler IDCT method can be used.
1577 */
1578
1579 cinfo->scale_num = 1;
1580
1581 x_scale = (jfloat) dest_width / (jfloat) cinfo->image_width;
1582 y_scale = (jfloat) dest_height / (jfloat) cinfo->image_height;
1583 max_scale = x_scale > y_scale ? x_scale : y_scale;
1584
1585 if (max_scale > 0.5) {
1586 cinfo->scale_denom = 1;
1587 } else if (max_scale > 0.25) {
1588 cinfo->scale_denom = 2;
1589 } else if (max_scale > 0.125) {
1590 cinfo->scale_denom = 4;
1591 } else {
1592 cinfo->scale_denom = 8;
1593 }
1594
1595 jpeg_start_decompress(cinfo);
1596
1597 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1598 (*env)->CallVoidMethod(env, this,
1599 JPEGImageLoader_setOutputAttributesID,
1600 cinfo->output_width,
1601 cinfo->output_height);
1602
1603 return cinfo->output_components;
1604 }
1605
1606 #define SAFE_TO_MULT(a, b) (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b)))
1607
1608 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_decompressIndirect
1609 (JNIEnv *env, jobject this, jlong ptr, jboolean report_progress, jbyteArray barray) {
1610 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1611 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1612 struct jpeg_source_mgr *src = cinfo->src;
1613 sun_jpeg_error_ptr jerr;
1614 int bytes_per_row = cinfo->output_width * cinfo->output_components;
1615 int offset = 0;
1616 JSAMPROW scanline_ptr = NULL;
1617
1618 if (!SAFE_TO_MULT(cinfo->output_width, cinfo->output_components) ||
1619 !SAFE_TO_MULT(bytes_per_row, cinfo->output_height) ||
1620 ((*env)->GetArrayLength(env, barray) <
1621 (bytes_per_row * cinfo->output_height)))
1622 {
1623 ThrowByName(env,
1624 "java/lang/OutOfMemoryError",
1625 "Reading JPEG Stream");
1626 return JNI_FALSE;
1627 }
1628
1629 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1630 ThrowByName(env,
1631 "java/io/IOException",
1632 "Array pin failed");
1633 return JNI_FALSE;
1634 }
1635
1636 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1637 jerr = (sun_jpeg_error_ptr) cinfo->err;
1638
1639 if (setjmp(jerr->setjmp_buffer)) {
1640 /* If we get here, the JPEG code has signaled an error
1641 while reading. */
1642 if (!(*env)->ExceptionOccurred(env)) {
1643 char buffer[JMSG_LENGTH_MAX];
1644 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1645 buffer);
1646 ThrowByName(env, "java/io/IOException", buffer);
1647 }
1648 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1649 return JNI_FALSE;
1650 }
1651
1652 scanline_ptr = (JSAMPROW) malloc(bytes_per_row * sizeof(JSAMPLE));
1653 if (scanline_ptr == NULL) {
1654 ThrowByName(env,
1655 "java/lang/OutOfMemoryError",
1656 "Reading JPEG Stream");
1657 return JNI_FALSE;
1658 }
1659
1660 while (cinfo->output_scanline < cinfo->output_height) {
1661 int num_scanlines;
1662 if (report_progress == JNI_TRUE) {
1663 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1664 (*env)->CallVoidMethod(env, this,
1665 JPEGImageLoader_updateImageProgressID,
1666 cinfo->output_scanline);
1667 if ((*env)->ExceptionCheck(env)) {
1668 free(scanline_ptr);
1669 return JNI_FALSE;
1670 }
1671 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1672 free(scanline_ptr);
1673 ThrowByName(env,
1674 "java/io/IOException",
1675 "Array pin failed");
1676 return JNI_FALSE;
1677 }
1678 }
1679
1680 num_scanlines = jpeg_read_scanlines(cinfo, &scanline_ptr, 1);
1681 if (num_scanlines == 1) {
1682 jbyte *body = (*env)->GetPrimitiveArrayCritical(env, barray, NULL);
1683 if (body == NULL) {
1684 fprintf(stderr, "decompressIndirect: GetPrimitiveArrayCritical returns NULL: out of memory\n");
1685 free(scanline_ptr);
1686 return JNI_FALSE;
1687 }
1688 memcpy(body+offset,scanline_ptr, bytes_per_row);
1689 (*env)->ReleasePrimitiveArrayCritical(env, barray, body, JNI_ABORT);
1690 offset += bytes_per_row;
1691 }
1692 }
1693 free(scanline_ptr);
1694
1695 if (report_progress == JNI_TRUE) {
1696 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1697 (*env)->CallVoidMethod(env, this,
1698 JPEGImageLoader_updateImageProgressID,
1699 cinfo->output_height);
1700 if ((*env)->ExceptionCheck(env)) {
1701 return JNI_FALSE;
1702 }
1703 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1704 ThrowByName(env,
1705 "java/io/IOException",
1706 "Array pin failed");
1707 return JNI_FALSE;
1708 }
1709 }
1710
1711 jpeg_finish_decompress(cinfo);
1712
1713 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1714 return JNI_TRUE;
1715 }