1/*
2 * Copyright (c) 1995, 2017, 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 was based upon the example.c stub file included in the
28 * release 6 of the Independent JPEG Group's free JPEG software.
29 * It has been updated to conform to release 6b.
30 */
31
32/* First, if system header files define "boolean" map it to "system_boolean" */
33#define boolean system_boolean
34
35#include <stdio.h>
36#include <setjmp.h>
37#include <string.h>
38#include <stdlib.h>
39#include <assert.h>
40
41#include "jni.h"
42#include "jni_util.h"
43
44/* undo "system_boolean" hack and undef FAR since we don't use it anyway */
45#undef boolean
46#undef FAR
47#include <jpeglib.h>
48#include "jerror.h"
49
50#ifdef __APPLE__
51/* use setjmp/longjmp versions that do not save/restore the signal mask */
52#define setjmp _setjmp
53#define longjmp _longjmp
54#endif
55
56/* The method IDs we cache. Note that the last two belongs to the
57 * java.io.InputStream class.
58 */
59static jmethodID sendHeaderInfoID;
60static jmethodID sendPixelsByteID;
61static jmethodID sendPixelsIntID;
62static jmethodID InputStream_readID;
63static jmethodID InputStream_availableID;
64
65/* Initialize the Java VM instance variable when the library is
66   first loaded */
67JavaVM *jvm;
68
69JNIEXPORT jint JNICALL
70DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
71{
72    jvm = vm;
73    return JNI_VERSION_1_2;
74}
75
76/*
77 * ERROR HANDLING:
78 *
79 * The JPEG library's standard error handler (jerror.c) is divided into
80 * several "methods" which you can override individually.  This lets you
81 * adjust the behavior without duplicating a lot of code, which you might
82 * have to update with each future release.
83 *
84 * Our example here shows how to override the "error_exit" method so that
85 * control is returned to the library's caller when a fatal error occurs,
86 * rather than calling exit() as the standard error_exit method does.
87 *
88 * We use C's setjmp/longjmp facility to return control.  This means that the
89 * routine which calls the JPEG library must first execute a setjmp() call to
90 * establish the return point.  We want the replacement error_exit to do a
91 * longjmp().  But we need to make the setjmp buffer accessible to the
92 * error_exit routine.  To do this, we make a private extension of the
93 * standard JPEG error handler object.  (If we were using C++, we'd say we
94 * were making a subclass of the regular error handler.)
95 *
96 * Here's the extended error handler struct:
97 */
98
99struct sun_jpeg_error_mgr {
100  struct jpeg_error_mgr pub;    /* "public" fields */
101
102  jmp_buf setjmp_buffer;        /* for return to caller */
103};
104
105typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr;
106
107/*
108 * Here's the routine that will replace the standard error_exit method:
109 */
110
111METHODDEF(void)
112sun_jpeg_error_exit (j_common_ptr cinfo)
113{
114  /* cinfo->err really points to a sun_jpeg_error_mgr struct */
115  sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err;
116
117  /* Always display the message. */
118  /* We could postpone this until after returning, if we chose. */
119  /* (*cinfo->err->output_message) (cinfo); */
120  /* For Java, we will format the message and put it in the error we throw. */
121
122  /* Return control to the setjmp point */
123  longjmp(myerr->setjmp_buffer, 1);
124}
125
126/*
127 * Error Message handling
128 *
129 * This overrides the output_message method to send JPEG messages
130 *
131 */
132
133METHODDEF(void)
134sun_jpeg_output_message (j_common_ptr cinfo)
135{
136  char buffer[JMSG_LENGTH_MAX];
137
138  /* Create the message */
139  (*cinfo->err->format_message) (cinfo, buffer);
140
141  /* Send it to stderr, adding a newline */
142  fprintf(stderr, "%s\n", buffer);
143}
144
145
146
147
148/*
149 * INPUT HANDLING:
150 *
151 * The JPEG library's input management is defined by the jpeg_source_mgr
152 * structure which contains two fields to convey the information in the
153 * buffer and 5 methods which perform all buffer management.  The library
154 * defines a standard input manager that uses stdio for obtaining compressed
155 * jpeg data, but here we need to use Java to get our data.
156 *
157 * We need to make the Java class information accessible to the source_mgr
158 * input routines.  We also need to store a pointer to the start of the
159 * Java array being used as an input buffer so that it is not moved or
160 * garbage collected while the JPEG library is using it.  To store these
161 * things, we make a private extension of the standard JPEG jpeg_source_mgr
162 * object.
163 *
164 * Here's the extended source manager struct:
165 */
166
167struct sun_jpeg_source_mgr {
168  struct jpeg_source_mgr pub;   /* "public" fields */
169
170  jobject hInputStream;
171  int suspendable;
172  unsigned long remaining_skip;
173
174  JOCTET *inbuf;
175  jbyteArray hInputBuffer;
176  size_t inbufoffset;
177
178  /* More stuff */
179  union pixptr {
180      int               *ip;
181      unsigned char     *bp;
182  } outbuf;
183  size_t outbufSize;
184  jobject hOutputBuffer;
185};
186
187typedef struct sun_jpeg_source_mgr * sun_jpeg_source_ptr;
188
189/* We use Get/ReleasePrimitiveArrayCritical functions to avoid
190 * the need to copy buffer elements.
191 *
192 * MAKE SURE TO:
193 *
194 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around
195 *   callbacks to Java.
196 * - call RELEASE_ARRAYS before returning to Java.
197 *
198 * Otherwise things will go horribly wrong. There may be memory leaks,
199 * excessive pinning, or even VM crashes!
200 *
201 * Note that GetPrimitiveArrayCritical may fail!
202 */
203static void RELEASE_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src)
204{
205    if (src->inbuf) {
206        if (src->pub.next_input_byte == 0) {
207            src->inbufoffset = -1;
208        } else {
209            src->inbufoffset = src->pub.next_input_byte - src->inbuf;
210        }
211        (*env)->ReleasePrimitiveArrayCritical(env, src->hInputBuffer,
212                                              src->inbuf, 0);
213        src->inbuf = 0;
214    }
215    if (src->outbuf.ip) {
216        (*env)->ReleasePrimitiveArrayCritical(env, src->hOutputBuffer,
217                                              src->outbuf.ip, 0);
218        src->outbuf.ip = 0;
219    }
220}
221
222static int GET_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src)
223{
224    if (src->hInputBuffer) {
225        assert(src->inbuf == 0);
226        src->inbuf = (JOCTET *)(*env)->GetPrimitiveArrayCritical
227            (env, src->hInputBuffer, 0);
228        if (src->inbuf == 0) {
229            return 0;
230        }
231        if ((int)(src->inbufoffset) >= 0) {
232            src->pub.next_input_byte = src->inbuf + src->inbufoffset;
233        }
234    }
235    if (src->hOutputBuffer) {
236        assert(src->outbuf.ip == 0);
237        src->outbufSize = (*env)->GetArrayLength(env, src->hOutputBuffer);
238        src->outbuf.ip = (int *)(*env)->GetPrimitiveArrayCritical
239            (env, src->hOutputBuffer, 0);
240        if (src->outbuf.ip == 0) {
241            RELEASE_ARRAYS(env, src);
242            return 0;
243        }
244    }
245    return 1;
246}
247
248/*
249 * Initialize source.  This is called by jpeg_read_header() before any
250 * data is actually read.  Unlike init_destination(), it may leave
251 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
252 * will occur immediately).
253 */
254
255GLOBAL(void)
256sun_jpeg_init_source(j_decompress_ptr cinfo)
257{
258    sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src;
259    src->pub.next_input_byte = 0;
260    src->pub.bytes_in_buffer = 0;
261}
262
263/*
264 * This is called whenever bytes_in_buffer has reached zero and more
265 * data is wanted.  In typical applications, it should read fresh data
266 * into the buffer (ignoring the current state of next_input_byte and
267 * bytes_in_buffer), reset the pointer & count to the start of the
268 * buffer, and return TRUE indicating that the buffer has been reloaded.
269 * It is not necessary to fill the buffer entirely, only to obtain at
270 * least one more byte.  bytes_in_buffer MUST be set to a positive value
271 * if TRUE is returned.  A FALSE return should only be used when I/O
272 * suspension is desired (this mode is discussed in the next section).
273 */
274/*
275 * Note that with I/O suspension turned on, this procedure should not
276 * do any work since the JPEG library has a very simple backtracking
277 * mechanism which relies on the fact that the buffer will be filled
278 * only when it has backed out to the top application level.  When
279 * suspendable is turned on, the sun_jpeg_fill_suspended_buffer will
280 * do the actual work of filling the buffer.
281 */
282
283GLOBAL(boolean)
284sun_jpeg_fill_input_buffer(j_decompress_ptr cinfo)
285{
286    sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src;
287    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
288    int ret, buflen;
289
290    if (src->suspendable) {
291        return FALSE;
292    }
293    if (src->remaining_skip) {
294        src->pub.skip_input_data(cinfo, 0);
295    }
296    RELEASE_ARRAYS(env, src);
297    buflen = (*env)->GetArrayLength(env, src->hInputBuffer);
298    ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID,
299                                src->hInputBuffer, 0, buflen);
300    if (ret > buflen) ret = buflen;
301    if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) {
302        cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
303    }
304    if (ret <= 0) {
305        /* Silently accept truncated JPEG files */
306        WARNMS(cinfo, JWRN_JPEG_EOF);
307        src->inbuf[0] = (JOCTET) 0xFF;
308        src->inbuf[1] = (JOCTET) JPEG_EOI;
309        ret = 2;
310    }
311
312    src->pub.next_input_byte = src->inbuf;
313    src->pub.bytes_in_buffer = ret;
314
315    return TRUE;
316}
317
318/*
319 * Note that with I/O suspension turned on, the JPEG library requires
320 * that all buffer filling be done at the top application level.  Due
321 * to the way that backtracking works, this procedure should save all
322 * of the data that was left in the buffer when suspension occurred and
323 * only read new data at the end.
324 */
325
326GLOBAL(void)
327sun_jpeg_fill_suspended_buffer(j_decompress_ptr cinfo)
328{
329    sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src;
330    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
331    size_t offset, buflen;
332    int ret;
333
334    RELEASE_ARRAYS(env, src);
335    ret = (*env)->CallIntMethod(env, src->hInputStream,
336                                InputStream_availableID);
337    if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) {
338        cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
339    }
340    if (ret < 0 || (unsigned int)ret <= src->remaining_skip) {
341        return;
342    }
343    if (src->remaining_skip) {
344        src->pub.skip_input_data(cinfo, 0);
345    }
346    /* Save the data currently in the buffer */
347    offset = src->pub.bytes_in_buffer;
348    if (src->pub.next_input_byte > src->inbuf) {
349        memmove(src->inbuf, src->pub.next_input_byte, offset);
350    }
351    RELEASE_ARRAYS(env, src);
352    buflen = (*env)->GetArrayLength(env, src->hInputBuffer) - offset;
353    if (buflen <= 0) {
354        if (!GET_ARRAYS(env, src)) {
355            cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
356        }
357        return;
358    }
359    ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID,
360                                src->hInputBuffer, offset, buflen);
361    if ((ret > 0) && ((unsigned int)ret > buflen)) ret = (int)buflen;
362    if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) {
363        cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
364    }
365    if (ret <= 0) {
366        /* Silently accept truncated JPEG files */
367        WARNMS(cinfo, JWRN_JPEG_EOF);
368        src->inbuf[offset] = (JOCTET) 0xFF;
369        src->inbuf[offset + 1] = (JOCTET) JPEG_EOI;
370        ret = 2;
371    }
372
373    src->pub.next_input_byte = src->inbuf;
374    src->pub.bytes_in_buffer = ret + offset;
375
376    return;
377}
378
379/*
380 * Skip num_bytes worth of data.  The buffer pointer and count should
381 * be advanced over num_bytes input bytes, refilling the buffer as
382 * needed.  This is used to skip over a potentially large amount of
383 * uninteresting data (such as an APPn marker).  In some applications
384 * it may be possible to optimize away the reading of the skipped data,
385 * but it's not clear that being smart is worth much trouble; large
386 * skips are uncommon.  bytes_in_buffer may be zero on return.
387 * A zero or negative skip count should be treated as a no-op.
388 */
389/*
390 * Note that with I/O suspension turned on, this procedure should not
391 * do any I/O since the JPEG library has a very simple backtracking
392 * mechanism which relies on the fact that the buffer will be filled
393 * only when it has backed out to the top application level.
394 */
395
396GLOBAL(void)
397sun_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
398{
399    sun_jpeg_source_ptr src = (sun_jpeg_source_ptr) cinfo->src;
400    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
401    int ret;
402    int buflen;
403
404
405    if (num_bytes < 0) {
406        return;
407    }
408    num_bytes += src->remaining_skip;
409    src->remaining_skip = 0;
410    ret = (int)src->pub.bytes_in_buffer; /* this conversion is safe, because capacity of the buffer is limited by jnit */
411    if (ret >= num_bytes) {
412        src->pub.next_input_byte += num_bytes;
413        src->pub.bytes_in_buffer -= num_bytes;
414        return;
415    }
416    num_bytes -= ret;
417    if (src->suspendable) {
418        src->remaining_skip = num_bytes;
419        src->pub.bytes_in_buffer = 0;
420        src->pub.next_input_byte = src->inbuf;
421        return;
422    }
423
424    /* Note that the signature for the method indicates that it takes
425     * and returns a long.  Casting the int num_bytes to a long on
426     * the input should work well enough, and if we assume that the
427     * return value for this particular method should always be less
428     * than the argument value (or -1), then the return value coerced
429     * to an int should return us the information we need...
430     */
431    RELEASE_ARRAYS(env, src);
432    buflen =  (*env)->GetArrayLength(env, src->hInputBuffer);
433    while (num_bytes > 0) {
434        ret = (*env)->CallIntMethod(env, src->hInputStream,
435                                    InputStream_readID,
436                                    src->hInputBuffer, 0, buflen);
437        if (ret > buflen) ret = buflen;
438        if ((*env)->ExceptionOccurred(env)) {
439            cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
440        }
441        if (ret < 0) {
442            break;
443        }
444        num_bytes -= ret;
445    }
446    if (!GET_ARRAYS(env, src)) {
447        cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
448    }
449    if (num_bytes > 0) {
450        /* Silently accept truncated JPEG files */
451        WARNMS(cinfo, JWRN_JPEG_EOF);
452        src->inbuf[0] = (JOCTET) 0xFF;
453        src->inbuf[1] = (JOCTET) JPEG_EOI;
454        src->pub.bytes_in_buffer = 2;
455        src->pub.next_input_byte = src->inbuf;
456    } else {
457        src->pub.bytes_in_buffer = -num_bytes;
458        src->pub.next_input_byte = src->inbuf + ret + num_bytes;
459    }
460}
461
462/*
463 * Terminate source --- called by jpeg_finish_decompress() after all
464 * data has been read.  Often a no-op.
465 */
466
467GLOBAL(void)
468sun_jpeg_term_source(j_decompress_ptr cinfo)
469{
470}
471
472JNIEXPORT void JNICALL
473Java_sun_awt_image_JPEGImageDecoder_initIDs(JNIEnv *env, jclass cls,
474                                            jclass InputStreamClass)
475{
476    CHECK_NULL(sendHeaderInfoID = (*env)->GetMethodID(env, cls, "sendHeaderInfo",
477                                           "(IIZZZ)Z"));
478    CHECK_NULL(sendPixelsByteID = (*env)->GetMethodID(env, cls, "sendPixels", "([BI)Z"));
479    CHECK_NULL(sendPixelsIntID = (*env)->GetMethodID(env, cls, "sendPixels", "([II)Z"));
480    CHECK_NULL(InputStream_readID = (*env)->GetMethodID(env, InputStreamClass,
481                                             "read", "([BII)I"));
482    CHECK_NULL(InputStream_availableID = (*env)->GetMethodID(env, InputStreamClass,
483                                                  "available", "()I"));
484}
485
486JNIEXPORT void JNICALL
487Java_sun_awt_image_JPEGImageDecoder_readImage(JNIEnv *env,
488                                              jobject this,
489                                              jobject hInputStream,
490                                              jbyteArray hInputBuffer)
491{
492  /* This struct contains the JPEG decompression parameters and pointers to
493   * working space (which is allocated as needed by the JPEG library).
494   */
495  struct jpeg_decompress_struct cinfo;
496  /* We use our private extension JPEG error handler.
497   * Note that this struct must live as long as the main JPEG parameter
498   * struct, to avoid dangling-pointer problems.
499   */
500  struct sun_jpeg_error_mgr jerr;
501  struct sun_jpeg_source_mgr jsrc;
502
503  int ret;
504  unsigned char *bp;
505  int *ip, pixel;
506  int grayscale;
507  int hasalpha;
508  int buffered_mode;
509  int final_pass;
510
511  /* Step 0: verify the inputs. */
512
513  if (hInputBuffer == 0 || hInputStream == 0) {
514    JNU_ThrowNullPointerException(env, 0);
515    return;
516  }
517
518  jsrc.outbuf.ip = 0;
519  jsrc.inbuf = 0;
520
521  /* Step 1: allocate and initialize JPEG decompression object */
522
523  /* We set up the normal JPEG error routines, then override error_exit. */
524  cinfo.err = jpeg_std_error(&jerr.pub);
525  jerr.pub.error_exit = sun_jpeg_error_exit;
526
527  /* We need to setup our own print routines */
528  jerr.pub.output_message = sun_jpeg_output_message;
529
530  /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
531  if (setjmp(jerr.setjmp_buffer)) {
532    /* If we get here, the JPEG code has signaled an error.
533     * We need to clean up the JPEG object, close the input file, and return.
534     */
535    jpeg_destroy_decompress(&cinfo);
536    RELEASE_ARRAYS(env, &jsrc);
537    if (!(*env)->ExceptionOccurred(env)) {
538        char buffer[JMSG_LENGTH_MAX];
539        (*cinfo.err->format_message) ((struct jpeg_common_struct *) &cinfo,
540                                      buffer);
541        JNU_ThrowByName(env, "sun/awt/image/ImageFormatException", buffer);
542    }
543    return;
544  }
545  /* Now we can initialize the JPEG decompression object. */
546  jpeg_create_decompress(&cinfo);
547
548  /* Step 2: specify data source (eg, a file) */
549
550  cinfo.src = &jsrc.pub;
551  jsrc.hInputStream = hInputStream;
552  jsrc.hInputBuffer = hInputBuffer;
553  jsrc.hOutputBuffer = 0;
554  jsrc.suspendable = FALSE;
555  jsrc.remaining_skip = 0;
556  jsrc.inbufoffset = -1;
557  jsrc.pub.init_source = sun_jpeg_init_source;
558  jsrc.pub.fill_input_buffer = sun_jpeg_fill_input_buffer;
559  jsrc.pub.skip_input_data = sun_jpeg_skip_input_data;
560  jsrc.pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
561  jsrc.pub.term_source = sun_jpeg_term_source;
562  if (!GET_ARRAYS(env, &jsrc)) {
563    jpeg_destroy_decompress(&cinfo);
564    return;
565  }
566  /* Step 3: read file parameters with jpeg_read_header() */
567
568  (void) jpeg_read_header(&cinfo, TRUE);
569  /* select buffered-image mode if it is a progressive JPEG only */
570  buffered_mode = cinfo.buffered_image = jpeg_has_multiple_scans(&cinfo);
571  grayscale = (cinfo.out_color_space == JCS_GRAYSCALE);
572#ifdef YCCALPHA
573  hasalpha = (cinfo.out_color_space == JCS_RGBA);
574#else
575  hasalpha = 0;
576#endif
577  /* We can ignore the return value from jpeg_read_header since
578   *   (a) suspension is not possible with the stdio data source, and
579   *                                    (nor with the Java input source)
580   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
581   * See libjpeg.doc for more info.
582   */
583  RELEASE_ARRAYS(env, &jsrc);
584  ret = (*env)->CallBooleanMethod(env, this, sendHeaderInfoID,
585                                  cinfo.image_width, cinfo.image_height,
586                                  grayscale, hasalpha, buffered_mode);
587  if ((*env)->ExceptionOccurred(env) || !ret) {
588    /* No more interest in this image... */
589    jpeg_destroy_decompress(&cinfo);
590    return;
591  }
592  /* Make a one-row-high sample array with enough room to expand to ints */
593  if (grayscale) {
594      jsrc.hOutputBuffer = (*env)->NewByteArray(env, cinfo.image_width);
595  } else {
596      jsrc.hOutputBuffer = (*env)->NewIntArray(env, cinfo.image_width);
597  }
598
599  if (jsrc.hOutputBuffer == 0 || !GET_ARRAYS(env, &jsrc)) {
600    jpeg_destroy_decompress(&cinfo);
601    return;
602  }
603
604  /* Step 4: set parameters for decompression */
605
606  /* In this example, we don't need to change any of the defaults set by
607   * jpeg_read_header(), so we do nothing here.
608   */
609  /* For the first pass for Java, we want to deal with RGB for simplicity */
610  /* Unfortunately, the JPEG code does not automatically convert Grayscale */
611  /* to RGB, so we have to deal with Grayscale explicitly. */
612  if (!grayscale && !hasalpha) {
613      cinfo.out_color_space = JCS_RGB;
614  }
615
616  /* Step 5: Start decompressor */
617
618  jpeg_start_decompress(&cinfo);
619
620  /* We may need to do some setup of our own at this point before reading
621   * the data.  After jpeg_start_decompress() we have the correct scaled
622   * output image dimensions available, as well as the output colormap
623   * if we asked for color quantization.
624   */
625
626  /* Step 6: while (scan lines remain to be read) */
627  /*           jpeg_read_scanlines(...); */
628
629  /* Here we use the library's state variable cinfo.output_scanline as the
630   * loop counter, so that we don't have to keep track ourselves.
631   */
632  if (buffered_mode) {
633      final_pass = FALSE;
634      cinfo.dct_method = JDCT_IFAST;
635  } else {
636      final_pass = TRUE;
637  }
638  do {
639      if (buffered_mode) {
640          do {
641              sun_jpeg_fill_suspended_buffer(&cinfo);
642              jsrc.suspendable = TRUE;
643              ret = jpeg_consume_input(&cinfo);
644              jsrc.suspendable = FALSE;
645          } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI);
646          if (ret == JPEG_REACHED_EOI) {
647              final_pass = TRUE;
648              cinfo.dct_method = JDCT_ISLOW;
649          }
650          jpeg_start_output(&cinfo, cinfo.input_scan_number);
651      }
652      while (cinfo.output_scanline < cinfo.output_height) {
653          if (! final_pass) {
654              do {
655                  sun_jpeg_fill_suspended_buffer(&cinfo);
656                  jsrc.suspendable = TRUE;
657                  ret = jpeg_consume_input(&cinfo);
658                  jsrc.suspendable = FALSE;
659              } while (ret != JPEG_SUSPENDED && ret != JPEG_REACHED_EOI);
660              if (ret == JPEG_REACHED_EOI) {
661                  break;
662              }
663          }
664          (void) jpeg_read_scanlines(&cinfo, (JSAMPARRAY) &(jsrc.outbuf), 1);
665
666          if (grayscale) {
667              RELEASE_ARRAYS(env, &jsrc);
668              ret = (*env)->CallBooleanMethod(env, this, sendPixelsByteID,
669                                              jsrc.hOutputBuffer,
670                                              cinfo.output_scanline - 1);
671          } else {
672              if (hasalpha) {
673                  ip = jsrc.outbuf.ip + jsrc.outbufSize;
674                  bp = jsrc.outbuf.bp + jsrc.outbufSize * 4;
675                  while (ip > jsrc.outbuf.ip) {
676                      pixel = (*--bp) << 24;
677                      pixel |= (*--bp);
678                      pixel |= (*--bp) << 8;
679                      pixel |= (*--bp) << 16;
680                      *--ip = pixel;
681                  }
682              } else {
683                  ip = jsrc.outbuf.ip + jsrc.outbufSize;
684                  bp = jsrc.outbuf.bp + jsrc.outbufSize * 3;
685                  while (ip > jsrc.outbuf.ip) {
686                      pixel = (*--bp);
687                      pixel |= (*--bp) << 8;
688                      pixel |= (*--bp) << 16;
689                      *--ip = pixel;
690                  }
691              }
692              RELEASE_ARRAYS(env, &jsrc);
693              ret = (*env)->CallBooleanMethod(env, this, sendPixelsIntID,
694                                              jsrc.hOutputBuffer,
695                                              cinfo.output_scanline - 1);
696          }
697          if ((*env)->ExceptionOccurred(env) || !ret ||
698              !GET_ARRAYS(env, &jsrc)) {
699              /* No more interest in this image... */
700              jpeg_destroy_decompress(&cinfo);
701              return;
702          }
703      }
704      if (buffered_mode) {
705          jpeg_finish_output(&cinfo);
706      }
707  } while (! final_pass);
708
709  /* Step 7: Finish decompression */
710
711  (void) jpeg_finish_decompress(&cinfo);
712  /* We can ignore the return value since suspension is not possible
713   * with the stdio data source.
714   * (nor with the Java data source)
715   */
716
717  /* Step 8: Release JPEG decompression object */
718
719  /* This is an important step since it will release a good deal of memory. */
720  jpeg_destroy_decompress(&cinfo);
721
722  /* After finish_decompress, we can close the input file.
723   * Here we postpone it until after no more JPEG errors are possible,
724   * so as to simplify the setjmp error logic above.  (Actually, I don't
725   * think that jpeg_destroy can do an error exit, but why assume anything...)
726   */
727  /* Not needed for Java - the Java code will close the file */
728  /* fclose(infile); */
729
730  /* At this point you may want to check to see whether any corrupt-data
731   * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
732   */
733
734  /* And we're done! */
735
736  RELEASE_ARRAYS(env, &jsrc);
737  return;
738}
739
740/*
741 * SOME FINE POINTS:
742 *
743 * In the above code, we ignored the return value of jpeg_read_scanlines,
744 * which is the number of scanlines actually read.  We could get away with
745 * this because we asked for only one line at a time and we weren't using
746 * a suspending data source.  See libjpeg.doc for more info.
747 *
748 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
749 * we should have done it beforehand to ensure that the space would be
750 * counted against the JPEG max_memory setting.  In some systems the above
751 * code would risk an out-of-memory error.  However, in general we don't
752 * know the output image dimensions before jpeg_start_decompress(), unless we
753 * call jpeg_calc_output_dimensions().  See libjpeg.doc for more about this.
754 *
755 * Scanlines are returned in the same order as they appear in the JPEG file,
756 * which is standardly top-to-bottom.  If you must emit data bottom-to-top,
757 * you can use one of the virtual arrays provided by the JPEG memory manager
758 * to invert the data.  See wrbmp.c for an example.
759 *
760 * As with compression, some operating modes may require temporary files.
761 * On some systems you may need to set up a signal handler to ensure that
762 * temporary files are deleted if the program is interrupted.  See libjpeg.doc.
763 */
764