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