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