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