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