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