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