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