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