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