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 }