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