1 /*
2 * Copyright (c) 2009, 2018, 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 /*************** end of shared utility code ****************/
690
691 /********************** Loader Support **************************/
692
693 /********************** Source Management ***********************/
694
695 /*
696 * INPUT HANDLING:
697 *
698 * The JPEG library's input management is defined by the jpeg_source_mgr
699 * structure which contains two fields to convey the information in the
700 * buffer and 5 methods which perform all buffer management. The library
701 * defines a standard input manager that uses stdio for obtaining compressed
702 * jpeg data, but here we need to use Java to get our data.
703 *
704 * We use the library jpeg_source_mgr but our own routines that access
705 * imageio-specific information in the imageIOData structure.
706 */
707
708 /*
709 * Initialize source. This is called by jpeg_read_header() before any
710 * data is actually read. Unlike init_destination(), it may leave
711 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
712 * will occur immediately).
713 */
714
715 GLOBAL(void)
716 imageio_init_source(j_decompress_ptr cinfo) {
717 struct jpeg_source_mgr *src = cinfo->src;
718 src->next_input_byte = NULL;
719 src->bytes_in_buffer = 0;
720 }
721
722 /*
723 * This is called whenever bytes_in_buffer has reached zero and more
724 * data is wanted. In typical applications, it should read fresh data
725 * into the buffer (ignoring the current state of next_input_byte and
726 * bytes_in_buffer), reset the pointer & count to the start of the
727 * buffer, and return TRUE indicating that the buffer has been reloaded.
728 * It is not necessary to fill the buffer entirely, only to obtain at
729 * least one more byte. bytes_in_buffer MUST be set to a positive value
730 * if TRUE is returned. A FALSE return should only be used when I/O
731 * suspension is desired (this mode is discussed in the next section).
732 */
733
734 /*
735 * Note that with I/O suspension turned on, this procedure should not
736 * do any work since the JPEG library has a very simple backtracking
737 * mechanism which relies on the fact that the buffer will be filled
738 * only when it has backed out to the top application level. When
739 * suspendable is turned on, imageio_fill_suspended_buffer will
740 * do the actual work of filling the buffer.
741 */
742
743 GLOBAL(boolean)
744 imageio_fill_input_buffer(j_decompress_ptr cinfo) {
745 struct jpeg_source_mgr *src = cinfo->src;
746 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
747 streamBufferPtr sb = &data->streamBuf;
748 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
749 int ret;
750
751 /* This is where input suspends */
752 if (sb->suspendable) {
753 return FALSE;
754 }
755
756 #ifdef DEBUG_IIO_JPEG
757 printf("Filling input buffer, remaining skip is %ld, ",
758 sb->remaining_skip);
759 printf("Buffer length is %d\n", sb->bufferLength);
760 #endif
761
762 /*
763 * Definitively skips. Could be left over if we tried to skip
764 * more than a buffer's worth but suspended when getting the next
765 * buffer. Now we aren't suspended, so we can catch up.
766 */
767 if (sb->remaining_skip) {
768 src->skip_input_data(cinfo, 0);
769 }
770
771 /*
772 * Now fill a complete buffer, or as much of one as the stream
773 * will give us if we are near the end.
774 */
775 RELEASE_ARRAYS(env, data, src->next_input_byte);
776 ret = (*env)->CallIntMethod(env,
777 sb->stream,
778 InputStream_readID,
779 sb->hstreamBuffer, 0,
780 sb->bufferLength);
781 if (ret > sb->bufferLength) ret = sb->bufferLength;
782 if ((*env)->ExceptionOccurred(env)
783 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
784 cinfo->err->error_exit((j_common_ptr) cinfo);
785 }
786
787 #ifdef DEBUG_IIO_JPEG
788 printf("Buffer filled. ret = %d\n", ret);
789 #endif
790 /*
791 * If we have reached the end of the stream, then the EOI marker
792 * is missing. We accept such streams but generate a warning.
793 * The image is likely to be corrupted, though everything through
794 * the end of the last complete MCU should be usable.
795 */
796 if (ret <= 0) {
797 jobject reader = data->imageIOobj;
798 #ifdef DEBUG_IIO_JPEG
799 printf("YO! Early EOI! ret = %d\n", ret);
800 #endif
801 RELEASE_ARRAYS(env, data, src->next_input_byte);
802 (*env)->CallVoidMethod(env, reader,
803 JPEGImageLoader_emitWarningID,
804 READ_NO_EOI);
805 if ((*env)->ExceptionOccurred(env)
806 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
807 cinfo->err->error_exit((j_common_ptr) cinfo);
808 }
809
810 sb->buf[0] = (JOCTET) 0xFF;
811 sb->buf[1] = (JOCTET) JPEG_EOI;
812 ret = 2;
813 }
814
815 src->next_input_byte = sb->buf;
816 src->bytes_in_buffer = ret;
817
818 return TRUE;
819 }
820
821 /*
822 * With I/O suspension turned on, the JPEG library requires that all
823 * buffer filling be done at the top application level, using this
824 * function. Due to the way that backtracking works, this procedure
825 * saves all of the data that was left in the buffer when suspension
826 * occured and read new data only at the end.
827 */
828
829 GLOBAL(void)
830 imageio_fill_suspended_buffer(j_decompress_ptr cinfo) {
831 struct jpeg_source_mgr *src = cinfo->src;
832 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
833 streamBufferPtr sb = &data->streamBuf;
834 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
835 jint ret;
836 int offset, buflen;
837
838 /*
839 * The original (jpegdecoder.c) had code here that called
840 * InputStream.available and just returned if the number of bytes
841 * available was less than any remaining skip. Presumably this was
842 * to avoid blocking, although the benefit was unclear, as no more
843 * decompression can take place until more data is available, so
844 * the code would block on input a little further along anyway.
845 * ImageInputStreams don't have an available method, so we'll just
846 * block in the skip if we have to.
847 */
848
849 if (sb->remaining_skip) {
850 src->skip_input_data(cinfo, 0);
851 }
852
853 /* Save the data currently in the buffer */
854 offset = src->bytes_in_buffer;
855 if (src->next_input_byte > sb->buf) {
856 memcpy(sb->buf, src->next_input_byte, offset);
857 }
858 RELEASE_ARRAYS(env, data, src->next_input_byte);
859 buflen = sb->bufferLength - offset;
860 if (buflen <= 0) {
861 if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
862 cinfo->err->error_exit((j_common_ptr) cinfo);
863 }
864 return;
865 }
866
867 ret = (*env)->CallIntMethod(env, sb->stream,
868 InputStream_readID,
869 sb->hstreamBuffer,
870 offset, buflen);
871 if (ret > buflen) ret = buflen;
872 if ((*env)->ExceptionOccurred(env)
873 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
874 cinfo->err->error_exit((j_common_ptr) cinfo);
875 }
876 /*
877 * If we have reached the end of the stream, then the EOI marker
878 * is missing. We accept such streams but generate a warning.
879 * The image is likely to be corrupted, though everything through
880 * the end of the last complete MCU should be usable.
881 */
882 if (ret <= 0) {
883 jobject reader = data->imageIOobj;
884 RELEASE_ARRAYS(env, data, src->next_input_byte);
885 (*env)->CallVoidMethod(env, reader,
886 JPEGImageLoader_emitWarningID,
887 READ_NO_EOI);
888 if ((*env)->ExceptionOccurred(env)
889 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
890 cinfo->err->error_exit((j_common_ptr) cinfo);
891 }
892
893 sb->buf[offset] = (JOCTET) 0xFF;
894 sb->buf[offset + 1] = (JOCTET) JPEG_EOI;
895 ret = 2;
896 }
897
898 src->next_input_byte = sb->buf;
899 src->bytes_in_buffer = ret + offset;
900
901 return;
902 }
903
904 /*
905 * Skip num_bytes worth of data. The buffer pointer and count are
906 * advanced over num_bytes input bytes, using the input stream
907 * skipBytes method if the skip is greater than the number of bytes
908 * in the buffer. This is used to skip over a potentially large amount of
909 * uninteresting data (such as an APPn marker). bytes_in_buffer will be
910 * zero on return if the skip is larger than the current contents of the
911 * buffer.
912 *
913 * A negative skip count is treated as a no-op. A zero skip count
914 * skips any remaining skip from a previous skip while suspended.
915 *
916 * Note that with I/O suspension turned on, this procedure does not
917 * call skipBytes since the JPEG library has a very simple backtracking
918 * mechanism which relies on the fact that the application level has
919 * exclusive control over actual I/O.
920 */
921
922 GLOBAL(void)
923 imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
924 struct jpeg_source_mgr *src = cinfo->src;
925 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
926 streamBufferPtr sb = &data->streamBuf;
927 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
928 jlong ret;
929 jobject reader;
930
931 if (num_bytes < 0) {
932 return;
933 }
934 num_bytes += sb->remaining_skip;
935 sb->remaining_skip = 0;
936
937 /* First the easy case where we are skipping <= the current contents. */
938 ret = src->bytes_in_buffer;
939 if (ret >= num_bytes) {
940 src->next_input_byte += num_bytes;
941 src->bytes_in_buffer -= num_bytes;
942 return;
943 }
944
945 /*
946 * We are skipping more than is in the buffer. We empty the buffer and,
947 * if we aren't suspended, call the Java skipBytes method. We always
948 * leave the buffer empty, to be filled by either fill method above.
949 */
950 src->bytes_in_buffer = 0;
951 src->next_input_byte = sb->buf;
952
953 num_bytes -= (long) ret;
954 if (sb->suspendable) {
955 sb->remaining_skip = num_bytes;
956 return;
957 }
958
959 RELEASE_ARRAYS(env, data, src->next_input_byte);
960 ret = (*env)->CallLongMethod(env,
961 sb->stream,
962 InputStream_skipID,
963 (jlong) num_bytes);
964 if ((*env)->ExceptionOccurred(env)
965 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
966 cinfo->err->error_exit((j_common_ptr) cinfo);
967 }
968
969 /*
970 * If we have reached the end of the stream, then the EOI marker
971 * is missing. We accept such streams but generate a warning.
972 * The image is likely to be corrupted, though everything through
973 * the end of the last complete MCU should be usable.
974 */
975 if (ret <= 0) {
976 reader = data->imageIOobj;
977 RELEASE_ARRAYS(env, data, src->next_input_byte);
978 (*env)->CallVoidMethod(env,
979 reader,
980 JPEGImageLoader_emitWarningID,
981 READ_NO_EOI);
982
983 if ((*env)->ExceptionOccurred(env)
984 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
985 cinfo->err->error_exit((j_common_ptr) cinfo);
986 }
987 sb->buf[0] = (JOCTET) 0xFF;
988 sb->buf[1] = (JOCTET) JPEG_EOI;
989 src->bytes_in_buffer = 2;
990 src->next_input_byte = sb->buf;
991 }
992 }
993
994 /*
995 * Terminate source --- called by jpeg_finish_decompress() after all
996 * data for an image has been read. In our case pushes back any
997 * remaining data, as it will be for another image and must be available
998 * for java to find out that there is another image. Also called if
999 * reseting state after reading a tables-only image.
1000 */
1001
1002 GLOBAL(void)
1003 imageio_term_source(j_decompress_ptr cinfo) {
1004 // To pushback, just seek back by src->bytes_in_buffer
1005 struct jpeg_source_mgr *src = cinfo->src;
1006 imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
1007 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2);
1008 jobject reader = data->imageIOobj;
1009 if (src->bytes_in_buffer > 0) {
1010 RELEASE_ARRAYS(env, data, src->next_input_byte);
1011
1012 if ((*env)->ExceptionOccurred(env)
1013 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1014 cinfo->err->error_exit((j_common_ptr) cinfo);
1015 }
1016 src->bytes_in_buffer = 0;
1017 //src->next_input_byte = sb->buf;
1018 }
1019 }
1020
1021 /********************* end of source manager ******************/
1022
1023 /********************* ICC profile support ********************/
1024 /*
1025 * The following routines are modified versions of the ICC
1026 * profile support routines available from the IJG website.
1027 * The originals were written by Todd Newman
1028 * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for
1029 * the IJG. They are further modified to fit in the context
1030 * of the imageio JPEG plug-in.
1031 */
1032
1033 /*
1034 * Since an ICC profile can be larger than the maximum size of a JPEG marker
1035 * (64K), we need provisions to split it into multiple markers. The format
1036 * defined by the ICC specifies one or more APP2 markers containing the
1037 * following data:
1038 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
1039 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
1040 * Number of markers Total number of APP2's used (1 byte)
1041 * Profile data (remainder of APP2 data)
1042 * Decoders should use the marker sequence numbers to reassemble the profile,
1043 * rather than assuming that the APP2 markers appear in the correct sequence.
1044 */
1045
1046 #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
1047 #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
1048 #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
1049 #define MAX_DATA_BYTES_IN_ICC_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
1050
1051 /*
1052 * Handy subroutine to test whether a saved marker is an ICC profile marker.
1053 */
1054
1055 static boolean
1056 marker_is_icc(jpeg_saved_marker_ptr marker) {
1057 return
1058 marker->marker == ICC_MARKER &&
1059 marker->data_length >= ICC_OVERHEAD_LEN &&
1060 /* verify the identifying string */
1061 GETJOCTET(marker->data[0]) == 0x49 &&
1062 GETJOCTET(marker->data[1]) == 0x43 &&
1063 GETJOCTET(marker->data[2]) == 0x43 &&
1064 GETJOCTET(marker->data[3]) == 0x5F &&
1065 GETJOCTET(marker->data[4]) == 0x50 &&
1066 GETJOCTET(marker->data[5]) == 0x52 &&
1067 GETJOCTET(marker->data[6]) == 0x4F &&
1068 GETJOCTET(marker->data[7]) == 0x46 &&
1069 GETJOCTET(marker->data[8]) == 0x49 &&
1070 GETJOCTET(marker->data[9]) == 0x4C &&
1071 GETJOCTET(marker->data[10]) == 0x45 &&
1072 GETJOCTET(marker->data[11]) == 0x0;
1073 }
1074
1075 /*
1076 * See if there was an ICC profile in the JPEG file being read;
1077 * if so, reassemble and return the profile data as a new Java byte array.
1078 * If there was no ICC profile, return NULL.
1079 *
1080 * If the file contains invalid ICC APP2 markers, we throw an IIOException
1081 * with an appropriate message.
1082 */
1083
1084 jbyteArray
1085 read_icc_profile(JNIEnv *env, j_decompress_ptr cinfo) {
1086 jpeg_saved_marker_ptr marker;
1087 int num_markers = 0;
1088 int num_found_markers = 0;
1089 int seq_no;
1090 JOCTET *icc_data;
1091 JOCTET *dst_ptr;
1092 unsigned int total_length;
1093 #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes
1094 jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1];
1095 int first; // index of the first marker in the icc_markers array
1096 int last; // index of the last marker in the icc_markers array
1097 jbyteArray data = NULL;
1098
1099 /* This first pass over the saved markers discovers whether there are
1100 * any ICC markers and verifies the consistency of the marker numbering.
1101 */
1102
1103 for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++)
1104 icc_markers[seq_no] = NULL;
1105
1106
1107 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
1108 if (marker_is_icc(marker)) {
1109 if (num_markers == 0)
1110 num_markers = GETJOCTET(marker->data[13]);
1111 else if (num_markers != GETJOCTET(marker->data[13])) {
1112 ThrowByName(env, "java/io/IOException",
1113 "Invalid icc profile: inconsistent num_markers fields");
1114 return NULL;
1115 }
1116 seq_no = GETJOCTET(marker->data[12]);
1117
1118 /* Some third-party tools produce images with profile chunk
1119 * numeration started from zero. It is inconsistent with ICC
1120 * spec, but seems to be recognized by majority of image
1121 * processing tools, so we should be more tolerant to this
1122 * departure from the spec.
1123 */
1124 if (seq_no < 0 || seq_no > num_markers) {
1125 ThrowByName(env, "java/io/IOException",
1126 "Invalid icc profile: bad sequence number");
1127 return NULL;
1128 }
1129 if (icc_markers[seq_no] != NULL) {
1130 ThrowByName(env, "java/io/IOException",
1131 "Invalid icc profile: duplicate sequence numbers");
1132 return NULL;
1133 }
1134 icc_markers[seq_no] = marker;
1135 num_found_markers++;
1136 }
1137 }
1138
1139 if (num_markers == 0)
1140 return NULL; // There is no profile
1141
1142 if (num_markers != num_found_markers) {
1143 ThrowByName(env, "java/io/IOException",
1144 "Invalid icc profile: invalid number of icc markers");
1145 return NULL;
1146 }
1147
1148 first = icc_markers[0] ? 0 : 1;
1149 last = num_found_markers + first;
1150
1151 /* Check for missing markers, count total space needed.
1152 */
1153 total_length = 0;
1154 for (seq_no = first; seq_no < last; seq_no++) {
1155 unsigned int length;
1156 if (icc_markers[seq_no] == NULL) {
1157 ThrowByName(env, "java/io/IOException",
1158 "Invalid icc profile: missing sequence number");
1159 return NULL;
1160 }
1161 /* check the data length correctness */
1162 length = icc_markers[seq_no]->data_length;
1163 if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) {
1164 ThrowByName(env, "java/io/IOException",
1165 "Invalid icc profile: invalid data length");
1166 return NULL;
1167 }
1168 total_length += (length - ICC_OVERHEAD_LEN);
1169 }
1170
1171 if (total_length <= 0) {
1172 ThrowByName(env, "java/io/IOException",
1173 "Invalid icc profile: found only empty markers");
1174 return NULL;
1175 }
1176
1177 /* Allocate a Java byte array for assembled data */
1178
1179 data = (*env)->NewByteArray(env, total_length);
1180 if (data == NULL) {
1181 ThrowByName(env,
1182 "java/lang/OutOfMemoryError",
1183 "Reading ICC profile");
1184 return NULL;
1185 }
1186
1187 icc_data = (JOCTET *) (*env)->GetPrimitiveArrayCritical(env,
1188 data,
1189 NULL);
1190 if (icc_data == NULL) {
1191 ThrowByName(env, "java/io/IOException",
1192 "Unable to pin icc profile data array");
1193 return NULL;
1194 }
1195
1196 /* and fill it in */
1197 dst_ptr = icc_data;
1198 for (seq_no = first; seq_no < last; seq_no++) {
1199 JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN;
1200 unsigned int length =
1201 icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN;
1202
1203 memcpy(dst_ptr, src_ptr, length);
1204 dst_ptr += length;
1205 }
1206
1207 /* finally, unpin the array */
1208 (*env)->ReleasePrimitiveArrayCritical(env,
1209 data,
1210 icc_data,
1211 0);
1212
1213
1214 return data;
1215 }
1216
1217 /********************* end of ICC profile support *************/
1218
1219 /********************* Loader JNI calls ***********************/
1220
1221 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initJPEGMethodIDs
1222 (JNIEnv *env, jclass cls, jclass InputStreamClass) {
1223 // InputStream methods.
1224 InputStream_readID = (*env)->GetMethodID(env,
1225 InputStreamClass,
1226 "read",
1227 "([BII)I");
1228 if ((*env)->ExceptionCheck(env)) {
1229 return;
1230 }
1231
1232 InputStream_skipID = (*env)->GetMethodID(env,
1233 InputStreamClass,
1234 "skip",
1235 "(J)J");
1236 if ((*env)->ExceptionCheck(env)) {
1237 return;
1238 }
1239
1240 // JPEGImageLoader IDs.
1241 JPEGImageLoader_setInputAttributesID = (*env)->GetMethodID(env,
1242 cls,
1243 "setInputAttributes",
1244 "(IIIII[B)V");
1245 if ((*env)->ExceptionCheck(env)) {
1246 return;
1247 }
1248
1249 JPEGImageLoader_setOutputAttributesID = (*env)->GetMethodID(env,
1250 cls,
1251 "setOutputAttributes",
1252 "(II)V");
1253 if ((*env)->ExceptionCheck(env)) {
1254 return;
1255 }
1256
1257 JPEGImageLoader_updateImageProgressID = (*env)->GetMethodID(env,
1258 cls,
1259 "updateImageProgress",
1260 "(I)V");
1261 if ((*env)->ExceptionCheck(env)) {
1262 return;
1263 }
1264
1265 JPEGImageLoader_emitWarningID = (*env)->GetMethodID(env,
1266 cls,
1267 "emitWarning",
1268 "(Ljava/lang/String;)V");
1269 if ((*env)->ExceptionCheck(env)) {
1270 return;
1271 }
1272
1273 }
1274
1275 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_disposeNative
1276 (JNIEnv *env, jclass cls, jlong ptr) {
1277 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1278 j_common_ptr info = destroyImageioData(env, data);
1279
1280 imageio_dispose(info);
1281 }
1282
1283 #define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */
1284
1285 /*
1286 * For EXIF images, the APP1 will appear immediately after the SOI,
1287 * so it's safe to only look at the first marker in the list.
1288 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58)
1289 */
1290 #define IS_EXIF(c) \
1291 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1))
1292
1293 JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initDecompressor
1294 (JNIEnv *env, jobject this, jobject stream) {
1295 imageIODataPtr data;
1296 struct sun_jpeg_error_mgr *jerr_mgr;
1297
1298 /* This struct contains the JPEG decompression parameters and pointers to
1299 * working space (which is allocated as needed by the JPEG library).
1300 */
1301 struct jpeg_decompress_struct *cinfo;
1302 int jret;
1303 int h_samp0, h_samp1, h_samp2;
1304 int v_samp0, v_samp1, v_samp2;
1305 struct jpeg_source_mgr *src;
1306 sun_jpeg_error_ptr jerr;
1307 jbyteArray profileData = NULL;
1308
1309 cinfo = malloc(sizeof (struct jpeg_decompress_struct));
1310 if (cinfo == NULL) {
1311 ThrowByName(env,
1312 "java/lang/OutOfMemoryError",
1313 "Initializing Reader");
1314 return 0;
1315 }
1316
1317 /* We use our private extension JPEG error handler.
1318 */
1319 jerr_mgr = malloc(sizeof (struct sun_jpeg_error_mgr));
1320 if (jerr_mgr == NULL) {
1321 free(cinfo);
1322 ThrowByName(env,
1323 "java/lang/OutOfMemoryError",
1324 "Initializing Reader");
1325 return 0;
1326 }
1327
1328 /* We set up the normal JPEG error routines, then override error_exit. */
1329 cinfo->err = jpeg_std_error(&(jerr_mgr->pub));
1330 jerr_mgr->pub.error_exit = sun_jpeg_error_exit;
1331 /* We need to setup our own print routines */
1332 jerr_mgr->pub.output_message = sun_jpeg_output_message;
1333 /* Now we can setjmp before every call to the library */
1334
1335 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1336 if (setjmp(jerr_mgr->setjmp_buffer)) {
1337 /* If we get here, the JPEG code has signaled an error. */
1338 char buffer[JMSG_LENGTH_MAX];
1339 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1340 buffer);
1341 ThrowByName(env, "java/io/IOException", buffer);
1342 return 0;
1343 }
1344
1345 /* Perform library initialization */
1346 jpeg_create_decompress(cinfo);
1347
1348 // Set up to keep any APP2 markers, as these might contain ICC profile
1349 // data
1350 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
1351
1352 /*
1353 * Now set up our source.
1354 */
1355 cinfo->src =
1356 (struct jpeg_source_mgr *) malloc(sizeof (struct jpeg_source_mgr));
1357 if (cinfo->src == NULL) {
1358 ThrowByName(env,
1359 "java/lang/OutOfMemoryError",
1360 "Initializing Reader");
1361 return 0;
1362 }
1363 cinfo->src->bytes_in_buffer = 0;
1364 cinfo->src->next_input_byte = NULL;
1365 cinfo->src->init_source = imageio_init_source;
1366 cinfo->src->fill_input_buffer = imageio_fill_input_buffer;
1367 cinfo->src->skip_input_data = imageio_skip_input_data;
1368 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default
1369 cinfo->src->term_source = imageio_term_source;
1370
1371 /* set up the association to persist for future calls */
1372 data = initImageioData(env, (j_common_ptr) cinfo, this);
1373 if (data == NULL) {
1374 ThrowByName(env,
1375 "java/lang/OutOfMemoryError",
1376 "Initializing Reader");
1377 return 0;
1378 }
1379
1380 imageio_set_stream(env, (j_common_ptr) cinfo, data, stream);
1381
1382 if ((*env)->ExceptionCheck(env)) return 0;
1383
1384 imageio_init_source((j_decompress_ptr) cinfo);
1385
1386 src = cinfo->src;
1387 jerr = (sun_jpeg_error_ptr) cinfo->err;
1388
1389 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1390 if (setjmp(jerr->setjmp_buffer)) {
1391 /* If we get here, the JPEG code has signaled an error
1392 while reading the header. */
1393 RELEASE_ARRAYS(env, data, src->next_input_byte);
1394 if (!(*env)->ExceptionOccurred(env)) {
1395 char buffer[JMSG_LENGTH_MAX];
1396 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1397 buffer);
1398 ThrowByName(env, "java/io/IOException", buffer);
1399 }
1400 return 0;
1401 }
1402
1403 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1404 ThrowByName(env,
1405 "java/io/IOException",
1406 "Array pin failed");
1407 return 0;
1408 }
1409
1410 jret = jpeg_read_header(cinfo, FALSE);
1411
1412 if (jret == JPEG_HEADER_TABLES_ONLY) {
1413 imageio_term_source(cinfo); // Pushback remaining buffer contents
1414 #ifdef DEBUG_IIO_JPEG
1415 printf("just read tables-only image; q table 0 at %p\n",
1416 cinfo->quant_tbl_ptrs[0]);
1417 #endif
1418 RELEASE_ARRAYS(env, data, src->next_input_byte);
1419 } else {
1420 /*
1421 * Now adjust the jpeg_color_space variable, which was set in
1422 * default_decompress_parms, to reflect our differences from IJG
1423 */
1424
1425 switch (cinfo->jpeg_color_space) {
1426 default:
1427 break;
1428 case JCS_YCbCr:
1429
1430 /*
1431 * There are several possibilities:
1432 * - we got image with embeded colorspace
1433 * Use it. User knows what he is doing.
1434 * - we got JFIF image
1435 * Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2)
1436 * - we got EXIF image
1437 * Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63)
1438 * - something else
1439 * Apply heuristical rules to identify actual colorspace.
1440 */
1441
1442 if (cinfo->saw_Adobe_marker) {
1443 if (cinfo->Adobe_transform != 1) {
1444 /*
1445 * IJG guesses this is YCbCr and emits a warning
1446 * We would rather not guess. Then the user knows
1447 * To read this as a Raster if at all
1448 */
1449 cinfo->jpeg_color_space = JCS_UNKNOWN;
1450 cinfo->out_color_space = JCS_UNKNOWN;
1451 }
1452 }
1453 break;
1454 #ifdef YCCALPHA
1455 case JCS_YCC:
1456 cinfo->out_color_space = JCS_YCC;
1457 break;
1458 #endif
1459 case JCS_YCCK:
1460 if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) {
1461 /*
1462 * IJG guesses this is YCCK and emits a warning
1463 * We would rather not guess. Then the user knows
1464 * To read this as a Raster if at all
1465 */
1466 cinfo->jpeg_color_space = JCS_UNKNOWN;
1467 cinfo->out_color_space = JCS_UNKNOWN;
1468 } else {
1469 /* There is no support for YCCK on jfx side, so request RGB output */
1470 cinfo->out_color_space = JCS_RGB;
1471 }
1472 break;
1473 case JCS_CMYK:
1474 /*
1475 * IJG assumes all unidentified 4-channels are CMYK.
1476 * We assume that only if the second two channels are
1477 * not subsampled (either horizontally or vertically).
1478 * If they are, we assume YCCK.
1479 */
1480 h_samp0 = cinfo->comp_info[0].h_samp_factor;
1481 h_samp1 = cinfo->comp_info[1].h_samp_factor;
1482 h_samp2 = cinfo->comp_info[2].h_samp_factor;
1483
1484 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1485 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1486 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1487
1488 if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) ||
1489 (v_samp1 > v_samp0) && (v_samp2 > v_samp0)) {
1490 cinfo->jpeg_color_space = JCS_YCCK;
1491 /* Leave the output space as CMYK */
1492 }
1493
1494 /* There is no support for CMYK on jfx side, so request RGB output */
1495 cinfo->out_color_space = JCS_RGB;
1496 }
1497 RELEASE_ARRAYS(env, data, src->next_input_byte);
1498
1499 /* read icc profile data */
1500 profileData = read_icc_profile(env, cinfo);
1501
1502 if ((*env)->ExceptionCheck(env)) {
1503 return 0;
1504 }
1505
1506 (*env)->CallVoidMethod(env, this,
1507 JPEGImageLoader_setInputAttributesID,
1508 cinfo->image_width,
1509 cinfo->image_height,
1510 cinfo->jpeg_color_space,
1511 cinfo->out_color_space,
1512 cinfo->num_components,
1513 profileData);
1514 if ((*env)->ExceptionCheck(env)) {
1515 return 0;
1516 }
1517 }
1518
1519 return ptr_to_jlong(data);
1520 }
1521
1522 JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_startDecompression
1523 (JNIEnv *env, jobject this, jlong ptr, jint outCS, jint dest_width, jint dest_height) {
1524 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1525 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1526 struct jpeg_source_mgr *src = cinfo->src;
1527 sun_jpeg_error_ptr jerr;
1528
1529 jfloat x_scale;
1530 jfloat y_scale;
1531 jfloat max_scale;
1532
1533 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1534 ThrowByName(env,
1535 "java/io/IOException",
1536 "Array pin failed");
1537 return JCS_UNKNOWN;
1538 }
1539
1540 cinfo = (j_decompress_ptr) data->jpegObj;
1541
1542 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1543 jerr = (sun_jpeg_error_ptr) cinfo->err;
1544
1545 if (setjmp(jerr->setjmp_buffer)) {
1546 /* If we get here, the JPEG code has signaled an error
1547 while initializing compression. */
1548 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1549 if (!(*env)->ExceptionOccurred(env)) {
1550 char buffer[JMSG_LENGTH_MAX];
1551 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1552 buffer);
1553 ThrowByName(env, "java/io/IOException", buffer);
1554 }
1555 return JCS_UNKNOWN;
1556 }
1557
1558 cinfo->out_color_space = outCS;
1559
1560 /* decide how much we want to sub-sample the incoming jpeg image.
1561 * The libjpeg docs say:
1562 *
1563 * unsigned int scale_num, scale_denom
1564 *
1565 * Scale the image by the fraction scale_num/scale_denom. Default is
1566 * 1/1, or no scaling. Currently, the only supported scaling ratios
1567 * are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary
1568 * scaling ratios but this is not likely to be implemented any time soon.)
1569 * Smaller scaling ratios permit significantly faster decoding since
1570 * fewer pixels need be processed and a simpler IDCT method can be used.
1571 */
1572
1573 cinfo->scale_num = 1;
1574
1575 x_scale = (jfloat) dest_width / (jfloat) cinfo->image_width;
1576 y_scale = (jfloat) dest_height / (jfloat) cinfo->image_height;
1577 max_scale = x_scale > y_scale ? x_scale : y_scale;
1578
1579 if (max_scale > 0.5) {
1580 cinfo->scale_denom = 1;
1581 } else if (max_scale > 0.25) {
1582 cinfo->scale_denom = 2;
1583 } else if (max_scale > 0.125) {
1584 cinfo->scale_denom = 4;
1585 } else {
1586 cinfo->scale_denom = 8;
1587 }
1588
1589 jpeg_start_decompress(cinfo);
1590
1591 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1592 (*env)->CallVoidMethod(env, this,
1593 JPEGImageLoader_setOutputAttributesID,
1594 cinfo->output_width,
1595 cinfo->output_height);
1596
1597 return cinfo->output_components;
1598 }
1599
1600 #define SAFE_TO_MULT(a, b) (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b)))
1601
1602 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_decompressIndirect
1603 (JNIEnv *env, jobject this, jlong ptr, jboolean report_progress, jbyteArray barray) {
1604 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr);
1605 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj;
1606 struct jpeg_source_mgr *src = cinfo->src;
1607 sun_jpeg_error_ptr jerr;
1608 int bytes_per_row = cinfo->output_width * cinfo->output_components;
1609 JSAMPROW scanline_ptr = (JSAMPROW) malloc(bytes_per_row * sizeof (JSAMPLE));
1610 int offset = 0;
1611
1612 if (!SAFE_TO_MULT(cinfo->output_width, cinfo->output_components) ||
1613 !SAFE_TO_MULT(bytes_per_row, cinfo->output_height) ||
1614 ((*env)->GetArrayLength(env, barray) <
1615 (bytes_per_row * cinfo->output_height)))
1616 {
1617 ThrowByName(env,
1618 "java/lang/OutOfMemoryError",
1619 "Reading JPEG Stream");
1620 return JNI_FALSE;
1621 }
1622
1623 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1624 ThrowByName(env,
1625 "java/io/IOException",
1626 "Array pin failed");
1627 return JNI_FALSE;
1628 }
1629
1630 if (scanline_ptr == NULL) {
1631 ThrowByName(env,
1632 "java/lang/OutOfMemoryError",
1633 "Reading JPEG Stream");
1634 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1635 return JNI_FALSE;
1636 }
1637
1638 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1639 jerr = (sun_jpeg_error_ptr) cinfo->err;
1640
1641 if (setjmp(jerr->setjmp_buffer)) {
1642 /* If we get here, the JPEG code has signaled an error
1643 while reading. */
1644 if (!(*env)->ExceptionOccurred(env)) {
1645 char buffer[JMSG_LENGTH_MAX];
1646 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1647 buffer);
1648 ThrowByName(env, "java/io/IOException", buffer);
1649 }
1650 if (scanline_ptr != NULL) {
1651 free(scanline_ptr);
1652 }
1653 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1654 return JNI_FALSE;
1655 }
1656
1657 while (cinfo->output_scanline < cinfo->output_height) {
1658 int num_scanlines;
1659 if (report_progress == JNI_TRUE) {
1660 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1661 (*env)->CallVoidMethod(env, this,
1662 JPEGImageLoader_updateImageProgressID,
1663 cinfo->output_scanline);
1664 if ((*env)->ExceptionCheck(env)) return JNI_FALSE;
1665 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1666 ThrowByName(env,
1667 "java/io/IOException",
1668 "Array pin failed");
1669 return JNI_FALSE;
1670 }
1671 }
1672
1673 num_scanlines = jpeg_read_scanlines(cinfo, &scanline_ptr, 1);
1674 if (num_scanlines == 1) {
1675 jboolean iscopy = FALSE;
1676 jbyte *body = (*env)->GetPrimitiveArrayCritical(env, barray, &iscopy);
1677 if (body == NULL) {
1678 fprintf(stderr, "decompressIndirect: GetPrimitiveArrayCritical returns NULL: out of memory\n");
1679 return JNI_FALSE;
1680 }
1681 memcpy(body+offset,scanline_ptr, bytes_per_row);
1682 (*env)->ReleasePrimitiveArrayCritical(env, barray, body, JNI_ABORT);
1683 offset += bytes_per_row;
1684 }
1685 }
1686
1687 if (report_progress == JNI_TRUE) {
1688 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1689 (*env)->CallVoidMethod(env, this,
1690 JPEGImageLoader_updateImageProgressID,
1691 cinfo->output_height);
1692 if ((*env)->ExceptionCheck(env)) return JNI_FALSE;
1693 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) {
1694 ThrowByName(env,
1695 "java/io/IOException",
1696 "Array pin failed");
1697 return JNI_FALSE;
1698 }
1699 }
1700
1701 jpeg_finish_decompress(cinfo);
1702 free(scanline_ptr);
1703
1704 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte);
1705 return JNI_TRUE;
1706 }