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