1 /*
   2  * Copyright (c) 2000, 2007, 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 /*
  27  * This file contains the code to link the Java Image I/O JPEG plug-in
  28  * to the IJG library used to read and write JPEG files.  Much of it has
  29  * been copied, updated, and annotated from the jpegdecoder.c AWT JPEG
  30  * decoder.  Where that code was unclear, the present author has either
  31  * rewritten the relevant section or commented it for the sake of future
  32  * maintainers.
  33  *
  34  * In particular, the way the AWT code handled progressive JPEGs seems
  35  * to me to be only accidentally correct and somewhat inefficient.  The
  36  * scheme used here represents the way I think it should work. (REV 11/00)
  37  */
  38 
  39 #include <stdlib.h>
  40 #include <setjmp.h>
  41 #include <assert.h>
  42 #include <string.h>
  43 
  44 
  45 /* java native interface headers */
  46 #include "jni.h"
  47 #include "jni_util.h"
  48 
  49 #include "com_sun_imageio_plugins_jpeg_JPEGImageReader.h"
  50 #include "com_sun_imageio_plugins_jpeg_JPEGImageWriter.h"
  51 
  52 /* headers from the JPEG library */
  53 #include <jpeglib.h>
  54 #include "jerror.h"
  55 
  56 #undef MAX
  57 #define MAX(a,b)        ((a) > (b) ? (a) : (b))
  58 
  59 /* Cached Java method ids */
  60 static jmethodID ImageInputStream_readID;
  61 static jmethodID ImageInputStream_skipBytesID;
  62 static jmethodID JPEGImageReader_warningOccurredID;
  63 static jmethodID JPEGImageReader_warningWithMessageID;
  64 static jmethodID JPEGImageReader_setImageDataID;
  65 static jmethodID JPEGImageReader_acceptPixelsID;
  66 static jmethodID JPEGImageReader_pushBackID;
  67 static jmethodID JPEGImageReader_passStartedID;
  68 static jmethodID JPEGImageReader_passCompleteID;
  69 static jmethodID ImageOutputStream_writeID;
  70 static jmethodID JPEGImageWriter_warningOccurredID;
  71 static jmethodID JPEGImageWriter_warningWithMessageID;
  72 static jmethodID JPEGImageWriter_writeMetadataID;
  73 static jmethodID JPEGImageWriter_grabPixelsID;
  74 static jfieldID JPEGQTable_tableID;
  75 static jfieldID JPEGHuffmanTable_lengthsID;
  76 static jfieldID JPEGHuffmanTable_valuesID;
  77 
  78 /*
  79  * Defined in jpegdecoder.c.  Copy code from there if and
  80  * when that disappears. */
  81 extern JavaVM *jvm;
  82 
  83 /*
  84  * The following sets of defines must match the warning messages in the
  85  * Java code.
  86  */
  87 
  88 /* Reader warnings */
  89 #define READ_NO_EOI          0
  90 
  91 /* Writer warnings */
  92 
  93 /* Return codes for various ops */
  94 #define OK     1
  95 #define NOT_OK 0
  96 
  97 /*
  98  * First we define two objects, one for the stream and buffer and one
  99  * for pixels.  Both contain references to Java objects and pointers to
 100  * pinned arrays.  These objects can be used for either input or
 101  * output.  Pixels can be accessed as either INT32s or bytes.
 102  * Every I/O operation will have one of each these objects, one for
 103  * the stream and the other to hold pixels, regardless of the I/O direction.
 104  */
 105 
 106 /******************** StreamBuffer definition ************************/
 107 
 108 typedef struct streamBufferStruct {
 109     jobject stream;            // ImageInputStream or ImageOutputStream
 110     jbyteArray hstreamBuffer;  // Handle to a Java buffer for the stream
 111     JOCTET *buf;               // Pinned buffer pointer */
 112     int bufferOffset;          // holds offset between unpin and the next pin
 113     int bufferLength;          // Allocated, nut just used
 114     int suspendable;           // Set to true to suspend input
 115     long remaining_skip;       // Used only on input
 116 } streamBuffer, *streamBufferPtr;
 117 
 118 /*
 119  * This buffer size was set to 64K in the old classes, 4K by default in the
 120  * IJG library, with the comment "an efficiently freadable size", and 1K
 121  * in AWT.
 122  * Unlike in the other Java designs, these objects will persist, so 64K
 123  * seems too big and 1K seems too small.  If 4K was good enough for the
 124  * IJG folks, it's good enough for me.
 125  */
 126 #define STREAMBUF_SIZE 4096
 127 
 128 /*
 129  * Used to signal that no data need be restored from an unpin to a pin.
 130  * I.e. the buffer is empty.
 131  */
 132 #define NO_DATA -1
 133 
 134 // Forward reference
 135 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb);
 136 
 137 /*
 138  * Initialize a freshly allocated StreamBuffer object.  The stream is left
 139  * null, as it will be set from Java by setSource, but the buffer object
 140  * is created and a global reference kept.  Returns OK on success, NOT_OK
 141  * if allocating the buffer or getting a global reference for it failed.
 142  */
 143 static int initStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
 144     /* Initialize a new buffer */
 145     jbyteArray hInputBuffer = (*env)->NewByteArray(env, STREAMBUF_SIZE);
 146     if (hInputBuffer == NULL) {
 147         JNU_ThrowByName( env,
 148                          "java/lang/OutOfMemoryError",
 149                          "Initializing Reader");
 150         return NOT_OK;
 151     }
 152     sb->bufferLength = (*env)->GetArrayLength(env, hInputBuffer);
 153     sb->hstreamBuffer = (*env)->NewGlobalRef(env, hInputBuffer);
 154     if (sb->hstreamBuffer == NULL) {
 155         JNU_ThrowByName( env,
 156                          "java/lang/OutOfMemoryError",
 157                          "Initializing Reader");
 158         return NOT_OK;
 159     }
 160 
 161 
 162     sb->stream = NULL;
 163 
 164     sb->buf = NULL;
 165 
 166     resetStreamBuffer(env, sb);
 167 
 168     return OK;
 169 }
 170 
 171 /*
 172  * Free all resources associated with this streamBuffer.  This must
 173  * be called to dispose the object to avoid leaking global references, as
 174  * resetStreamBuffer does not release the buffer reference.
 175  */
 176 static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
 177     resetStreamBuffer(env, sb);
 178     if (sb->hstreamBuffer != NULL) {
 179         (*env)->DeleteGlobalRef(env, sb->hstreamBuffer);
 180     }
 181 }
 182 
 183 // Forward reference
 184 static void unpinStreamBuffer(JNIEnv *env,
 185                               streamBufferPtr sb,
 186                               const JOCTET *next_byte);
 187 /*
 188  * Resets the state of a streamBuffer object that has been in use.
 189  * The global reference to the stream is released, but the reference
 190  * to the buffer is retained.  The buffer is unpinned if it was pinned.
 191  * All other state is reset.
 192  */
 193 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
 194     if (sb->stream != NULL) {
 195         (*env)->DeleteGlobalRef(env, sb->stream);
 196         sb->stream = NULL;
 197     }
 198     unpinStreamBuffer(env, sb, NULL);
 199     sb->bufferOffset = NO_DATA;
 200     sb->suspendable = FALSE;
 201     sb->remaining_skip = 0;
 202 }
 203 
 204 /*
 205  * Pins the data buffer associated with this stream.  Returns OK on
 206  * success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail.
 207  */
 208 static int pinStreamBuffer(JNIEnv *env,
 209                            streamBufferPtr sb,
 210                            const JOCTET **next_byte) {
 211     if (sb->hstreamBuffer != NULL) {
 212         assert(sb->buf == NULL);
 213         sb->buf =
 214             (JOCTET *)(*env)->GetPrimitiveArrayCritical(env,
 215                                                         sb->hstreamBuffer,
 216                                                         NULL);
 217         if (sb->buf == NULL) {
 218             return NOT_OK;
 219         }
 220         if (sb->bufferOffset != NO_DATA) {
 221             *next_byte = sb->buf + sb->bufferOffset;
 222         }
 223     }
 224     return OK;
 225 }
 226 
 227 /*
 228  * Unpins the data buffer associated with this stream.
 229  */
 230 static void unpinStreamBuffer(JNIEnv *env,
 231                               streamBufferPtr sb,
 232                               const JOCTET *next_byte) {
 233     if (sb->buf != NULL) {
 234         assert(sb->hstreamBuffer != NULL);
 235         if (next_byte == NULL) {
 236             sb->bufferOffset = NO_DATA;
 237         } else {
 238             sb->bufferOffset = next_byte - sb->buf;
 239         }
 240         (*env)->ReleasePrimitiveArrayCritical(env,
 241                                               sb->hstreamBuffer,
 242                                               sb->buf,
 243                                               0);
 244         sb->buf = NULL;
 245     }
 246 }
 247 
 248 /*
 249  * Clear out the streamBuffer.  This just invalidates the data in the buffer.
 250  */
 251 static void clearStreamBuffer(streamBufferPtr sb) {
 252     sb->bufferOffset = NO_DATA;
 253 }
 254 
 255 /*************************** end StreamBuffer definition *************/
 256 
 257 /*************************** Pixel Buffer definition ******************/
 258 
 259 typedef struct pixelBufferStruct {
 260     jobject hpixelObject;   // Usually a DataBuffer bank as a byte array
 261     unsigned int byteBufferLength;
 262     union pixptr {
 263         INT32         *ip;  // Pinned buffer pointer, as 32-bit ints
 264         unsigned char *bp;  // Pinned buffer pointer, as bytes
 265     } buf;
 266 } pixelBuffer, *pixelBufferPtr;
 267 
 268 /*
 269  * Initialize a freshly allocated PixelBuffer.  All fields are simply
 270  * set to NULL, as we have no idea what size buffer we will need.
 271  */
 272 static void initPixelBuffer(pixelBufferPtr pb) {
 273     pb->hpixelObject = NULL;
 274     pb->byteBufferLength = 0;
 275     pb->buf.ip = NULL;
 276 }
 277 
 278 /*
 279  * Set the pixelBuffer to use the given buffer, acquiring a new global
 280  * reference for it.  Returns OK on success, NOT_OK on failure.
 281  */
 282 static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) {
 283     pb->hpixelObject = (*env)->NewGlobalRef(env, obj);
 284     if (pb->hpixelObject == NULL) {
 285         JNU_ThrowByName( env,
 286                          "java/lang/OutOfMemoryError",
 287                          "Setting Pixel Buffer");
 288         return NOT_OK;
 289     }
 290     pb->byteBufferLength = (*env)->GetArrayLength(env, pb->hpixelObject);
 291     return OK;
 292 }
 293 
 294 // Forward reference
 295 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb);
 296 
 297 /*
 298  * Resets a pixel buffer to its initial state.  Unpins any pixel buffer,
 299  * releases the global reference, and resets fields to NULL.  Use this
 300  * method to dispose the object as well (there is no destroyPixelBuffer).
 301  */
 302 static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
 303     if (pb->hpixelObject != NULL) {
 304         unpinPixelBuffer(env, pb);
 305         (*env)->DeleteGlobalRef(env, pb->hpixelObject);
 306         pb->hpixelObject = NULL;
 307         pb->byteBufferLength = 0;
 308     }
 309 }
 310 
 311 /*
 312  * Pins the data buffer.  Returns OK on success, NOT_OK on failure.
 313  */
 314 static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
 315     if (pb->hpixelObject != NULL) {
 316         assert(pb->buf.ip == NULL);
 317         pb->buf.bp = (unsigned char *)(*env)->GetPrimitiveArrayCritical
 318             (env, pb->hpixelObject, NULL);
 319         if (pb->buf.bp == NULL) {
 320             return NOT_OK;
 321         }
 322     }
 323     return OK;
 324 }
 325 
 326 /*
 327  * Unpins the data buffer.
 328  */
 329 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
 330 
 331     if (pb->buf.ip != NULL) {
 332         assert(pb->hpixelObject != NULL);
 333         (*env)->ReleasePrimitiveArrayCritical(env,
 334                                               pb->hpixelObject,
 335                                               pb->buf.ip,
 336                                               0);
 337         pb->buf.ip = NULL;
 338     }
 339 }
 340 
 341 /********************* end PixelBuffer definition *******************/
 342 
 343 /********************* ImageIOData definition ***********************/
 344 
 345 #define MAX_BANDS 4
 346 #define JPEG_BAND_SIZE 8
 347 #define NUM_BAND_VALUES (1<<JPEG_BAND_SIZE)
 348 #define MAX_JPEG_BAND_VALUE (NUM_BAND_VALUES-1)
 349 #define HALF_MAX_JPEG_BAND_VALUE (MAX_JPEG_BAND_VALUE>>1)
 350 
 351 /* The number of possible incoming values to be scaled. */
 352 #define NUM_INPUT_VALUES (1 << 16)
 353 
 354 /*
 355  * The principal imageioData object, opaque to I/O direction.
 356  * Each JPEGImageReader will have associated with it a
 357  * jpeg_decompress_struct, and similarly each JPEGImageWriter will
 358  * have associated with it a jpeg_compress_struct.  In order to
 359  * ensure that these associations persist from one native call to
 360  * the next, and to provide a central locus of imageio-specific
 361  * data, we define an imageioData struct containing references
 362  * to the Java object and the IJG structs.  The functions
 363  * that manipulate these objects know whether input or output is being
 364  * performed and therefore know how to manipulate the contents correctly.
 365  * If for some reason they don't, the direction can be determined by
 366  * checking the is_decompressor field of the jpegObj.
 367  * In order for lower level code to determine a
 368  * Java object given an IJG struct, such as for dispatching warnings,
 369  * we use the client_data field of the jpeg object to store a pointer
 370  * to the imageIOData object.  Maintenance of this pointer is performed
 371  * exclusively within the following access functions.  If you
 372  * change that, you run the risk of dangling pointers.
 373  */
 374 typedef struct imageIODataStruct {
 375     j_common_ptr jpegObj;     // Either struct is fine
 376     jobject imageIOobj;       // A JPEGImageReader or a JPEGImageWriter
 377 
 378     streamBuffer streamBuf;   // Buffer for the stream
 379     pixelBuffer pixelBuf;     // Buffer for pixels
 380 
 381     jboolean abortFlag;       // Passed down from Java abort method
 382 } imageIOData, *imageIODataPtr;
 383 
 384 /*
 385  * Allocate and initialize a new imageIOData object to associate the
 386  * jpeg object and the Java object.  Returns a pointer to the new object
 387  * on success, NULL on failure.
 388  */
 389 static imageIODataPtr initImageioData (JNIEnv *env,
 390                                        j_common_ptr cinfo,
 391                                        jobject obj) {
 392     int i, j;
 393 
 394     imageIODataPtr data = (imageIODataPtr) malloc (sizeof(imageIOData));
 395     if (data == NULL) {
 396         return NULL;
 397     }
 398 
 399     data->jpegObj = cinfo;
 400     cinfo->client_data = data;
 401 
 402 #ifdef DEBUG_IIO_JPEG
 403     printf("new structures: data is %p, cinfo is %p\n", data, cinfo);
 404 #endif
 405 
 406     data->imageIOobj = (*env)->NewWeakGlobalRef(env, obj);
 407     if (data->imageIOobj == NULL) {
 408         free (data);
 409         return NULL;
 410     }
 411     if (initStreamBuffer(env, &data->streamBuf) == NOT_OK) {
 412         (*env)->DeleteWeakGlobalRef(env, data->imageIOobj);
 413         free (data);
 414         return NULL;
 415     }
 416     initPixelBuffer(&data->pixelBuf);
 417 
 418     data->abortFlag = JNI_FALSE;
 419 
 420     return data;
 421 }
 422 
 423 /*
 424  * Resets the imageIOData object to its initial state, as though
 425  * it had just been allocated and initialized.
 426  */
 427 static void resetImageIOData(JNIEnv *env, imageIODataPtr data) {
 428     resetStreamBuffer(env, &data->streamBuf);
 429     resetPixelBuffer(env, &data->pixelBuf);
 430     data->abortFlag = JNI_FALSE;
 431 }
 432 
 433 /*
 434  * Releases all resources held by this object and its subobjects,
 435  * frees the object, and returns the jpeg object.  This method must
 436  * be called to avoid leaking global references.
 437  * Note that the jpeg object is not freed or destroyed, as that is
 438  * the client's responsibility, although the client_data field is
 439  * cleared.
 440  */
 441 static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) {
 442     j_common_ptr ret = data->jpegObj;
 443     (*env)->DeleteWeakGlobalRef(env, data->imageIOobj);
 444     destroyStreamBuffer(env, &data->streamBuf);
 445     resetPixelBuffer(env, &data->pixelBuf);
 446     ret->client_data = NULL;
 447     free(data);
 448     return ret;
 449 }
 450 
 451 /******************** end ImageIOData definition ***********************/
 452 
 453 /******************** Java array pinning and unpinning *****************/
 454 
 455 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid
 456  * the need to copy array elements for the above two objects.
 457  *
 458  * MAKE SURE TO:
 459  *
 460  * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around
 461  *   callbacks to Java.
 462  * - call RELEASE_ARRAYS before returning to Java.
 463  *
 464  * Otherwise things will go horribly wrong. There may be memory leaks,
 465  * excessive pinning, or even VM crashes!
 466  *
 467  * Note that GetPrimitiveArrayCritical may fail!
 468  */
 469 
 470 /*
 471  * Release (unpin) all the arrays in use during a read.
 472  */
 473 static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte)
 474 {
 475     unpinStreamBuffer(env, &data->streamBuf, next_byte);
 476 
 477     unpinPixelBuffer(env, &data->pixelBuf);
 478 
 479 }
 480 
 481 /*
 482  * Get (pin) all the arrays in use during a read.
 483  */
 484 static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) {
 485     if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) {
 486         return NOT_OK;
 487     }
 488 
 489     if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) {
 490         RELEASE_ARRAYS(env, data, *next_byte);
 491         return NOT_OK;
 492     }
 493     return OK;
 494 }
 495 
 496 /****** end of Java array pinning and unpinning ***********/
 497 
 498 /****** Error Handling *******/
 499 
 500 /*
 501  * Set up error handling to use setjmp/longjmp.  This is the third such
 502  * setup, as both the AWT jpeg decoder and the com.sun... JPEG classes
 503  * setup thier own.  Ultimately these should be integrated, as they all
 504  * do pretty much the same thing.
 505  */
 506 
 507 struct sun_jpeg_error_mgr {
 508   struct jpeg_error_mgr pub;    /* "public" fields */
 509 
 510   jmp_buf setjmp_buffer;        /* for return to caller */
 511 };
 512 
 513 typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr;
 514 
 515 /*
 516  * Here's the routine that will replace the standard error_exit method:
 517  */
 518 
 519 METHODDEF(void)
 520 sun_jpeg_error_exit (j_common_ptr cinfo)
 521 {
 522   /* cinfo->err really points to a sun_jpeg_error_mgr struct */
 523   sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err;
 524 
 525   /* For Java, we will format the message and put it in the error we throw. */
 526 
 527   /* Return control to the setjmp point */
 528   longjmp(myerr->setjmp_buffer, 1);
 529 }
 530 
 531 /*
 532  * Error Message handling
 533  *
 534  * This overrides the output_message method to send JPEG messages
 535  *
 536  */
 537 
 538 METHODDEF(void)
 539 sun_jpeg_output_message (j_common_ptr cinfo)
 540 {
 541   char buffer[JMSG_LENGTH_MAX];
 542   jstring string;
 543   imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
 544   JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 545   jobject theObject;
 546 
 547   /* Create the message */
 548   (*cinfo->err->format_message) (cinfo, buffer);
 549 
 550   // Create a new java string from the message
 551   string = (*env)->NewStringUTF(env, buffer);
 552 
 553   theObject = data->imageIOobj;
 554 
 555   if (cinfo->is_decompressor) {
 556       (*env)->CallVoidMethod(env, theObject,
 557                              JPEGImageReader_warningWithMessageID,
 558                              string);
 559   } else {
 560       (*env)->CallVoidMethod(env, theObject,
 561                              JPEGImageWriter_warningWithMessageID,
 562                              string);
 563   }
 564 }
 565 
 566 /* End of verbatim copy from jpegdecoder.c */
 567 
 568 /*************** end of error handling *********************/
 569 
 570 /*************** Shared utility code ***********************/
 571 
 572 static void imageio_set_stream(JNIEnv *env,
 573                                j_common_ptr cinfo,
 574                                imageIODataPtr data,
 575                                jobject stream){
 576     streamBufferPtr sb;
 577     sun_jpeg_error_ptr jerr;
 578 
 579     sb = &data->streamBuf;
 580 
 581     resetStreamBuffer(env, sb);  // Removes any old stream
 582 
 583     /* Now we need a new global reference for the stream */
 584     if (stream != NULL) { // Fix for 4411955
 585         sb->stream = (*env)->NewGlobalRef(env, stream);
 586         if (sb->stream == NULL) {
 587             JNU_ThrowByName(env,
 588                             "java/lang/OutOfMemoryError",
 589                             "Setting Stream");
 590             return;
 591         }
 592     }
 593 
 594     /* And finally reset state */
 595     data->abortFlag = JNI_FALSE;
 596 
 597     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
 598     jerr = (sun_jpeg_error_ptr) cinfo->err;
 599 
 600     if (setjmp(jerr->setjmp_buffer)) {
 601         /* If we get here, the JPEG code has signaled an error
 602            while aborting. */
 603         if (!(*env)->ExceptionOccurred(env)) {
 604             char buffer[JMSG_LENGTH_MAX];
 605             (*cinfo->err->format_message) (cinfo,
 606                                            buffer);
 607             JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
 608         }
 609         return;
 610     }
 611 
 612     jpeg_abort(cinfo);  // Frees any markers, but not tables
 613 
 614 }
 615 
 616 static void imageio_reset(JNIEnv *env,
 617                           j_common_ptr cinfo,
 618                           imageIODataPtr data) {
 619     sun_jpeg_error_ptr jerr;
 620 
 621     resetImageIOData(env, data);  // Mapping to jpeg object is retained.
 622 
 623     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
 624     jerr = (sun_jpeg_error_ptr) cinfo->err;
 625 
 626     if (setjmp(jerr->setjmp_buffer)) {
 627         /* If we get here, the JPEG code has signaled an error
 628            while aborting. */
 629         if (!(*env)->ExceptionOccurred(env)) {
 630             char buffer[JMSG_LENGTH_MAX];
 631             (*cinfo->err->format_message) (cinfo, buffer);
 632             JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
 633         }
 634         return;
 635     }
 636 
 637     jpeg_abort(cinfo);  // Does not reset tables
 638 
 639 }
 640 
 641 static void imageio_dispose(j_common_ptr info) {
 642 
 643     if (info != NULL) {
 644         free(info->err);
 645         info->err = NULL;
 646         if (info->is_decompressor) {
 647             j_decompress_ptr dinfo = (j_decompress_ptr) info;
 648             free(dinfo->src);
 649             dinfo->src = NULL;
 650         } else {
 651             j_compress_ptr cinfo = (j_compress_ptr) info;
 652             free(cinfo->dest);
 653             cinfo->dest = NULL;
 654         }
 655         jpeg_destroy(info);
 656         free(info);
 657     }
 658 }
 659 
 660 static void imageio_abort(JNIEnv *env, jobject this,
 661                           imageIODataPtr data) {
 662     data->abortFlag = JNI_TRUE;
 663 }
 664 
 665 static int setQTables(JNIEnv *env,
 666                       j_common_ptr cinfo,
 667                       jobjectArray qtables,
 668                       boolean write) {
 669     jsize qlen;
 670     jobject table;
 671     jintArray qdata;
 672     jint *qdataBody;
 673     JQUANT_TBL *quant_ptr;
 674     int i, j;
 675     j_compress_ptr comp;
 676     j_decompress_ptr decomp;
 677 
 678     qlen = (*env)->GetArrayLength(env, qtables);
 679 #ifdef DEBUG_IIO_JPEG
 680     printf("in setQTables, qlen = %d, write is %d\n", qlen, write);
 681 #endif
 682     if (qlen > NUM_QUANT_TBLS) {
 683         /* Ignore extra qunterization tables. */
 684         qlen = NUM_QUANT_TBLS;
 685     }
 686     for (i = 0; i < qlen; i++) {
 687         table = (*env)->GetObjectArrayElement(env, qtables, i);
 688         qdata = (*env)->GetObjectField(env, table, JPEGQTable_tableID);
 689         qdataBody = (*env)->GetPrimitiveArrayCritical(env, qdata, NULL);
 690 
 691         if (cinfo->is_decompressor) {
 692             decomp = (j_decompress_ptr) cinfo;
 693             if (decomp->quant_tbl_ptrs[i] == NULL) {
 694                 decomp->quant_tbl_ptrs[i] =
 695                     jpeg_alloc_quant_table(cinfo);
 696             }
 697             quant_ptr = decomp->quant_tbl_ptrs[i];
 698         } else {
 699             comp = (j_compress_ptr) cinfo;
 700             if (comp->quant_tbl_ptrs[i] == NULL) {
 701                 comp->quant_tbl_ptrs[i] =
 702                     jpeg_alloc_quant_table(cinfo);
 703             }
 704             quant_ptr = comp->quant_tbl_ptrs[i];
 705         }
 706 
 707         for (j = 0; j < 64; j++) {
 708             quant_ptr->quantval[j] = (UINT16)qdataBody[j];
 709         }
 710         quant_ptr->sent_table = !write;
 711         (*env)->ReleasePrimitiveArrayCritical(env,
 712                                               qdata,
 713                                               qdataBody,
 714                                               0);
 715     }
 716     return qlen;
 717 }
 718 
 719 static void setHuffTable(JNIEnv *env,
 720                          JHUFF_TBL *huff_ptr,
 721                          jobject table) {
 722 
 723     jshortArray huffLens;
 724     jshortArray huffValues;
 725     jshort *hlensBody, *hvalsBody;
 726     jsize hlensLen, hvalsLen;
 727     int i;
 728 
 729     // lengths
 730     huffLens = (*env)->GetObjectField(env,
 731                                       table,
 732                                       JPEGHuffmanTable_lengthsID);
 733     hlensLen = (*env)->GetArrayLength(env, huffLens);
 734     hlensBody = (*env)->GetShortArrayElements(env,
 735                                               huffLens,
 736                                               NULL);
 737     if (hlensLen > 16) {
 738         /* Ignore extra elements of bits array. Only 16 elements can be
 739            stored. 0-th element is not used. (see jpeglib.h, line 107)  */
 740         hlensLen = 16;
 741     }
 742     for (i = 1; i <= hlensLen; i++) {
 743         huff_ptr->bits[i] = (UINT8)hlensBody[i-1];
 744     }
 745     (*env)->ReleaseShortArrayElements(env,
 746                                       huffLens,
 747                                       hlensBody,
 748                                       JNI_ABORT);
 749     // values
 750     huffValues = (*env)->GetObjectField(env,
 751                                         table,
 752                                         JPEGHuffmanTable_valuesID);
 753     hvalsLen = (*env)->GetArrayLength(env, huffValues);
 754     hvalsBody = (*env)->GetShortArrayElements(env,
 755                                               huffValues,
 756                                               NULL);
 757 
 758     if (hvalsLen > 256) {
 759         /* Ignore extra elements of hufval array. Only 256 elements
 760            can be stored. (see jpeglib.h, line 109)                  */
 761         hlensLen = 256;
 762     }
 763     for (i = 0; i < hvalsLen; i++) {
 764         huff_ptr->huffval[i] = (UINT8)hvalsBody[i];
 765     }
 766     (*env)->ReleaseShortArrayElements(env,
 767                                       huffValues,
 768                                       hvalsBody,
 769                                       JNI_ABORT);
 770 }
 771 
 772 static int setHTables(JNIEnv *env,
 773                       j_common_ptr cinfo,
 774                       jobjectArray DCHuffmanTables,
 775                       jobjectArray ACHuffmanTables,
 776                       boolean write) {
 777     int i;
 778     jobject table;
 779     JHUFF_TBL *huff_ptr;
 780     j_compress_ptr comp;
 781     j_decompress_ptr decomp;
 782     jsize hlen = (*env)->GetArrayLength(env, DCHuffmanTables);
 783 
 784     if (hlen > NUM_HUFF_TBLS) {
 785         /* Ignore extra DC huffman tables. */
 786         hlen = NUM_HUFF_TBLS;
 787     }
 788     for (i = 0; i < hlen; i++) {
 789         if (cinfo->is_decompressor) {
 790             decomp = (j_decompress_ptr) cinfo;
 791             if (decomp->dc_huff_tbl_ptrs[i] == NULL) {
 792                 decomp->dc_huff_tbl_ptrs[i] =
 793                     jpeg_alloc_huff_table(cinfo);
 794             }
 795             huff_ptr = decomp->dc_huff_tbl_ptrs[i];
 796         } else {
 797             comp = (j_compress_ptr) cinfo;
 798             if (comp->dc_huff_tbl_ptrs[i] == NULL) {
 799                 comp->dc_huff_tbl_ptrs[i] =
 800                     jpeg_alloc_huff_table(cinfo);
 801             }
 802             huff_ptr = comp->dc_huff_tbl_ptrs[i];
 803         }
 804         table = (*env)->GetObjectArrayElement(env, DCHuffmanTables, i);
 805         setHuffTable(env, huff_ptr, table);
 806         huff_ptr->sent_table = !write;
 807     }
 808     hlen = (*env)->GetArrayLength(env, ACHuffmanTables);
 809     if (hlen > NUM_HUFF_TBLS) {
 810         /* Ignore extra AC huffman tables. */
 811         hlen = NUM_HUFF_TBLS;
 812     }
 813     for (i = 0; i < hlen; i++) {
 814         if (cinfo->is_decompressor) {
 815             decomp = (j_decompress_ptr) cinfo;
 816             if (decomp->ac_huff_tbl_ptrs[i] == NULL) {
 817                 decomp->ac_huff_tbl_ptrs[i] =
 818                     jpeg_alloc_huff_table(cinfo);
 819             }
 820             huff_ptr = decomp->ac_huff_tbl_ptrs[i];
 821         } else {
 822             comp = (j_compress_ptr) cinfo;
 823             if (comp->ac_huff_tbl_ptrs[i] == NULL) {
 824                 comp->ac_huff_tbl_ptrs[i] =
 825                     jpeg_alloc_huff_table(cinfo);
 826             }
 827             huff_ptr = comp->ac_huff_tbl_ptrs[i];
 828         }
 829         table = (*env)->GetObjectArrayElement(env, ACHuffmanTables, i);
 830         setHuffTable(env, huff_ptr, table);
 831         huff_ptr->sent_table = !write;
 832     }
 833     return hlen;
 834 }
 835 
 836 
 837 /*************** end of shared utility code ****************/
 838 
 839 /********************** Reader Support **************************/
 840 
 841 /********************** Source Management ***********************/
 842 
 843 /*
 844  * INPUT HANDLING:
 845  *
 846  * The JPEG library's input management is defined by the jpeg_source_mgr
 847  * structure which contains two fields to convey the information in the
 848  * buffer and 5 methods which perform all buffer management.  The library
 849  * defines a standard input manager that uses stdio for obtaining compressed
 850  * jpeg data, but here we need to use Java to get our data.
 851  *
 852  * We use the library jpeg_source_mgr but our own routines that access
 853  * imageio-specific information in the imageIOData structure.
 854  */
 855 
 856 /*
 857  * Initialize source.  This is called by jpeg_read_header() before any
 858  * data is actually read.  Unlike init_destination(), it may leave
 859  * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
 860  * will occur immediately).
 861  */
 862 
 863 GLOBAL(void)
 864 imageio_init_source(j_decompress_ptr cinfo)
 865 {
 866     struct jpeg_source_mgr *src = cinfo->src;
 867     src->next_input_byte = NULL;
 868     src->bytes_in_buffer = 0;
 869 }
 870 
 871 /*
 872  * This is called whenever bytes_in_buffer has reached zero and more
 873  * data is wanted.  In typical applications, it should read fresh data
 874  * into the buffer (ignoring the current state of next_input_byte and
 875  * bytes_in_buffer), reset the pointer & count to the start of the
 876  * buffer, and return TRUE indicating that the buffer has been reloaded.
 877  * It is not necessary to fill the buffer entirely, only to obtain at
 878  * least one more byte.  bytes_in_buffer MUST be set to a positive value
 879  * if TRUE is returned.  A FALSE return should only be used when I/O
 880  * suspension is desired (this mode is discussed in the next section).
 881  */
 882 /*
 883  * Note that with I/O suspension turned on, this procedure should not
 884  * do any work since the JPEG library has a very simple backtracking
 885  * mechanism which relies on the fact that the buffer will be filled
 886  * only when it has backed out to the top application level.  When
 887  * suspendable is turned on, imageio_fill_suspended_buffer will
 888  * do the actual work of filling the buffer.
 889  */
 890 
 891 GLOBAL(boolean)
 892 imageio_fill_input_buffer(j_decompress_ptr cinfo)
 893 {
 894     struct jpeg_source_mgr *src = cinfo->src;
 895     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
 896     streamBufferPtr sb = &data->streamBuf;
 897     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 898     int ret;
 899 
 900     /* This is where input suspends */
 901     if (sb->suspendable) {
 902         return FALSE;
 903     }
 904 
 905 #ifdef DEBUG_IIO_JPEG
 906     printf("Filling input buffer, remaining skip is %ld, ",
 907            sb->remaining_skip);
 908     printf("Buffer length is %d\n", sb->bufferLength);
 909 #endif
 910 
 911     /*
 912      * Definitively skips.  Could be left over if we tried to skip
 913      * more than a buffer's worth but suspended when getting the next
 914      * buffer.  Now we aren't suspended, so we can catch up.
 915      */
 916     if (sb->remaining_skip) {
 917         src->skip_input_data(cinfo, 0);
 918     }
 919 
 920     /*
 921      * Now fill a complete buffer, or as much of one as the stream
 922      * will give us if we are near the end.
 923      */
 924     RELEASE_ARRAYS(env, data, src->next_input_byte);
 925     ret = (*env)->CallIntMethod(env,
 926                                 sb->stream,
 927                                 ImageInputStream_readID,
 928                                 sb->hstreamBuffer, 0,
 929                                 sb->bufferLength);
 930     if ((*env)->ExceptionOccurred(env)
 931         || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
 932             cinfo->err->error_exit((j_common_ptr) cinfo);
 933     }
 934 
 935 #ifdef DEBUG_IIO_JPEG
 936       printf("Buffer filled. ret = %d\n", ret);
 937 #endif
 938     /*
 939      * If we have reached the end of the stream, then the EOI marker
 940      * is missing.  We accept such streams but generate a warning.
 941      * The image is likely to be corrupted, though everything through
 942      * the end of the last complete MCU should be usable.
 943      */
 944     if (ret <= 0) {
 945         jobject reader = data->imageIOobj;
 946 #ifdef DEBUG_IIO_JPEG
 947       printf("YO! Early EOI! ret = %d\n", ret);
 948 #endif
 949         RELEASE_ARRAYS(env, data, src->next_input_byte);
 950         (*env)->CallVoidMethod(env, reader,
 951                                JPEGImageReader_warningOccurredID,
 952                                READ_NO_EOI);
 953         if ((*env)->ExceptionOccurred(env)
 954             || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
 955             cinfo->err->error_exit((j_common_ptr) cinfo);
 956         }
 957 
 958         sb->buf[0] = (JOCTET) 0xFF;
 959         sb->buf[1] = (JOCTET) JPEG_EOI;
 960         ret = 2;
 961     }
 962 
 963     src->next_input_byte = sb->buf;
 964     src->bytes_in_buffer = ret;
 965 
 966     return TRUE;
 967 }
 968 
 969 /*
 970  * With I/O suspension turned on, the JPEG library requires that all
 971  * buffer filling be done at the top application level, using this
 972  * function.  Due to the way that backtracking works, this procedure
 973  * saves all of the data that was left in the buffer when suspension
 974  * occured and read new data only at the end.
 975  */
 976 
 977 GLOBAL(void)
 978 imageio_fill_suspended_buffer(j_decompress_ptr cinfo)
 979 {
 980     struct jpeg_source_mgr *src = cinfo->src;
 981     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
 982     streamBufferPtr sb = &data->streamBuf;
 983     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 984     jint ret;
 985     int offset, buflen;
 986 
 987     /*
 988      * The original (jpegdecoder.c) had code here that called
 989      * InputStream.available and just returned if the number of bytes
 990      * available was less than any remaining skip.  Presumably this was
 991      * to avoid blocking, although the benefit was unclear, as no more
 992      * decompression can take place until more data is available, so
 993      * the code would block on input a little further along anyway.
 994      * ImageInputStreams don't have an available method, so we'll just
 995      * block in the skip if we have to.
 996      */
 997 
 998     if (sb->remaining_skip) {
 999         src->skip_input_data(cinfo, 0);
1000     }
1001 
1002     /* Save the data currently in the buffer */
1003     offset = src->bytes_in_buffer;
1004     if (src->next_input_byte > sb->buf) {
1005         memcpy(sb->buf, src->next_input_byte, offset);
1006     }
1007     RELEASE_ARRAYS(env, data, src->next_input_byte);
1008     buflen = sb->bufferLength - offset;
1009     if (buflen <= 0) {
1010         if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
1011             cinfo->err->error_exit((j_common_ptr) cinfo);
1012         }
1013         return;
1014     }
1015 
1016     ret = (*env)->CallIntMethod(env, sb->stream,
1017                                 ImageInputStream_readID,
1018                                 sb->hstreamBuffer,
1019                                 offset, buflen);
1020     if ((*env)->ExceptionOccurred(env)
1021         || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1022         cinfo->err->error_exit((j_common_ptr) cinfo);
1023     }
1024     /*
1025      * If we have reached the end of the stream, then the EOI marker
1026      * is missing.  We accept such streams but generate a warning.
1027      * The image is likely to be corrupted, though everything through
1028      * the end of the last complete MCU should be usable.
1029      */
1030     if (ret <= 0) {
1031         jobject reader = data->imageIOobj;
1032         RELEASE_ARRAYS(env, data, src->next_input_byte);
1033         (*env)->CallVoidMethod(env, reader,
1034                                JPEGImageReader_warningOccurredID,
1035                                READ_NO_EOI);
1036         if ((*env)->ExceptionOccurred(env)
1037             || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1038             cinfo->err->error_exit((j_common_ptr) cinfo);
1039         }
1040 
1041         sb->buf[offset] = (JOCTET) 0xFF;
1042         sb->buf[offset + 1] = (JOCTET) JPEG_EOI;
1043         ret = 2;
1044     }
1045 
1046     src->next_input_byte = sb->buf;
1047     src->bytes_in_buffer = ret + offset;
1048 
1049     return;
1050 }
1051 
1052 /*
1053  * Skip num_bytes worth of data.  The buffer pointer and count are
1054  * advanced over num_bytes input bytes, using the input stream
1055  * skipBytes method if the skip is greater than the number of bytes
1056  * in the buffer.  This is used to skip over a potentially large amount of
1057  * uninteresting data (such as an APPn marker).  bytes_in_buffer will be
1058  * zero on return if the skip is larger than the current contents of the
1059  * buffer.
1060  *
1061  * A negative skip count is treated as a no-op.  A zero skip count
1062  * skips any remaining skip from a previous skip while suspended.
1063  *
1064  * Note that with I/O suspension turned on, this procedure does not
1065  * call skipBytes since the JPEG library has a very simple backtracking
1066  * mechanism which relies on the fact that the application level has
1067  * exclusive control over actual I/O.
1068  */
1069 
1070 GLOBAL(void)
1071 imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
1072 {
1073     struct jpeg_source_mgr *src = cinfo->src;
1074     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
1075     streamBufferPtr sb = &data->streamBuf;
1076     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1077     jlong ret;
1078     jobject reader;
1079 
1080     if (num_bytes < 0) {
1081         return;
1082     }
1083     num_bytes += sb->remaining_skip;
1084     sb->remaining_skip = 0;
1085 
1086     /* First the easy case where we are skipping <= the current contents. */
1087     ret = src->bytes_in_buffer;
1088     if (ret >= num_bytes) {
1089         src->next_input_byte += num_bytes;
1090         src->bytes_in_buffer -= num_bytes;
1091         return;
1092     }
1093 
1094     /*
1095      * We are skipping more than is in the buffer.  We empty the buffer and,
1096      * if we aren't suspended, call the Java skipBytes method.  We always
1097      * leave the buffer empty, to be filled by either fill method above.
1098      */
1099     src->bytes_in_buffer = 0;
1100     src->next_input_byte = sb->buf;
1101 
1102     num_bytes -= (long)ret;
1103     if (sb->suspendable) {
1104         sb->remaining_skip = num_bytes;
1105         return;
1106     }
1107 
1108     RELEASE_ARRAYS(env, data, src->next_input_byte);
1109     ret = (*env)->CallLongMethod(env,
1110                                  sb->stream,
1111                                  ImageInputStream_skipBytesID,
1112                                  (jlong) num_bytes);
1113     if ((*env)->ExceptionOccurred(env)
1114         || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1115             cinfo->err->error_exit((j_common_ptr) cinfo);
1116     }
1117 
1118     /*
1119      * If we have reached the end of the stream, then the EOI marker
1120      * is missing.  We accept such streams but generate a warning.
1121      * The image is likely to be corrupted, though everything through
1122      * the end of the last complete MCU should be usable.
1123      */
1124     if (ret <= 0) {
1125         reader = data->imageIOobj;
1126         RELEASE_ARRAYS(env, data, src->next_input_byte);
1127         (*env)->CallVoidMethod(env,
1128                                reader,
1129                                JPEGImageReader_warningOccurredID,
1130                                READ_NO_EOI);
1131 
1132         if ((*env)->ExceptionOccurred(env)
1133             || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1134                 cinfo->err->error_exit((j_common_ptr) cinfo);
1135         }
1136         sb->buf[0] = (JOCTET) 0xFF;
1137         sb->buf[1] = (JOCTET) JPEG_EOI;
1138         src->bytes_in_buffer = 2;
1139         src->next_input_byte = sb->buf;
1140     }
1141 }
1142 
1143 /*
1144  * Terminate source --- called by jpeg_finish_decompress() after all
1145  * data for an image has been read.  In our case pushes back any
1146  * remaining data, as it will be for another image and must be available
1147  * for java to find out that there is another image.  Also called if
1148  * reseting state after reading a tables-only image.
1149  */
1150 
1151 GLOBAL(void)
1152 imageio_term_source(j_decompress_ptr cinfo)
1153 {
1154     // To pushback, just seek back by src->bytes_in_buffer
1155     struct jpeg_source_mgr *src = cinfo->src;
1156     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
1157     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1158     jobject reader = data->imageIOobj;
1159     if (src->bytes_in_buffer > 0) {
1160          RELEASE_ARRAYS(env, data, src->next_input_byte);
1161          (*env)->CallVoidMethod(env,
1162                                 reader,
1163                                 JPEGImageReader_pushBackID,
1164                                 src->bytes_in_buffer);
1165 
1166          if ((*env)->ExceptionOccurred(env)
1167              || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
1168              cinfo->err->error_exit((j_common_ptr) cinfo);
1169          }
1170          src->bytes_in_buffer = 0;
1171          //src->next_input_byte = sb->buf;
1172     }
1173 }
1174 
1175 /********************* end of source manager ******************/
1176 
1177 /********************* ICC profile support ********************/
1178 /*
1179  * The following routines are modified versions of the ICC
1180  * profile support routines available from the IJG website.
1181  * The originals were written by Todd Newman
1182  * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for
1183  * the IJG.  They are further modified to fit in the context
1184  * of the imageio JPEG plug-in.
1185  */
1186 
1187 /*
1188  * Since an ICC profile can be larger than the maximum size of a JPEG marker
1189  * (64K), we need provisions to split it into multiple markers.  The format
1190  * defined by the ICC specifies one or more APP2 markers containing the
1191  * following data:
1192  *      Identifying string      ASCII "ICC_PROFILE\0"  (12 bytes)
1193  *      Marker sequence number  1 for first APP2, 2 for next, etc (1 byte)
1194  *      Number of markers       Total number of APP2's used (1 byte)
1195  *      Profile data            (remainder of APP2 data)
1196  * Decoders should use the marker sequence numbers to reassemble the profile,
1197  * rather than assuming that the APP2 markers appear in the correct sequence.
1198  */
1199 
1200 #define ICC_MARKER  (JPEG_APP0 + 2)     /* JPEG marker code for ICC */
1201 #define ICC_OVERHEAD_LEN  14            /* size of non-profile data in APP2 */
1202 #define MAX_BYTES_IN_MARKER  65533      /* maximum data len of a JPEG marker */
1203 #define MAX_DATA_BYTES_IN_ICC_MARKER  (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
1204 
1205 
1206 /*
1207  * Handy subroutine to test whether a saved marker is an ICC profile marker.
1208  */
1209 
1210 static boolean
1211 marker_is_icc (jpeg_saved_marker_ptr marker)
1212 {
1213   return
1214     marker->marker == ICC_MARKER &&
1215     marker->data_length >= ICC_OVERHEAD_LEN &&
1216     /* verify the identifying string */
1217     GETJOCTET(marker->data[0]) == 0x49 &&
1218     GETJOCTET(marker->data[1]) == 0x43 &&
1219     GETJOCTET(marker->data[2]) == 0x43 &&
1220     GETJOCTET(marker->data[3]) == 0x5F &&
1221     GETJOCTET(marker->data[4]) == 0x50 &&
1222     GETJOCTET(marker->data[5]) == 0x52 &&
1223     GETJOCTET(marker->data[6]) == 0x4F &&
1224     GETJOCTET(marker->data[7]) == 0x46 &&
1225     GETJOCTET(marker->data[8]) == 0x49 &&
1226     GETJOCTET(marker->data[9]) == 0x4C &&
1227     GETJOCTET(marker->data[10]) == 0x45 &&
1228     GETJOCTET(marker->data[11]) == 0x0;
1229 }
1230 
1231 /*
1232  * See if there was an ICC profile in the JPEG file being read;
1233  * if so, reassemble and return the profile data as a new Java byte array.
1234  * If there was no ICC profile, return NULL.
1235  *
1236  * If the file contains invalid ICC APP2 markers, we throw an IIOException
1237  * with an appropriate message.
1238  */
1239 
1240 jbyteArray
1241 read_icc_profile (JNIEnv *env, j_decompress_ptr cinfo)
1242 {
1243     jpeg_saved_marker_ptr marker;
1244     int num_markers = 0;
1245     int num_found_markers = 0;
1246     int seq_no;
1247     JOCTET *icc_data;
1248     JOCTET *dst_ptr;
1249     unsigned int total_length;
1250 #define MAX_SEQ_NO  255         // sufficient since marker numbers are bytes
1251     jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1];
1252     int first;         // index of the first marker in the icc_markers array
1253     int last;          // index of the last marker in the icc_markers array
1254     jbyteArray data = NULL;
1255 
1256     /* This first pass over the saved markers discovers whether there are
1257      * any ICC markers and verifies the consistency of the marker numbering.
1258      */
1259 
1260     for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++)
1261         icc_markers[seq_no] = NULL;
1262 
1263 
1264     for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
1265         if (marker_is_icc(marker)) {
1266             if (num_markers == 0)
1267                 num_markers = GETJOCTET(marker->data[13]);
1268             else if (num_markers != GETJOCTET(marker->data[13])) {
1269                 JNU_ThrowByName(env, "javax/imageio/IIOException",
1270                      "Invalid icc profile: inconsistent num_markers fields");
1271                 return NULL;
1272             }
1273             seq_no = GETJOCTET(marker->data[12]);
1274 
1275             /* Some third-party tools produce images with profile chunk
1276              * numeration started from zero. It is inconsistent with ICC
1277              * spec, but seems to be recognized by majority of image
1278              * processing tools, so we should be more tolerant to this
1279              * departure from the spec.
1280              */
1281             if (seq_no < 0 || seq_no > num_markers) {
1282                 JNU_ThrowByName(env, "javax/imageio/IIOException",
1283                      "Invalid icc profile: bad sequence number");
1284                 return NULL;
1285             }
1286             if (icc_markers[seq_no] != NULL) {
1287                 JNU_ThrowByName(env, "javax/imageio/IIOException",
1288                      "Invalid icc profile: duplicate sequence numbers");
1289                 return NULL;
1290             }
1291             icc_markers[seq_no] = marker;
1292             num_found_markers ++;
1293         }
1294     }
1295 
1296     if (num_markers == 0)
1297         return NULL;  // There is no profile
1298 
1299     if (num_markers != num_found_markers) {
1300         JNU_ThrowByName(env, "javax/imageio/IIOException",
1301                         "Invalid icc profile: invalid number of icc markers");
1302         return NULL;
1303     }
1304 
1305     first = icc_markers[0] ? 0 : 1;
1306     last = num_found_markers + first;
1307 
1308     /* Check for missing markers, count total space needed.
1309      */
1310     total_length = 0;
1311     for (seq_no = first; seq_no < last; seq_no++) {
1312         unsigned int length;
1313         if (icc_markers[seq_no] == NULL) {
1314             JNU_ThrowByName(env, "javax/imageio/IIOException",
1315                  "Invalid icc profile: missing sequence number");
1316             return NULL;
1317         }
1318         /* check the data length correctness */
1319         length = icc_markers[seq_no]->data_length;
1320         if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) {
1321             JNU_ThrowByName(env, "javax/imageio/IIOException",
1322                  "Invalid icc profile: invalid data length");
1323             return NULL;
1324         }
1325         total_length += (length - ICC_OVERHEAD_LEN);
1326     }
1327 
1328     if (total_length <= 0) {
1329         JNU_ThrowByName(env, "javax/imageio/IIOException",
1330               "Invalid icc profile: found only empty markers");
1331         return NULL;
1332     }
1333 
1334     /* Allocate a Java byte array for assembled data */
1335 
1336     data = (*env)->NewByteArray(env, total_length);
1337     if (data == NULL) {
1338         JNU_ThrowByName(env,
1339                         "java/lang/OutOfMemoryError",
1340                         "Reading ICC profile");
1341         return NULL;
1342     }
1343 
1344     icc_data = (JOCTET *)(*env)->GetPrimitiveArrayCritical(env,
1345                                                            data,
1346                                                            NULL);
1347     if (icc_data == NULL) {
1348         JNU_ThrowByName(env, "javax/imageio/IIOException",
1349                         "Unable to pin icc profile data array");
1350         return NULL;
1351     }
1352 
1353     /* and fill it in */
1354     dst_ptr = icc_data;
1355     for (seq_no = first; seq_no < last; seq_no++) {
1356         JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN;
1357         unsigned int length =
1358             icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN;
1359 
1360         memcpy(dst_ptr, src_ptr, length);
1361         dst_ptr += length;
1362     }
1363 
1364     /* finally, unpin the array */
1365     (*env)->ReleasePrimitiveArrayCritical(env,
1366                                           data,
1367                                           icc_data,
1368                                           0);
1369 
1370 
1371     return data;
1372 }
1373 
1374 /********************* end of ICC profile support *************/
1375 
1376 /********************* Reader JNI calls ***********************/
1377 
1378 JNIEXPORT void JNICALL
1379 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initReaderIDs
1380     (JNIEnv *env,
1381      jclass cls,
1382      jclass ImageInputStreamClass,
1383      jclass qTableClass,
1384      jclass huffClass) {
1385 
1386     ImageInputStream_readID = (*env)->GetMethodID(env,
1387                                                   ImageInputStreamClass,
1388                                                   "read",
1389                                                   "([BII)I");
1390     ImageInputStream_skipBytesID = (*env)->GetMethodID(env,
1391                                                        ImageInputStreamClass,
1392                                                        "skipBytes",
1393                                                        "(J)J");
1394     JPEGImageReader_warningOccurredID = (*env)->GetMethodID(env,
1395                                                             cls,
1396                                                             "warningOccurred",
1397                                                             "(I)V");
1398     JPEGImageReader_warningWithMessageID =
1399         (*env)->GetMethodID(env,
1400                             cls,
1401                             "warningWithMessage",
1402                             "(Ljava/lang/String;)V");
1403     JPEGImageReader_setImageDataID = (*env)->GetMethodID(env,
1404                                                          cls,
1405                                                          "setImageData",
1406                                                          "(IIIII[B)V");
1407     JPEGImageReader_acceptPixelsID = (*env)->GetMethodID(env,
1408                                                          cls,
1409                                                          "acceptPixels",
1410                                                          "(IZ)V");
1411     JPEGImageReader_passStartedID = (*env)->GetMethodID(env,
1412                                                         cls,
1413                                                         "passStarted",
1414                                                         "(I)V");
1415     JPEGImageReader_passCompleteID = (*env)->GetMethodID(env,
1416                                                          cls,
1417                                                          "passComplete",
1418                                                          "()V");
1419     JPEGImageReader_pushBackID = (*env)->GetMethodID(env,
1420                                                      cls,
1421                                                      "pushBack",
1422                                                      "(I)V");
1423     JPEGQTable_tableID = (*env)->GetFieldID(env,
1424                                             qTableClass,
1425                                             "qTable",
1426                                             "[I");
1427 
1428     JPEGHuffmanTable_lengthsID = (*env)->GetFieldID(env,
1429                                                     huffClass,
1430                                                     "lengths",
1431                                                     "[S");
1432 
1433     JPEGHuffmanTable_valuesID = (*env)->GetFieldID(env,
1434                                                     huffClass,
1435                                                     "values",
1436                                                     "[S");
1437 }
1438 
1439 JNIEXPORT jlong JNICALL
1440 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader
1441     (JNIEnv *env,
1442      jobject this) {
1443 
1444     imageIODataPtr ret;
1445     struct sun_jpeg_error_mgr *jerr;
1446 
1447     /* This struct contains the JPEG decompression parameters and pointers to
1448      * working space (which is allocated as needed by the JPEG library).
1449      */
1450     struct jpeg_decompress_struct *cinfo =
1451         malloc(sizeof(struct jpeg_decompress_struct));
1452     if (cinfo == NULL) {
1453         JNU_ThrowByName( env,
1454                          "java/lang/OutOfMemoryError",
1455                          "Initializing Reader");
1456         return 0;
1457     }
1458 
1459     /* We use our private extension JPEG error handler.
1460      */
1461     jerr = malloc (sizeof(struct sun_jpeg_error_mgr));
1462     if (jerr == NULL) {
1463         JNU_ThrowByName( env,
1464                          "java/lang/OutOfMemoryError",
1465                          "Initializing Reader");
1466         free(cinfo);
1467         return 0;
1468     }
1469 
1470     /* We set up the normal JPEG error routines, then override error_exit. */
1471     cinfo->err = jpeg_std_error(&(jerr->pub));
1472     jerr->pub.error_exit = sun_jpeg_error_exit;
1473     /* We need to setup our own print routines */
1474     jerr->pub.output_message = sun_jpeg_output_message;
1475     /* Now we can setjmp before every call to the library */
1476 
1477     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1478     if (setjmp(jerr->setjmp_buffer)) {
1479         /* If we get here, the JPEG code has signaled an error. */
1480         char buffer[JMSG_LENGTH_MAX];
1481         (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1482                                       buffer);
1483         JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
1484         return 0;
1485     }
1486 
1487     /* Perform library initialization */
1488     jpeg_create_decompress(cinfo);
1489 
1490     // Set up to keep any APP2 markers, as these might contain ICC profile
1491     // data
1492     jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
1493 
1494     /*
1495      * Now set up our source.
1496      */
1497     cinfo->src =
1498         (struct jpeg_source_mgr *) malloc (sizeof(struct jpeg_source_mgr));
1499     if (cinfo->src == NULL) {
1500         JNU_ThrowByName(env,
1501                         "java/lang/OutOfMemoryError",
1502                         "Initializing Reader");
1503         imageio_dispose((j_common_ptr)cinfo);
1504         return 0;
1505     }
1506     cinfo->src->bytes_in_buffer = 0;
1507     cinfo->src->next_input_byte = NULL;
1508     cinfo->src->init_source = imageio_init_source;
1509     cinfo->src->fill_input_buffer = imageio_fill_input_buffer;
1510     cinfo->src->skip_input_data = imageio_skip_input_data;
1511     cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default
1512     cinfo->src->term_source = imageio_term_source;
1513 
1514     /* set up the association to persist for future calls */
1515     ret = initImageioData(env, (j_common_ptr) cinfo, this);
1516     if (ret == NULL) {
1517         JNU_ThrowByName( env,
1518                          "java/lang/OutOfMemoryError",
1519                          "Initializing Reader");
1520         imageio_dispose((j_common_ptr)cinfo);
1521         return 0;
1522     }
1523     return (jlong) ret;
1524 }
1525 
1526 /*
1527  * When we set a source from Java, we set up the stream in the streamBuf
1528  * object.  If there was an old one, it is released first.
1529  */
1530 
1531 JNIEXPORT void JNICALL
1532 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource
1533     (JNIEnv *env,
1534      jobject this,
1535      jlong ptr,
1536      jobject source) {
1537 
1538     imageIODataPtr data = (imageIODataPtr) ptr;
1539     j_common_ptr cinfo;
1540 
1541     if (data == NULL) {
1542         JNU_ThrowByName(env,
1543                         "java/lang/IllegalStateException",
1544                         "Attempting to use reader after dispose()");
1545         return;
1546     }
1547 
1548     cinfo = data->jpegObj;
1549 
1550     imageio_set_stream(env, cinfo, data, source);
1551 
1552     imageio_init_source((j_decompress_ptr) cinfo);
1553 }
1554 
1555 #define JPEG_APP1  (JPEG_APP0 + 1)  /* EXIF APP1 marker code  */
1556 
1557 /*
1558  * For EXIF images, the APP1 will appear immediately after the SOI,
1559  * so it's safe to only look at the first marker in the list.
1560  * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58)
1561  */
1562 #define IS_EXIF(c) \
1563     (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1))
1564 
1565 JNIEXPORT jboolean JNICALL
1566 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
1567     (JNIEnv *env,
1568      jobject this,
1569      jlong ptr,
1570      jboolean clearFirst,
1571      jboolean reset) {
1572 
1573     int ret;
1574     int h_samp0, h_samp1, h_samp2;
1575     int v_samp0, v_samp1, v_samp2;
1576     jboolean retval = JNI_FALSE;
1577     imageIODataPtr data = (imageIODataPtr) ptr;
1578     j_decompress_ptr cinfo;
1579     struct jpeg_source_mgr *src;
1580     sun_jpeg_error_ptr jerr;
1581     jbyteArray profileData = NULL;
1582 
1583     if (data == NULL) {
1584         JNU_ThrowByName(env,
1585                         "java/lang/IllegalStateException",
1586                         "Attempting to use reader after dispose()");
1587         return JNI_FALSE;
1588     }
1589 
1590     cinfo = (j_decompress_ptr) data->jpegObj;
1591     src = cinfo->src;
1592 
1593     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1594     jerr = (sun_jpeg_error_ptr) cinfo->err;
1595 
1596     if (setjmp(jerr->setjmp_buffer)) {
1597         /* If we get here, the JPEG code has signaled an error
1598            while reading the header. */
1599         RELEASE_ARRAYS(env, data, src->next_input_byte);
1600         if (!(*env)->ExceptionOccurred(env)) {
1601             char buffer[JMSG_LENGTH_MAX];
1602             (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1603                                           buffer);
1604             JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
1605         }
1606         return retval;
1607     }
1608 
1609 #ifdef DEBUG_IIO_JPEG
1610     printf("In readImageHeader, data is %p cinfo is %p\n", data, cinfo);
1611     printf("clearFirst is %d\n", clearFirst);
1612 #endif
1613 
1614     if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1615         JNU_ThrowByName(env,
1616                         "javax/imageio/IIOException",
1617                         "Array pin failed");
1618         return retval;
1619     }
1620 
1621     /*
1622      * Now clear the input buffer if the Java code has done a seek
1623      * on the stream since the last call, invalidating any buffer contents.
1624      */
1625     if (clearFirst) {
1626         clearStreamBuffer(&data->streamBuf);
1627         src->next_input_byte = NULL;
1628         src->bytes_in_buffer = 0;
1629     }
1630 
1631     ret = jpeg_read_header(cinfo, FALSE);
1632 
1633     if (ret == JPEG_HEADER_TABLES_ONLY) {
1634         retval = JNI_TRUE;
1635         imageio_term_source(cinfo);  // Pushback remaining buffer contents
1636 #ifdef DEBUG_IIO_JPEG
1637         printf("just read tables-only image; q table 0 at %p\n",
1638                cinfo->quant_tbl_ptrs[0]);
1639 #endif
1640         RELEASE_ARRAYS(env, data, src->next_input_byte);
1641     } else {
1642         /*
1643          * Now adjust the jpeg_color_space variable, which was set in
1644          * default_decompress_parms, to reflect our differences from IJG
1645          */
1646 
1647         switch (cinfo->jpeg_color_space) {
1648         default :
1649           break;
1650         case JCS_YCbCr:
1651 
1652             /*
1653              * There are several possibilities:
1654              *  - we got image with embeded colorspace
1655              *     Use it. User knows what he is doing.
1656              *  - we got JFIF image
1657              *     Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2)
1658              *  - we got EXIF image
1659              *     Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63)
1660              *  - something else
1661              *     Apply heuristical rules to identify actual colorspace.
1662              */
1663 
1664             if (cinfo->saw_Adobe_marker) {
1665                 if (cinfo->Adobe_transform != 1) {
1666                     /*
1667                      * IJG guesses this is YCbCr and emits a warning
1668                      * We would rather not guess.  Then the user knows
1669                      * To read this as a Raster if at all
1670                      */
1671                     cinfo->jpeg_color_space = JCS_UNKNOWN;
1672                     cinfo->out_color_space = JCS_UNKNOWN;
1673                 }
1674             } else if (!cinfo->saw_JFIF_marker && !IS_EXIF(cinfo)) {
1675                 /*
1676                  * IJG assumes all unidentified 3-channels are YCbCr.
1677                  * We assume that only if the second two channels are
1678                  * subsampled (either horizontally or vertically).  If not,
1679                  * we assume RGB.
1680                  *
1681                  * 4776576: Some digital cameras output YCbCr JPEG images
1682                  * that do not contain a JFIF APP0 marker but are only
1683                  * vertically subsampled (no horizontal subsampling).
1684                  * We should only assume this is RGB data if the subsampling
1685                  * factors for the second two channels are the same as the
1686                  * first (check both horizontal and vertical factors).
1687                  */
1688                 h_samp0 = cinfo->comp_info[0].h_samp_factor;
1689                 h_samp1 = cinfo->comp_info[1].h_samp_factor;
1690                 h_samp2 = cinfo->comp_info[2].h_samp_factor;
1691 
1692                 v_samp0 = cinfo->comp_info[0].v_samp_factor;
1693                 v_samp1 = cinfo->comp_info[1].v_samp_factor;
1694                 v_samp2 = cinfo->comp_info[2].v_samp_factor;
1695 
1696                 if ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) &&
1697                     (v_samp1 == v_samp0) && (v_samp2 == v_samp0))
1698                 {
1699                     cinfo->jpeg_color_space = JCS_RGB;
1700                     /* output is already RGB, so it stays the same */
1701                 }
1702             }
1703             break;
1704 #ifdef YCCALPHA
1705         case JCS_YCC:
1706             cinfo->out_color_space = JCS_YCC;
1707             break;
1708 #endif
1709         case JCS_YCCK:
1710             if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) {
1711                 /*
1712                  * IJG guesses this is YCCK and emits a warning
1713                  * We would rather not guess.  Then the user knows
1714                  * To read this as a Raster if at all
1715                  */
1716                 cinfo->jpeg_color_space = JCS_UNKNOWN;
1717                 cinfo->out_color_space = JCS_UNKNOWN;
1718             }
1719             break;
1720         case JCS_CMYK:
1721             /*
1722              * IJG assumes all unidentified 4-channels are CMYK.
1723              * We assume that only if the second two channels are
1724              * not subsampled (either horizontally or vertically).
1725              * If they are, we assume YCCK.
1726              */
1727             h_samp0 = cinfo->comp_info[0].h_samp_factor;
1728             h_samp1 = cinfo->comp_info[1].h_samp_factor;
1729             h_samp2 = cinfo->comp_info[2].h_samp_factor;
1730 
1731             v_samp0 = cinfo->comp_info[0].v_samp_factor;
1732             v_samp1 = cinfo->comp_info[1].v_samp_factor;
1733             v_samp2 = cinfo->comp_info[2].v_samp_factor;
1734 
1735             if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) ||
1736                 (v_samp1 > v_samp0) && (v_samp2 > v_samp0))
1737             {
1738                 cinfo->jpeg_color_space = JCS_YCCK;
1739                 /* Leave the output space as CMYK */
1740             }
1741         }
1742         RELEASE_ARRAYS(env, data, src->next_input_byte);
1743 
1744         /* read icc profile data */
1745         profileData = read_icc_profile(env, cinfo);
1746 
1747         if ((*env)->ExceptionCheck(env)) {
1748             return retval;
1749         }
1750 
1751         (*env)->CallVoidMethod(env, this,
1752                                JPEGImageReader_setImageDataID,
1753                                cinfo->image_width,
1754                                cinfo->image_height,
1755                                cinfo->jpeg_color_space,
1756                                cinfo->out_color_space,
1757                                cinfo->num_components,
1758                                profileData);
1759         if (reset) {
1760             jpeg_abort_decompress(cinfo);
1761         }
1762     }
1763 
1764     return retval;
1765 }
1766 
1767 
1768 JNIEXPORT void JNICALL
1769 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setOutColorSpace
1770     (JNIEnv *env,
1771      jobject this,
1772      jlong ptr,
1773      jint code) {
1774 
1775     imageIODataPtr data = (imageIODataPtr) ptr;
1776     j_decompress_ptr cinfo;
1777 
1778     if (data == NULL) {
1779         JNU_ThrowByName(env,
1780                         "java/lang/IllegalStateException",
1781                         "Attempting to use reader after dispose()");
1782         return;
1783     }
1784 
1785     cinfo = (j_decompress_ptr) data->jpegObj;
1786 
1787     cinfo->out_color_space = code;
1788 
1789 }
1790 
1791 JNIEXPORT jboolean JNICALL
1792 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
1793     (JNIEnv *env,
1794      jobject this,
1795      jlong ptr,
1796      jbyteArray buffer,
1797      jint numBands,
1798      jintArray srcBands,
1799      jintArray bandSizes,
1800      jint sourceXStart,
1801      jint sourceYStart,
1802      jint sourceWidth,
1803      jint sourceHeight,
1804      jint stepX,
1805      jint stepY,
1806      jobjectArray qtables,
1807      jobjectArray DCHuffmanTables,
1808      jobjectArray ACHuffmanTables,
1809      jint minProgressivePass,  // Counts from 0
1810      jint maxProgressivePass,
1811      jboolean wantUpdates) {
1812 
1813 
1814     struct jpeg_source_mgr *src;
1815     JSAMPROW scanLinePtr = NULL;
1816     jint bands[MAX_BANDS];
1817     int i, j;
1818     jint *body;
1819     int scanlineLimit;
1820     int pixelStride;
1821     unsigned char *in, *out, *pixelLimit;
1822     int targetLine;
1823     int skipLines, linesLeft;
1824     pixelBufferPtr pb;
1825     sun_jpeg_error_ptr jerr;
1826     boolean done;
1827     jint *bandSize;
1828     int maxBandValue, halfMaxBandValue;
1829     boolean mustScale = FALSE;
1830     boolean progressive = FALSE;
1831     boolean orderedBands = TRUE;
1832     imageIODataPtr data = (imageIODataPtr) ptr;
1833     j_decompress_ptr cinfo;
1834     unsigned int numBytes;
1835 
1836     /* verify the inputs */
1837 
1838     if (data == NULL) {
1839         JNU_ThrowByName(env,
1840                         "java/lang/IllegalStateException",
1841                         "Attempting to use reader after dispose()");
1842         return JNI_FALSE;
1843     }
1844 
1845     if ((buffer == NULL) || (srcBands == NULL))  {
1846         JNU_ThrowNullPointerException(env, 0);
1847         return JNI_FALSE;
1848     }
1849 
1850     cinfo = (j_decompress_ptr) data->jpegObj;
1851 
1852     if ((numBands < 1) ||
1853         (sourceXStart < 0) || (sourceXStart >= (jint)cinfo->image_width) ||
1854         (sourceYStart < 0) || (sourceYStart >= (jint)cinfo->image_height) ||
1855         (sourceWidth < 1) || (sourceWidth > (jint)cinfo->image_width) ||
1856         (sourceHeight < 1) || (sourceHeight > (jint)cinfo->image_height) ||
1857         (stepX < 1) || (stepY < 1) ||
1858         (minProgressivePass < 0) ||
1859         (maxProgressivePass < minProgressivePass))
1860     {
1861         JNU_ThrowByName(env, "javax/imageio/IIOException",
1862                         "Invalid argument to native readImage");
1863         return JNI_FALSE;
1864     }
1865 
1866     if (stepX > cinfo->image_width) {
1867         stepX = cinfo->image_width;
1868     }
1869     if (stepY > cinfo->image_height) {
1870         stepY = cinfo->image_height;
1871     }
1872 
1873     /*
1874      * First get the source bands array and copy it to our local array
1875      * so we don't have to worry about pinning and unpinning it again.
1876      */
1877 
1878     body = (*env)->GetIntArrayElements(env, srcBands, NULL);
1879     if (body == NULL) {
1880         JNU_ThrowByName( env,
1881                          "java/lang/OutOfMemoryError",
1882                          "Initializing Read");
1883         return JNI_FALSE;
1884     }
1885 
1886     for (i = 0; i < numBands; i++) {
1887         bands[i] = body[i];
1888         if (orderedBands && (bands[i] != i)) {
1889             orderedBands = FALSE;
1890         }
1891     }
1892 
1893     (*env)->ReleaseIntArrayElements(env, srcBands, body, JNI_ABORT);
1894 
1895 #ifdef DEBUG_IIO_JPEG
1896     printf("---- in reader.read ----\n");
1897     printf("numBands is %d\n", numBands);
1898     printf("bands array: ");
1899     for (i = 0; i < numBands; i++) {
1900         printf("%d ", bands[i]);
1901     }
1902     printf("\n");
1903     printf("jq table 0 at %p\n",
1904                cinfo->quant_tbl_ptrs[0]);
1905 #endif
1906 
1907     data = (imageIODataPtr) cinfo->client_data;
1908     src = cinfo->src;
1909 
1910     /* Set the buffer as our PixelBuffer */
1911     pb = &data->pixelBuf;
1912 
1913     if (setPixelBuffer(env, pb, buffer) == NOT_OK) {
1914         return data->abortFlag;  // We already threw an out of memory exception
1915     }
1916 
1917     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
1918     jerr = (sun_jpeg_error_ptr) cinfo->err;
1919 
1920     if (setjmp(jerr->setjmp_buffer)) {
1921         /* If we get here, the JPEG code has signaled an error
1922            while reading. */
1923         RELEASE_ARRAYS(env, data, src->next_input_byte);
1924         if (!(*env)->ExceptionOccurred(env)) {
1925             char buffer[JMSG_LENGTH_MAX];
1926             (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
1927                                           buffer);
1928             JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
1929         }
1930         if (scanLinePtr != NULL) {
1931             free(scanLinePtr);
1932             scanLinePtr = NULL;
1933         }
1934         return data->abortFlag;
1935     }
1936 
1937     if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) {
1938         JNU_ThrowByName(env,
1939                         "javax/imageio/IIOException",
1940                         "Array pin failed");
1941         return data->abortFlag;
1942     }
1943 
1944     // If there are no tables in our structure and table arguments aren't
1945     // NULL, use the table arguments.
1946     if ((qtables != NULL) && (cinfo->quant_tbl_ptrs[0] == NULL)) {
1947         (void) setQTables(env, (j_common_ptr) cinfo, qtables, TRUE);
1948     }
1949 
1950     if ((DCHuffmanTables != NULL) && (cinfo->dc_huff_tbl_ptrs[0] == NULL)) {
1951         setHTables(env, (j_common_ptr) cinfo,
1952                    DCHuffmanTables,
1953                    ACHuffmanTables,
1954                    TRUE);
1955     }
1956 
1957     progressive = jpeg_has_multiple_scans(cinfo);
1958     if (progressive) {
1959         cinfo->buffered_image = TRUE;
1960         cinfo->input_scan_number = minProgressivePass+1; // Java count from 0
1961 #define MAX_JAVA_INT 2147483647 // XXX Is this defined in JNI somewhere?
1962         if (maxProgressivePass < MAX_JAVA_INT) {
1963             maxProgressivePass++; // For testing
1964         }
1965     }
1966 
1967     data->streamBuf.suspendable = FALSE;
1968 
1969     jpeg_start_decompress(cinfo);
1970 
1971     if (numBands !=  cinfo->output_components) {
1972         JNU_ThrowByName(env, "javax/imageio/IIOException",
1973                         "Invalid argument to native readImage");
1974         return data->abortFlag;
1975     }
1976 
1977 
1978     // Allocate a 1-scanline buffer
1979     scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->output_components);
1980     if (scanLinePtr == NULL) {
1981         RELEASE_ARRAYS(env, data, src->next_input_byte);
1982         JNU_ThrowByName( env,
1983                          "java/lang/OutOfMemoryError",
1984                          "Reading JPEG Stream");
1985         return data->abortFlag;
1986     }
1987 
1988     // loop over progressive passes
1989     done = FALSE;
1990     while (!done) {
1991         if (progressive) {
1992             // initialize the next pass.  Note that this skips up to
1993             // the first interesting pass.
1994             jpeg_start_output(cinfo, cinfo->input_scan_number);
1995             if (wantUpdates) {
1996                 (*env)->CallVoidMethod(env, this,
1997                                        JPEGImageReader_passStartedID,
1998                                        cinfo->input_scan_number-1);
1999             }
2000         } else if (wantUpdates) {
2001             (*env)->CallVoidMethod(env, this,
2002                                    JPEGImageReader_passStartedID,
2003                                    0);
2004 
2005         }
2006 
2007         // Skip until the first interesting line
2008         while ((data->abortFlag == JNI_FALSE)
2009                && ((jint)cinfo->output_scanline < sourceYStart)) {
2010             jpeg_read_scanlines(cinfo, &scanLinePtr, 1);
2011         }
2012 
2013         scanlineLimit = sourceYStart+sourceHeight;
2014         pixelLimit = scanLinePtr
2015             +(sourceXStart+sourceWidth)*cinfo->output_components;
2016 
2017         pixelStride = stepX*cinfo->output_components;
2018         targetLine = 0;
2019 
2020         while ((data->abortFlag == JNI_FALSE)
2021                && ((jint)cinfo->output_scanline < scanlineLimit)) {
2022 
2023             jpeg_read_scanlines(cinfo, &scanLinePtr, 1);
2024 
2025             // Now mangle it into our buffer
2026             out = data->pixelBuf.buf.bp;
2027 
2028             if (orderedBands && (pixelStride == numBands)) {
2029                 // Optimization: The component bands are ordered sequentially,
2030                 // so we can simply use memcpy() to copy the intermediate
2031                 // scanline buffer into the raster.
2032                 in = scanLinePtr + (sourceXStart * cinfo->output_components);
2033                 if (pixelLimit > in) {
2034                     numBytes = pixelLimit - in;
2035                     if (numBytes > data->pixelBuf.byteBufferLength) {
2036                         numBytes = data->pixelBuf.byteBufferLength;
2037                     }
2038                     memcpy(out, in, numBytes);
2039                 }
2040             } else {
2041                 numBytes = numBands;
2042                 for (in = scanLinePtr+sourceXStart*cinfo->output_components;
2043                      in < pixelLimit &&
2044                        numBytes <= data->pixelBuf.byteBufferLength;
2045                      in += pixelStride) {
2046                     for (i = 0; i < numBands; i++) {
2047                         *out++ = *(in+bands[i]);
2048                     }
2049                     numBytes += numBands;
2050                 }
2051             }
2052 
2053             // And call it back to Java
2054             RELEASE_ARRAYS(env, data, src->next_input_byte);
2055             (*env)->CallVoidMethod(env,
2056                                    this,
2057                                    JPEGImageReader_acceptPixelsID,
2058                                    targetLine++,
2059                                    progressive);
2060 
2061             if ((*env)->ExceptionOccurred(env)
2062                 || !GET_ARRAYS(env, data, &(src->next_input_byte))) {
2063                 cinfo->err->error_exit((j_common_ptr) cinfo);
2064             }
2065 
2066             // And skip over uninteresting lines to the next subsampled line
2067             // Ensure we don't go past the end of the image
2068 
2069             // Lines to skip based on subsampling
2070             skipLines = stepY - 1;
2071             // Lines left in the image
2072             linesLeft =  scanlineLimit - cinfo->output_scanline;
2073             // Take the minimum
2074             if (skipLines > linesLeft) {
2075                 skipLines = linesLeft;
2076             }
2077             for(i = 0; i < skipLines; i++) {
2078                 jpeg_read_scanlines(cinfo, &scanLinePtr, 1);
2079             }
2080         }
2081         if (progressive) {
2082             jpeg_finish_output(cinfo); // Increments pass counter
2083             // Call Java to notify pass complete
2084             if (jpeg_input_complete(cinfo)
2085                 || (cinfo->input_scan_number > maxProgressivePass)) {
2086                 done = TRUE;
2087             }
2088         } else {
2089             done = TRUE;
2090         }
2091         if (wantUpdates) {
2092             (*env)->CallVoidMethod(env, this,
2093                                    JPEGImageReader_passCompleteID);
2094         }
2095 
2096     }
2097     /*
2098      * We are done, but we might not have read all the lines, or all
2099      * the passes, so use jpeg_abort instead of jpeg_finish_decompress.
2100      */
2101     if (cinfo->output_scanline == cinfo->output_height) {
2102         //    if ((cinfo->output_scanline == cinfo->output_height) &&
2103         //(jpeg_input_complete(cinfo))) {  // We read the whole file
2104         jpeg_finish_decompress(cinfo);
2105     } else {
2106         jpeg_abort_decompress(cinfo);
2107     }
2108 
2109     free(scanLinePtr);
2110 
2111     RELEASE_ARRAYS(env, data, src->next_input_byte);
2112 
2113     return data->abortFlag;
2114 }
2115 
2116 JNIEXPORT void JNICALL
2117 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_abortRead
2118     (JNIEnv *env,
2119      jobject this,
2120      jlong ptr) {
2121 
2122     imageIODataPtr data = (imageIODataPtr) ptr;
2123 
2124     if (data == NULL) {
2125         JNU_ThrowByName(env,
2126                         "java/lang/IllegalStateException",
2127                         "Attempting to use reader after dispose()");
2128         return;
2129     }
2130 
2131     imageio_abort(env, this, data);
2132 
2133 }
2134 
2135 JNIEXPORT void JNICALL
2136 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetLibraryState
2137     (JNIEnv *env,
2138      jobject this,
2139      jlong ptr) {
2140     imageIODataPtr data = (imageIODataPtr) ptr;
2141     j_decompress_ptr cinfo;
2142 
2143     if (data == NULL) {
2144         JNU_ThrowByName(env,
2145                         "java/lang/IllegalStateException",
2146                         "Attempting to use reader after dispose()");
2147         return;
2148     }
2149 
2150     cinfo = (j_decompress_ptr) data->jpegObj;
2151 
2152     jpeg_abort_decompress(cinfo);
2153 }
2154 
2155 
2156 JNIEXPORT void JNICALL
2157 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_resetReader
2158     (JNIEnv *env,
2159      jobject this,
2160      jlong ptr) {
2161 
2162     imageIODataPtr data = (imageIODataPtr) ptr;
2163     j_decompress_ptr cinfo;
2164     sun_jpeg_error_ptr jerr;
2165 
2166     if (data == NULL) {
2167         JNU_ThrowByName(env,
2168                         "java/lang/IllegalStateException",
2169                         "Attempting to use reader after dispose()");
2170         return;
2171     }
2172 
2173     cinfo = (j_decompress_ptr) data->jpegObj;
2174 
2175     jerr = (sun_jpeg_error_ptr) cinfo->err;
2176 
2177     imageio_reset(env, (j_common_ptr) cinfo, data);
2178 
2179     /*
2180      * The tables have not been reset, and there is no way to do so
2181      * in IJG without leaking memory.  The only situation in which
2182      * this will cause a problem is if an image-only stream is read
2183      * with this object without initializing the correct tables first.
2184      * This situation, which should cause an error, might work but
2185      * produce garbage instead.  If the huffman tables are wrong,
2186      * it will fail during the decode.  If the q tables are wrong, it
2187      * will look strange.  This is very unlikely, so don't worry about
2188      * it.  To be really robust, we would keep a flag for table state
2189      * and consult it to catch exceptional situations.
2190      */
2191 
2192     /* above does not clean up the source, so we have to */
2193 
2194     /*
2195       We need to explicitly initialize exception handler or we may
2196        longjump to random address from the term_source()
2197      */
2198 
2199     if (setjmp(jerr->setjmp_buffer)) {
2200 
2201         /*
2202           We may get IOException from pushBack() here.
2203 
2204           However it could be legal if original input stream was closed
2205           earlier (for example because network connection was closed).
2206           Unfortunately, image inputstream API has no way to check whether
2207           stream is already closed or IOException was thrown because of some
2208           other IO problem,
2209           And we can not avoid call to pushBack() on closed stream for the
2210           same reason.
2211 
2212           So, for now we will silently eat this exception.
2213 
2214           NB: this may be changed in future when ImageInputStream API will
2215           become more flexible.
2216         */
2217 
2218         if ((*env)->ExceptionOccurred(env)) {
2219             (*env)->ExceptionClear(env);
2220         }
2221     } else {
2222         cinfo->src->term_source(cinfo);
2223     }
2224 
2225     cinfo->src->bytes_in_buffer = 0;
2226     cinfo->src->next_input_byte = NULL;
2227 }
2228 
2229 JNIEXPORT void JNICALL
2230 Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_disposeReader
2231     (JNIEnv *env,
2232      jclass reader,
2233      jlong ptr) {
2234 
2235     imageIODataPtr data = (imageIODataPtr) ptr;
2236     j_common_ptr info = destroyImageioData(env, data);
2237 
2238     imageio_dispose(info);
2239 }
2240 
2241 /********************** end of Reader *************************/
2242 
2243 /********************** Writer Support ************************/
2244 
2245 /********************** Destination Manager *******************/
2246 
2247 METHODDEF(void)
2248 /*
2249  * Initialize destination --- called by jpeg_start_compress
2250  * before any data is actually written.  The data arrays
2251  * must be pinned before this is called.
2252  */
2253 imageio_init_destination (j_compress_ptr cinfo)
2254 {
2255     struct jpeg_destination_mgr *dest = cinfo->dest;
2256     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
2257     streamBufferPtr sb = &data->streamBuf;
2258     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
2259 
2260     if (sb->buf == NULL) {
2261         // We forgot to pin the array
2262         (*env)->FatalError(env, "Output buffer not pinned!");
2263     }
2264 
2265     dest->next_output_byte = sb->buf;
2266     dest->free_in_buffer = sb->bufferLength;
2267 }
2268 
2269 /*
2270  * Empty the output buffer --- called whenever buffer fills up.
2271  *
2272  * This routine writes the entire output buffer
2273  * (ignoring the current state of next_output_byte & free_in_buffer),
2274  * resets the pointer & count to the start of the buffer, and returns TRUE
2275  * indicating that the buffer has been dumped.
2276  */
2277 
2278 METHODDEF(boolean)
2279 imageio_empty_output_buffer (j_compress_ptr cinfo)
2280 {
2281     struct jpeg_destination_mgr *dest = cinfo->dest;
2282     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
2283     streamBufferPtr sb = &data->streamBuf;
2284     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
2285 
2286     RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2287 
2288     (*env)->CallVoidMethod(env,
2289                            sb->stream,
2290                            ImageOutputStream_writeID,
2291                            sb->hstreamBuffer,
2292                            0,
2293                            sb->bufferLength);
2294     if ((*env)->ExceptionOccurred(env)
2295         || !GET_ARRAYS(env, data,
2296                        (const JOCTET **)(&dest->next_output_byte))) {
2297             cinfo->err->error_exit((j_common_ptr) cinfo);
2298     }
2299 
2300     dest->next_output_byte = sb->buf;
2301     dest->free_in_buffer = sb->bufferLength;
2302 
2303     return TRUE;
2304 }
2305 
2306 /*
2307  * After all of the data has been encoded there may still be some
2308  * more left over in some of the working buffers.  Now is the
2309  * time to clear them out.
2310  */
2311 METHODDEF(void)
2312 imageio_term_destination (j_compress_ptr cinfo)
2313 {
2314     struct jpeg_destination_mgr *dest = cinfo->dest;
2315     imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
2316     streamBufferPtr sb = &data->streamBuf;
2317     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
2318 
2319     /* find out how much needs to be written */
2320     jint datacount = sb->bufferLength - dest->free_in_buffer;
2321 
2322     if (datacount != 0) {
2323         RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2324 
2325         (*env)->CallVoidMethod(env,
2326                                sb->stream,
2327                                ImageOutputStream_writeID,
2328                                sb->hstreamBuffer,
2329                                0,
2330                                datacount);
2331 
2332         if ((*env)->ExceptionOccurred(env)
2333             || !GET_ARRAYS(env, data,
2334                            (const JOCTET **)(&dest->next_output_byte))) {
2335             cinfo->err->error_exit((j_common_ptr) cinfo);
2336         }
2337     }
2338 
2339     dest->next_output_byte = NULL;
2340     dest->free_in_buffer = 0;
2341 
2342 }
2343 
2344 /*
2345  * Flush the destination buffer.  This is not called by the library,
2346  * but by our code below.  This is the simplest implementation, though
2347  * certainly not the most efficient.
2348  */
2349 METHODDEF(void)
2350 imageio_flush_destination(j_compress_ptr cinfo)
2351 {
2352     imageio_term_destination(cinfo);
2353     imageio_init_destination(cinfo);
2354 }
2355 
2356 /********************** end of destination manager ************/
2357 
2358 /********************** Writer JNI calls **********************/
2359 
2360 
2361 JNIEXPORT void JNICALL
2362 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs
2363     (JNIEnv *env,
2364      jclass cls,
2365      jclass IOSClass,
2366      jclass qTableClass,
2367      jclass huffClass) {
2368 
2369     ImageOutputStream_writeID = (*env)->GetMethodID(env,
2370                                                     IOSClass,
2371                                                     "write",
2372                                                     "([BII)V");
2373 
2374     JPEGImageWriter_warningOccurredID = (*env)->GetMethodID(env,
2375                                                             cls,
2376                                                             "warningOccurred",
2377                                                             "(I)V");
2378     JPEGImageWriter_warningWithMessageID =
2379         (*env)->GetMethodID(env,
2380                             cls,
2381                             "warningWithMessage",
2382                             "(Ljava/lang/String;)V");
2383 
2384     JPEGImageWriter_writeMetadataID = (*env)->GetMethodID(env,
2385                                                           cls,
2386                                                           "writeMetadata",
2387                                                           "()V");
2388     JPEGImageWriter_grabPixelsID = (*env)->GetMethodID(env,
2389                                                        cls,
2390                                                        "grabPixels",
2391                                                        "(I)V");
2392 
2393     JPEGQTable_tableID = (*env)->GetFieldID(env,
2394                                             qTableClass,
2395                                             "qTable",
2396                                             "[I");
2397 
2398     JPEGHuffmanTable_lengthsID = (*env)->GetFieldID(env,
2399                                                     huffClass,
2400                                                     "lengths",
2401                                                     "[S");
2402 
2403     JPEGHuffmanTable_valuesID = (*env)->GetFieldID(env,
2404                                                     huffClass,
2405                                                     "values",
2406                                                     "[S");
2407 }
2408 
2409 JNIEXPORT jlong JNICALL
2410 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter
2411     (JNIEnv *env,
2412      jobject this) {
2413 
2414     imageIODataPtr ret;
2415     struct sun_jpeg_error_mgr *jerr;
2416     struct jpeg_destination_mgr *dest;
2417 
2418     /* This struct contains the JPEG compression parameters and pointers to
2419      * working space (which is allocated as needed by the JPEG library).
2420      */
2421     struct jpeg_compress_struct *cinfo =
2422         malloc(sizeof(struct jpeg_compress_struct));
2423     if (cinfo == NULL) {
2424         JNU_ThrowByName( env,
2425                          "java/lang/OutOfMemoryError",
2426                          "Initializing Writer");
2427         return 0;
2428     }
2429 
2430     /* We use our private extension JPEG error handler.
2431      */
2432     jerr = malloc (sizeof(struct sun_jpeg_error_mgr));
2433     if (jerr == NULL) {
2434         JNU_ThrowByName( env,
2435                          "java/lang/OutOfMemoryError",
2436                          "Initializing Writer");
2437         free(cinfo);
2438         return 0;
2439     }
2440 
2441     /* We set up the normal JPEG error routines, then override error_exit. */
2442     cinfo->err = jpeg_std_error(&(jerr->pub));
2443     jerr->pub.error_exit = sun_jpeg_error_exit;
2444     /* We need to setup our own print routines */
2445     jerr->pub.output_message = sun_jpeg_output_message;
2446     /* Now we can setjmp before every call to the library */
2447 
2448     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
2449     if (setjmp(jerr->setjmp_buffer)) {
2450         /* If we get here, the JPEG code has signaled an error. */
2451         char buffer[JMSG_LENGTH_MAX];
2452         (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
2453                                       buffer);
2454         JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
2455         return 0;
2456     }
2457 
2458     /* Perform library initialization */
2459     jpeg_create_compress(cinfo);
2460 
2461     /* Now set up the destination  */
2462     dest = malloc(sizeof(struct jpeg_destination_mgr));
2463     if (dest == NULL) {
2464         JNU_ThrowByName( env,
2465                          "java/lang/OutOfMemoryError",
2466                          "Initializing Writer");
2467         imageio_dispose((j_common_ptr)cinfo);
2468         return 0;
2469     }
2470 
2471     dest->init_destination = imageio_init_destination;
2472     dest->empty_output_buffer = imageio_empty_output_buffer;
2473     dest->term_destination = imageio_term_destination;
2474     dest->next_output_byte = NULL;
2475     dest->free_in_buffer = 0;
2476 
2477     cinfo->dest = dest;
2478 
2479     /* set up the association to persist for future calls */
2480     ret = initImageioData(env, (j_common_ptr) cinfo, this);
2481     if (ret == NULL) {
2482         JNU_ThrowByName( env,
2483                          "java/lang/OutOfMemoryError",
2484                          "Initializing Writer");
2485         imageio_dispose((j_common_ptr)cinfo);
2486         return 0;
2487     }
2488     return (jlong) ret;
2489 }
2490 
2491 JNIEXPORT void JNICALL
2492 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest
2493     (JNIEnv *env,
2494      jobject this,
2495      jlong ptr,
2496      jobject destination) {
2497 
2498     imageIODataPtr data = (imageIODataPtr) ptr;
2499     j_compress_ptr cinfo;
2500 
2501     if (data == NULL) {
2502         JNU_ThrowByName(env,
2503                         "java/lang/IllegalStateException",
2504                         "Attempting to use writer after dispose()");
2505         return;
2506     }
2507 
2508     cinfo = (j_compress_ptr) data->jpegObj;
2509 
2510     imageio_set_stream(env, data->jpegObj, data, destination);
2511 
2512 
2513     // Don't call the init method, as that depends on pinned arrays
2514     cinfo->dest->next_output_byte = NULL;
2515     cinfo->dest->free_in_buffer = 0;
2516 }
2517 
2518 JNIEXPORT void JNICALL
2519 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables
2520     (JNIEnv *env,
2521      jobject this,
2522      jlong ptr,
2523      jobjectArray qtables,
2524      jobjectArray DCHuffmanTables,
2525      jobjectArray ACHuffmanTables) {
2526 
2527     struct jpeg_destination_mgr *dest;
2528     sun_jpeg_error_ptr jerr;
2529     imageIODataPtr data = (imageIODataPtr) ptr;
2530     j_compress_ptr cinfo;
2531 
2532     if (data == NULL) {
2533         JNU_ThrowByName(env,
2534                         "java/lang/IllegalStateException",
2535                         "Attempting to use writer after dispose()");
2536         return;
2537     }
2538 
2539     cinfo = (j_compress_ptr) data->jpegObj;
2540     dest = cinfo->dest;
2541 
2542     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
2543     jerr = (sun_jpeg_error_ptr) cinfo->err;
2544 
2545     if (setjmp(jerr->setjmp_buffer)) {
2546         /* If we get here, the JPEG code has signaled an error
2547            while writing. */
2548         RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2549         if (!(*env)->ExceptionOccurred(env)) {
2550             char buffer[JMSG_LENGTH_MAX];
2551             (*cinfo->err->format_message) ((j_common_ptr) cinfo,
2552                                           buffer);
2553             JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
2554         }
2555         return;
2556     }
2557 
2558     if (GET_ARRAYS(env, data,
2559                    (const JOCTET **)(&dest->next_output_byte)) == NOT_OK) {
2560         JNU_ThrowByName(env,
2561                         "javax/imageio/IIOException",
2562                         "Array pin failed");
2563         return;
2564     }
2565 
2566     jpeg_suppress_tables(cinfo, TRUE);  // Suppress writing of any current
2567 
2568     data->streamBuf.suspendable = FALSE;
2569     if (qtables != NULL) {
2570 #ifdef DEBUG_IIO_JPEG
2571         printf("in writeTables: qtables not NULL\n");
2572 #endif
2573         setQTables(env, (j_common_ptr) cinfo, qtables, TRUE);
2574     }
2575 
2576     if (DCHuffmanTables != NULL) {
2577         setHTables(env, (j_common_ptr) cinfo,
2578                    DCHuffmanTables, ACHuffmanTables, TRUE);
2579     }
2580 
2581     jpeg_write_tables(cinfo); // Flushes the buffer for you
2582     RELEASE_ARRAYS(env, data, NULL);
2583 }
2584 
2585 JNIEXPORT jboolean JNICALL
2586 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
2587     (JNIEnv *env,
2588      jobject this,
2589      jlong ptr,
2590      jbyteArray buffer,
2591      jint inCs, jint outCs,
2592      jint numBands,
2593      jintArray bandSizes,
2594      jint srcWidth,
2595      jint destWidth, jint destHeight,
2596      jint stepX, jint stepY,
2597      jobjectArray qtables,
2598      jboolean writeDQT,
2599      jobjectArray DCHuffmanTables,
2600      jobjectArray ACHuffmanTables,
2601      jboolean writeDHT,
2602      jboolean optimize,
2603      jboolean progressive,
2604      jint numScans,
2605      jintArray scanInfo,
2606      jintArray componentIds,
2607      jintArray HsamplingFactors,
2608      jintArray VsamplingFactors,
2609      jintArray QtableSelectors,
2610      jboolean haveMetadata,
2611      jint restartInterval) {
2612 
2613     struct jpeg_destination_mgr *dest;
2614     JSAMPROW scanLinePtr;
2615     int i, j;
2616     int pixelStride;
2617     unsigned char *in, *out, *pixelLimit, *scanLineLimit;
2618     unsigned int scanLineSize, pixelBufferSize;
2619     int targetLine;
2620     pixelBufferPtr pb;
2621     sun_jpeg_error_ptr jerr;
2622     jint *ids, *hfactors, *vfactors, *qsels;
2623     jsize qlen, hlen;
2624     int *scanptr;
2625     jint *scanData;
2626     jint *bandSize;
2627     int maxBandValue, halfMaxBandValue;
2628     imageIODataPtr data = (imageIODataPtr) ptr;
2629     j_compress_ptr cinfo;
2630     UINT8** scale = NULL;
2631 
2632     /* verify the inputs */
2633 
2634     if (data == NULL) {
2635         JNU_ThrowByName(env,
2636                         "java/lang/IllegalStateException",
2637                         "Attempting to use writer after dispose()");
2638         return JNI_FALSE;
2639     }
2640 
2641     if ((buffer == NULL) ||
2642         (qtables == NULL) ||
2643         // H tables can be null if optimizing
2644         (componentIds == NULL) ||
2645         (HsamplingFactors == NULL) || (VsamplingFactors == NULL) ||
2646         (QtableSelectors == NULL) ||
2647         ((numScans != 0) && (scanInfo != NULL))) {
2648 
2649         JNU_ThrowNullPointerException(env, 0);
2650         return JNI_FALSE;
2651 
2652     }
2653 
2654     scanLineSize = destWidth * numBands;
2655     if ((inCs < 0) || (inCs > JCS_YCCK) ||
2656         (outCs < 0) || (outCs > JCS_YCCK) ||
2657         (numBands < 1) || (numBands > MAX_BANDS) ||
2658         (srcWidth < 0) ||
2659         (destWidth < 0) || (destWidth > srcWidth) ||
2660         (destHeight < 0) ||
2661         (stepX < 0) || (stepY < 0) ||
2662         ((scanLineSize / numBands) < destWidth))  /* destWidth causes an integer overflow */
2663     {
2664         JNU_ThrowByName(env, "javax/imageio/IIOException",
2665                         "Invalid argument to native writeImage");
2666         return JNI_FALSE;
2667     }
2668 
2669     if (stepX > srcWidth) {
2670         stepX = srcWidth;
2671     }
2672 
2673     bandSize = (*env)->GetIntArrayElements(env, bandSizes, NULL);
2674 
2675     for (i = 0; i < numBands; i++) {
2676         if (bandSize[i] != JPEG_BAND_SIZE) {
2677             if (scale == NULL) {
2678                 scale = (UINT8**) calloc(numBands, sizeof(UINT8*));
2679 
2680                 if (scale == NULL) {
2681                     JNU_ThrowByName( env, "java/lang/OutOfMemoryError",
2682                                      "Writing JPEG Stream");
2683                     return JNI_FALSE;
2684                 }
2685             }
2686 
2687             maxBandValue = (1 << bandSize[i]) - 1;
2688 
2689             scale[i] = (UINT8*) malloc((maxBandValue + 1) * sizeof(UINT8));
2690 
2691             if (scale[i] == NULL) {
2692                 JNU_ThrowByName( env, "java/lang/OutOfMemoryError",
2693                                  "Writing JPEG Stream");
2694                 return JNI_FALSE;
2695             }
2696 
2697             halfMaxBandValue = maxBandValue >> 1;
2698 
2699             for (j = 0; j <= maxBandValue; j++) {
2700                 scale[i][j] = (UINT8)
2701                     ((j*MAX_JPEG_BAND_VALUE + halfMaxBandValue)/maxBandValue);
2702             }
2703         }
2704     }
2705 
2706     (*env)->ReleaseIntArrayElements(env, bandSizes,
2707                                     bandSize, JNI_ABORT);
2708 
2709     cinfo = (j_compress_ptr) data->jpegObj;
2710     dest = cinfo->dest;
2711 
2712     /* Set the buffer as our PixelBuffer */
2713     pb = &data->pixelBuf;
2714 
2715     if (setPixelBuffer(env, pb, buffer) == NOT_OK) {
2716         return data->abortFlag;  // We already threw an out of memory exception
2717     }
2718 
2719     // Allocate a 1-scanline buffer
2720     scanLinePtr = (JSAMPROW)malloc(scanLineSize);
2721     if (scanLinePtr == NULL) {
2722         RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2723         JNU_ThrowByName( env,
2724                          "java/lang/OutOfMemoryError",
2725                          "Writing JPEG Stream");
2726         return data->abortFlag;
2727     }
2728     scanLineLimit = scanLinePtr + scanLineSize;
2729 
2730     /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
2731     jerr = (sun_jpeg_error_ptr) cinfo->err;
2732 
2733     if (setjmp(jerr->setjmp_buffer)) {
2734         /* If we get here, the JPEG code has signaled an error
2735            while writing. */
2736         RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2737         if (!(*env)->ExceptionOccurred(env)) {
2738             char buffer[JMSG_LENGTH_MAX];
2739             (*cinfo->err->format_message) ((j_common_ptr) cinfo,
2740                                           buffer);
2741             JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
2742         }
2743         free(scanLinePtr);
2744         return data->abortFlag;
2745     }
2746 
2747     // set up parameters
2748     cinfo->image_width = destWidth;
2749     cinfo->image_height = destHeight;
2750     cinfo->input_components = numBands;
2751     cinfo->in_color_space = inCs;
2752 
2753     jpeg_set_defaults(cinfo);
2754 
2755     jpeg_set_colorspace(cinfo, outCs);
2756 
2757     cinfo->optimize_coding = optimize;
2758 
2759     cinfo->write_JFIF_header = FALSE;
2760     cinfo->write_Adobe_marker = FALSE;
2761     // copy componentIds
2762     ids = (*env)->GetIntArrayElements(env, componentIds, NULL);
2763     hfactors = (*env)->GetIntArrayElements(env, HsamplingFactors, NULL);
2764     vfactors = (*env)->GetIntArrayElements(env, VsamplingFactors, NULL);
2765     qsels = (*env)->GetIntArrayElements(env, QtableSelectors, NULL);
2766 
2767     if ((ids == NULL) ||
2768         (hfactors == NULL) || (vfactors == NULL) ||
2769         (qsels == NULL)) {
2770         JNU_ThrowByName( env,
2771                          "java/lang/OutOfMemoryError",
2772                          "Writing JPEG");
2773         return JNI_FALSE;
2774     }
2775 
2776     for (i = 0; i < numBands; i++) {
2777         cinfo->comp_info[i].component_id = ids[i];
2778         cinfo->comp_info[i].h_samp_factor = hfactors[i];
2779         cinfo->comp_info[i].v_samp_factor = vfactors[i];
2780         cinfo->comp_info[i].quant_tbl_no = qsels[i];
2781     }
2782 
2783     (*env)->ReleaseIntArrayElements(env, componentIds,
2784                                     ids, JNI_ABORT);
2785     (*env)->ReleaseIntArrayElements(env, HsamplingFactors,
2786                                     hfactors, JNI_ABORT);
2787     (*env)->ReleaseIntArrayElements(env, VsamplingFactors,
2788                                     vfactors, JNI_ABORT);
2789     (*env)->ReleaseIntArrayElements(env, QtableSelectors,
2790                                     qsels, JNI_ABORT);
2791 
2792     jpeg_suppress_tables(cinfo, TRUE);  // Disable writing any current
2793 
2794     qlen = setQTables(env, (j_common_ptr) cinfo, qtables, writeDQT);
2795 
2796     if (!optimize) {
2797         // Set the h tables
2798         hlen = setHTables(env,
2799                           (j_common_ptr) cinfo,
2800                           DCHuffmanTables,
2801                           ACHuffmanTables,
2802                           writeDHT);
2803     }
2804 
2805     if (GET_ARRAYS(env, data,
2806                    (const JOCTET **)(&dest->next_output_byte)) == NOT_OK) {
2807         JNU_ThrowByName(env,
2808                         "javax/imageio/IIOException",
2809                         "Array pin failed");
2810         return data->abortFlag;
2811     }
2812 
2813     data->streamBuf.suspendable = FALSE;
2814 
2815     if (progressive) {
2816         if (numScans == 0) { // then use default scans
2817             jpeg_simple_progression(cinfo);
2818         } else {
2819             cinfo->num_scans = numScans;
2820             // Copy the scanInfo to a local array
2821             // The following is copied from jpeg_simple_progression:
2822   /* Allocate space for script.
2823    * We need to put it in the permanent pool in case the application performs
2824    * multiple compressions without changing the settings.  To avoid a memory
2825    * leak if jpeg_simple_progression is called repeatedly for the same JPEG
2826    * object, we try to re-use previously allocated space, and we allocate
2827    * enough space to handle YCbCr even if initially asked for grayscale.
2828    */
2829             if (cinfo->script_space == NULL
2830                 || cinfo->script_space_size < numScans) {
2831                 cinfo->script_space_size = MAX(numScans, 10);
2832                 cinfo->script_space = (jpeg_scan_info *)
2833                     (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
2834                                                 JPOOL_PERMANENT,
2835                                                 cinfo->script_space_size
2836                                                 * sizeof(jpeg_scan_info));
2837             }
2838             cinfo->scan_info = cinfo->script_space;
2839             scanptr = (int *) cinfo->script_space;
2840             scanData = (*env)->GetIntArrayElements(env, scanInfo, NULL);
2841             // number of jints per scan is 9
2842             // We avoid a memcpy to handle different size ints
2843             for (i = 0; i < numScans*9; i++) {
2844                 scanptr[i] = scanData[i];
2845             }
2846             (*env)->ReleaseIntArrayElements(env, scanInfo,
2847                                             scanData, JNI_ABORT);
2848 
2849         }
2850     }
2851 
2852     cinfo->restart_interval = restartInterval;
2853 
2854 #ifdef DEBUG_IIO_JPEG
2855     printf("writer setup complete, starting compressor\n");
2856 #endif
2857 
2858     // start the compressor; tables must already be set
2859     jpeg_start_compress(cinfo, FALSE); // Leaves sent_table alone
2860 
2861     if (haveMetadata) {
2862         // Flush the buffer
2863         imageio_flush_destination(cinfo);
2864         // Call Java to write the metadata
2865         RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2866         (*env)->CallVoidMethod(env,
2867                                this,
2868                                JPEGImageWriter_writeMetadataID);
2869         if ((*env)->ExceptionOccurred(env)
2870             || !GET_ARRAYS(env, data,
2871                            (const JOCTET **)(&dest->next_output_byte))) {
2872                 cinfo->err->error_exit((j_common_ptr) cinfo);
2873          }
2874     }
2875 
2876     targetLine = 0;
2877     pixelBufferSize = srcWidth * numBands;
2878     pixelStride = numBands * stepX;
2879 
2880     // for each line in destHeight
2881     while ((data->abortFlag == JNI_FALSE)
2882            && (cinfo->next_scanline < cinfo->image_height)) {
2883         // get the line from Java
2884         RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
2885         (*env)->CallVoidMethod(env,
2886                                this,
2887                                JPEGImageWriter_grabPixelsID,
2888                                targetLine);
2889         if ((*env)->ExceptionOccurred(env)
2890             || !GET_ARRAYS(env, data,
2891                            (const JOCTET **)(&dest->next_output_byte))) {
2892                 cinfo->err->error_exit((j_common_ptr) cinfo);
2893          }
2894 
2895         // subsample it into our buffer
2896 
2897         in = data->pixelBuf.buf.bp;
2898         out = scanLinePtr;
2899         pixelLimit = in + ((pixelBufferSize > data->pixelBuf.byteBufferLength) ?
2900                            data->pixelBuf.byteBufferLength : pixelBufferSize);
2901         for (; (in < pixelLimit) && (out < scanLineLimit); in += pixelStride) {
2902             for (i = 0; i < numBands; i++) {
2903                 if (scale !=NULL && scale[i] != NULL) {
2904                     *out++ = scale[i][*(in+i)];
2905 #ifdef DEBUG_IIO_JPEG
2906                     if (in == data->pixelBuf.buf.bp){ // Just the first pixel
2907                         printf("in %d -> out %d, ", *(in+i), *(out-i-1));
2908                     }
2909 #endif
2910 
2911 #ifdef DEBUG_IIO_JPEG
2912                     if (in == data->pixelBuf.buf.bp){ // Just the first pixel
2913                         printf("\n");
2914                     }
2915 #endif
2916                 } else {
2917                     *out++ = *(in+i);
2918                 }
2919             }
2920         }
2921         // write it out
2922         jpeg_write_scanlines(cinfo, (JSAMPARRAY)&scanLinePtr, 1);
2923         targetLine += stepY;
2924     }
2925 
2926     /*
2927      * We are done, but we might not have done all the lines,
2928      * so use jpeg_abort instead of jpeg_finish_compress.
2929      */
2930     if (cinfo->next_scanline == cinfo->image_height) {
2931         jpeg_finish_compress(cinfo);  // Flushes buffer with term_dest
2932     } else {
2933         jpeg_abort((j_common_ptr)cinfo);
2934     }
2935 
2936     if (scale != NULL) {
2937         for (i = 0; i < numBands; i++) {
2938             if (scale[i] != NULL) {
2939                 free(scale[i]);
2940             }
2941         }
2942         free(scale);
2943     }
2944 
2945     free(scanLinePtr);
2946     RELEASE_ARRAYS(env, data, NULL);
2947     return data->abortFlag;
2948 }
2949 
2950 JNIEXPORT void JNICALL
2951 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_abortWrite
2952     (JNIEnv *env,
2953      jobject this,
2954      jlong ptr) {
2955 
2956     imageIODataPtr data = (imageIODataPtr) ptr;
2957 
2958     if (data == NULL) {
2959         JNU_ThrowByName(env,
2960                         "java/lang/IllegalStateException",
2961                         "Attempting to use writer after dispose()");
2962         return;
2963     }
2964 
2965     imageio_abort(env, this, data);
2966 }
2967 
2968 JNIEXPORT void JNICALL
2969 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_resetWriter
2970     (JNIEnv *env,
2971      jobject this,
2972      jlong ptr) {
2973     imageIODataPtr data = (imageIODataPtr) ptr;
2974     j_compress_ptr cinfo;
2975 
2976     if (data == NULL) {
2977         JNU_ThrowByName(env,
2978                         "java/lang/IllegalStateException",
2979                         "Attempting to use writer after dispose()");
2980         return;
2981     }
2982 
2983     cinfo = (j_compress_ptr) data->jpegObj;
2984 
2985     imageio_reset(env, (j_common_ptr) cinfo, data);
2986 
2987     /*
2988      * The tables have not been reset, and there is no way to do so
2989      * in IJG without leaking memory.  The only situation in which
2990      * this will cause a problem is if an image-only stream is written
2991      * with this object without initializing the correct tables first,
2992      * which should not be possible.
2993      */
2994 
2995     cinfo->dest->next_output_byte = NULL;
2996     cinfo->dest->free_in_buffer = 0;
2997 }
2998 
2999 JNIEXPORT void JNICALL
3000 Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_disposeWriter
3001     (JNIEnv *env,
3002      jclass writer,
3003      jlong ptr) {
3004 
3005     imageIODataPtr data = (imageIODataPtr) ptr;
3006     j_common_ptr info = destroyImageioData(env, data);
3007 
3008     imageio_dispose(info);
3009 }