Bug Summary

File:jdk/src/java.desktop/share/native/libjavajpeg/jpegdecoder.c
Warning:line 368, column 28
Array access (via field 'inbuf') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name jpegdecoder.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -D LIBC=gnu -D _GNU_SOURCE -D _REENTRANT -D _LARGEFILE64_SOURCE -D LINUX -D DEBUG -D _LITTLE_ENDIAN -D ARCH="amd64" -D amd64 -D _LP64=1 -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libjavajpeg -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/java.desktop -D _FORTIFY_SOURCE=2 -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-unused -Wno-clobbered -Wno-implicit-fallthrough -Wno-shift-negative-value -Wno-array-bounds -std=c99 -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libjavajpeg/jpegdecoder.c
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 *the_jvm;
68
69JNIEXPORT__attribute__((visibility("default"))) jint JNICALL
70DEF_JNI_OnLoadJNI_OnLoad(JavaVM *vm, void *reserved)
71{
72 the_jvm = vm;
73 return JNI_VERSION_1_20x00010002;
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)static 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)static void
134sun_jpeg_output_message (j_common_ptr cinfo)
135{
136 char buffer[JMSG_LENGTH_MAX200];
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)__fprintf_chk (stderr, 2 - 1, "%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) {
26
Assuming field 'inbuf' is null
27
Taking false branch
43
Assuming field 'inbuf' is non-null
44
Taking true branch
206 if (src->pub.next_input_byte == 0) {
45
Assuming field 'next_input_byte' is equal to null
46
Taking true branch
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;
47
Null pointer value stored to field 'inbuf'
214 }
215 if (src->outbuf.ip) {
28
Assuming field 'ip' is null
29
Taking false branch
48
Assuming field 'ip' is null
49
Taking false branch
216 (*env)->ReleasePrimitiveArrayCritical(env, src->hOutputBuffer,
217 src->outbuf.ip, 0);
218 src->outbuf.ip = 0;
219 }
220}
30
Returning without writing to 'src->inbuf'
221
222static int GET_ARRAYS(JNIEnv *env, sun_jpeg_source_ptr src)
223{
224 if (src->hOutputBuffer) {
225 assert(src->outbuf.ip == 0)((src->outbuf.ip == 0) ? (void) (0) : __assert_fail ("src->outbuf.ip == 0"
, "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libjavajpeg/jpegdecoder.c"
, 225, __extension__ __PRETTY_FUNCTION__))
;
226 src->outbufSize = (*env)->GetArrayLength(env, src->hOutputBuffer);
227 src->outbuf.ip = (int *)(*env)->GetPrimitiveArrayCritical
228 (env, src->hOutputBuffer, 0);
229 if (src->outbuf.ip == 0) {
230 return 0;
231 }
232 }
233 if (src->hInputBuffer) {
234 assert(src->inbuf == 0)((src->inbuf == 0) ? (void) (0) : __assert_fail ("src->inbuf == 0"
, "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libjavajpeg/jpegdecoder.c"
, 234, __extension__ __PRETTY_FUNCTION__))
;
235 src->inbuf = (JOCTET *)(*env)->GetPrimitiveArrayCritical
236 (env, src->hInputBuffer, 0);
237 if (src->inbuf == 0) {
238 RELEASE_ARRAYS(env, src);
239 return 0;
240 }
241 if ((int)(src->inbufoffset) >= 0) {
242 src->pub.next_input_byte = src->inbuf + src->inbufoffset;
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)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)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(the_jvm, JNI_VERSION_1_20x00010002);
288 int ret, buflen;
289
290 if (src->suspendable) {
291 return FALSE0;
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)((cinfo)->err->msg_code = (JWRN_JPEG_EOF), (*(cinfo)->
err->emit_message) ((j_common_ptr) (cinfo), -1))
;
307 src->inbuf[0] = (JOCTET) 0xFF;
308 src->inbuf[1] = (JOCTET) JPEG_EOI0xD9;
309 ret = 2;
310 }
311
312 src->pub.next_input_byte = src->inbuf;
313 src->pub.bytes_in_buffer = ret;
314
315 return TRUE1;
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)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(the_jvm, JNI_VERSION_1_20x00010002);
331 size_t offset, buflen;
332 int ret;
333
334 RELEASE_ARRAYS(env, src);
25
Calling 'RELEASE_ARRAYS'
31
Returning from 'RELEASE_ARRAYS'
335 ret = (*env)->CallIntMethod(env, src->hInputStream,
336 InputStream_availableID);
337 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) {
32
Assuming the condition is false
33
Assuming the condition is false
34
Taking false branch
338 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
339 }
340 if (ret < 0 || (unsigned int)ret <= src->remaining_skip) {
35
Assuming 'ret' is >= 0
36
Assuming 'ret' is > field 'remaining_skip'
37
Taking false branch
341 return;
342 }
343 if (src->remaining_skip) {
38
Assuming field 'remaining_skip' is 0
39
Taking false branch
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) {
40
Assuming field 'next_input_byte' is <= field 'inbuf'
41
Taking false branch
349 memmove(src->inbuf, src->pub.next_input_byte, offset);
350 }
351 RELEASE_ARRAYS(env, src);
42
Calling 'RELEASE_ARRAYS'
50
Returning from 'RELEASE_ARRAYS'
352 buflen = (*env)->GetArrayLength(env, src->hInputBuffer) - offset;
353 if (buflen <= 0) {
51
Assuming 'buflen' is > 0
52
Taking false branch
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;
53
Assuming 'ret' is <= 0
362 if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) {
54
Assuming the condition is true
363 cinfo->err->error_exit((struct jpeg_common_struct *) cinfo);
364 }
365 if (ret
54.1
'ret' is <= 0
<= 0) {
55
Taking true branch
366 /* Silently accept truncated JPEG files */
367 WARNMS(cinfo, JWRN_JPEG_EOF)((cinfo)->err->msg_code = (JWRN_JPEG_EOF), (*(cinfo)->
err->emit_message) ((j_common_ptr) (cinfo), -1))
;
368 src->inbuf[offset] = (JOCTET) 0xFF;
56
Array access (via field 'inbuf') results in a null pointer dereference
369 src->inbuf[offset + 1] = (JOCTET) JPEG_EOI0xD9;
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)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(the_jvm, JNI_VERSION_1_20x00010002);
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)((cinfo)->err->msg_code = (JWRN_JPEG_EOF), (*(cinfo)->
err->emit_message) ((j_common_ptr) (cinfo), -1))
;
452 src->inbuf[0] = (JOCTET) 0xFF;
453 src->inbuf[1] = (JOCTET) JPEG_EOI0xD9;
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)void
468sun_jpeg_term_source(j_decompress_ptr cinfo)
469{
470}
471
472JNIEXPORT__attribute__((visibility("default"))) 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",do { if ((sendHeaderInfoID = (*env)->GetMethodID(env, cls,
"sendHeaderInfo", "(IIZZZ)Z")) == ((void*)0)) { return; } } while
(0)
477 "(IIZZZ)Z"))do { if ((sendHeaderInfoID = (*env)->GetMethodID(env, cls,
"sendHeaderInfo", "(IIZZZ)Z")) == ((void*)0)) { return; } } while
(0)
;
478 CHECK_NULL(sendPixelsByteID = (*env)->GetMethodID(env, cls, "sendPixels", "([BI)Z"))do { if ((sendPixelsByteID = (*env)->GetMethodID(env, cls,
"sendPixels", "([BI)Z")) == ((void*)0)) { return; } } while (
0)
;
479 CHECK_NULL(sendPixelsIntID = (*env)->GetMethodID(env, cls, "sendPixels", "([II)Z"))do { if ((sendPixelsIntID = (*env)->GetMethodID(env, cls, "sendPixels"
, "([II)Z")) == ((void*)0)) { return; } } while (0)
;
480 CHECK_NULL(InputStream_readID = (*env)->GetMethodID(env, InputStreamClass,do { if ((InputStream_readID = (*env)->GetMethodID(env, InputStreamClass
, "read", "([BII)I")) == ((void*)0)) { return; } } while (0)
481 "read", "([BII)I"))do { if ((InputStream_readID = (*env)->GetMethodID(env, InputStreamClass
, "read", "([BII)I")) == ((void*)0)) { return; } } while (0)
;
482 CHECK_NULL(InputStream_availableID = (*env)->GetMethodID(env, InputStreamClass,do { if ((InputStream_availableID = (*env)->GetMethodID(env
, InputStreamClass, "available", "()I")) == ((void*)0)) { return
; } } while (0)
483 "available", "()I"))do { if ((InputStream_availableID = (*env)->GetMethodID(env
, InputStreamClass, "available", "()I")) == ((void*)0)) { return
; } } while (0)
;
484}
485
486JNIEXPORT__attribute__((visibility("default"))) 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) {
1
Assuming 'hInputBuffer' is not equal to null
2
Assuming 'hInputStream' is not equal to null
3
Taking false branch
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_errorjStdError(&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)_setjmp (jerr.setjmp_buffer)) {
4
Assuming the condition is false
5
Taking false branch
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_decompressjDestDecompress(&cinfo);
536 RELEASE_ARRAYS(env, &jsrc);
537 if (!(*env)->ExceptionOccurred(env)) {
538 char buffer[JMSG_LENGTH_MAX200];
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)jCreaDecompress((&cinfo), 62, (size_t) sizeof(struct jpeg_decompress_struct
))
;
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 = FALSE0;
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_restartjResyncRestart; /* use default method */
561 jsrc.pub.term_source = sun_jpeg_term_source;
562 if (!GET_ARRAYS(env, &jsrc)) {
6
Taking false branch
563 jpeg_destroy_decompressjDestDecompress(&cinfo);
564 return;
565 }
566 /* Step 3: read file parameters with jpeg_read_header() */
567
568 (void) jpeg_read_headerjReadHeader(&cinfo, TRUE1);
569 /* select buffered-image mode if it is a progressive JPEG only */
570 buffered_mode = cinfo.buffered_image = jpeg_has_multiple_scansjHasMultScn(&cinfo);
571 grayscale = (cinfo.out_color_space == JCS_GRAYSCALE);
7
Assuming field 'out_color_space' is not equal to JCS_GRAYSCALE
572 hasalpha = 0;
573 /* We can ignore the return value from jpeg_read_header since
574 * (a) suspension is not possible with the stdio data source, and
575 * (nor with the Java input source)
576 * (b) we passed TRUE to reject a tables-only JPEG file as an error.
577 * See libjpeg.doc for more info.
578 */
579 RELEASE_ARRAYS(env, &jsrc);
580 ret = (*env)->CallBooleanMethod(env, this, sendHeaderInfoID,
581 cinfo.image_width, cinfo.image_height,
582 grayscale, hasalpha, buffered_mode);
583 if ((*env)->ExceptionOccurred(env) || !ret) {
8
Assuming the condition is false
9
Assuming 'ret' is not equal to 0
10
Taking false branch
584 /* No more interest in this image... */
585 jpeg_destroy_decompressjDestDecompress(&cinfo);
586 return;
587 }
588 /* Make a one-row-high sample array with enough room to expand to ints */
589 if (grayscale
10.1
'grayscale' is 0
) {
11
Taking false branch
590 jsrc.hOutputBuffer = (*env)->NewByteArray(env, cinfo.image_width);
591 } else {
592 jsrc.hOutputBuffer = (*env)->NewIntArray(env, cinfo.image_width);
593 }
594
595 if (jsrc.hOutputBuffer == 0 || !GET_ARRAYS(env, &jsrc)) {
12
Assuming field 'hOutputBuffer' is not equal to null
13
Taking false branch
596 jpeg_destroy_decompressjDestDecompress(&cinfo);
597 return;
598 }
599
600 /* Step 4: set parameters for decompression */
601
602 /* In this example, we don't need to change any of the defaults set by
603 * jpeg_read_header(), so we do nothing here.
604 */
605 /* For the first pass for Java, we want to deal with RGB for simplicity */
606 /* Unfortunately, the JPEG code does not automatically convert Grayscale */
607 /* to RGB, so we have to deal with Grayscale explicitly. */
608 if (!grayscale
13.1
'grayscale' is 0
&& !hasalpha
13.2
'hasalpha' is 0
) {
14
Taking true branch
609 cinfo.out_color_space = JCS_RGB;
610 }
611
612 /* Step 5: Start decompressor */
613
614 jpeg_start_decompressjStrtDecompress(&cinfo);
615
616 /* We may need to do some setup of our own at this point before reading
617 * the data. After jpeg_start_decompress() we have the correct scaled
618 * output image dimensions available, as well as the output colormap
619 * if we asked for color quantization.
620 */
621
622 /* Step 6: while (scan lines remain to be read) */
623 /* jpeg_read_scanlines(...); */
624
625 /* Here we use the library's state variable cinfo.output_scanline as the
626 * loop counter, so that we don't have to keep track ourselves.
627 */
628 if (buffered_mode) {
15
Assuming 'buffered_mode' is not equal to 0
16
Taking true branch
629 final_pass = FALSE0;
630 cinfo.dct_method = JDCT_IFAST;
631 } else {
632 final_pass = TRUE1;
633 }
634 do {
635 if (buffered_mode
16.1
'buffered_mode' is not equal to 0
) {
17
Taking true branch
636 do {
20
Loop condition is true. Execution continues on line 637
23
Loop condition is true. Execution continues on line 637
637 sun_jpeg_fill_suspended_buffer(&cinfo);
24
Calling 'sun_jpeg_fill_suspended_buffer'
638 jsrc.suspendable = TRUE1;
639 ret = jpeg_consume_inputjConsumeInput(&cinfo);
640 jsrc.suspendable = FALSE0;
641 } while (ret != JPEG_SUSPENDED0 && ret != JPEG_REACHED_EOI2);
18
Assuming 'ret' is not equal to JPEG_SUSPENDED
19
Assuming 'ret' is not equal to JPEG_REACHED_EOI
21
Assuming 'ret' is not equal to JPEG_SUSPENDED
22
Assuming 'ret' is not equal to JPEG_REACHED_EOI
642 if (ret == JPEG_REACHED_EOI2) {
643 final_pass = TRUE1;
644 cinfo.dct_method = JDCT_ISLOW;
645 }
646 jpeg_start_outputjStrtOutput(&cinfo, cinfo.input_scan_number);
647 }
648 while (cinfo.output_scanline < cinfo.output_height) {
649 if (! final_pass) {
650 do {
651 sun_jpeg_fill_suspended_buffer(&cinfo);
652 jsrc.suspendable = TRUE1;
653 ret = jpeg_consume_inputjConsumeInput(&cinfo);
654 jsrc.suspendable = FALSE0;
655 } while (ret != JPEG_SUSPENDED0 && ret != JPEG_REACHED_EOI2);
656 if (ret == JPEG_REACHED_EOI2) {
657 break;
658 }
659 }
660 (void) jpeg_read_scanlinesjReadScanlines(&cinfo, (JSAMPARRAY) &(jsrc.outbuf), 1);
661
662 if (grayscale) {
663 RELEASE_ARRAYS(env, &jsrc);
664 ret = (*env)->CallBooleanMethod(env, this, sendPixelsByteID,
665 jsrc.hOutputBuffer,
666 cinfo.output_scanline - 1);
667 } else {
668 if (hasalpha) {
669 ip = jsrc.outbuf.ip + jsrc.outbufSize;
670 bp = jsrc.outbuf.bp + jsrc.outbufSize * 4;
671 while (ip > jsrc.outbuf.ip) {
672 pixel = (*--bp) << 24;
673 pixel |= (*--bp);
674 pixel |= (*--bp) << 8;
675 pixel |= (*--bp) << 16;
676 *--ip = pixel;
677 }
678 } else {
679 ip = jsrc.outbuf.ip + jsrc.outbufSize;
680 bp = jsrc.outbuf.bp + jsrc.outbufSize * 3;
681 while (ip > jsrc.outbuf.ip) {
682 pixel = (*--bp);
683 pixel |= (*--bp) << 8;
684 pixel |= (*--bp) << 16;
685 *--ip = pixel;
686 }
687 }
688 RELEASE_ARRAYS(env, &jsrc);
689 ret = (*env)->CallBooleanMethod(env, this, sendPixelsIntID,
690 jsrc.hOutputBuffer,
691 cinfo.output_scanline - 1);
692 }
693 if ((*env)->ExceptionOccurred(env) || !ret ||
694 !GET_ARRAYS(env, &jsrc)) {
695 /* No more interest in this image... */
696 jpeg_destroy_decompressjDestDecompress(&cinfo);
697 return;
698 }
699 }
700 if (buffered_mode) {
701 jpeg_finish_outputjFinOutput(&cinfo);
702 }
703 } while (! final_pass);
704
705 /* Step 7: Finish decompression */
706
707 (void) jpeg_finish_decompressjFinDecompress(&cinfo);
708 /* We can ignore the return value since suspension is not possible
709 * with the stdio data source.
710 * (nor with the Java data source)
711 */
712
713 /* Step 8: Release JPEG decompression object */
714
715 /* This is an important step since it will release a good deal of memory. */
716 jpeg_destroy_decompressjDestDecompress(&cinfo);
717
718 /* After finish_decompress, we can close the input file.
719 * Here we postpone it until after no more JPEG errors are possible,
720 * so as to simplify the setjmp error logic above. (Actually, I don't
721 * think that jpeg_destroy can do an error exit, but why assume anything...)
722 */
723 /* Not needed for Java - the Java code will close the file */
724 /* fclose(infile); */
725
726 /* At this point you may want to check to see whether any corrupt-data
727 * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
728 */
729
730 /* And we're done! */
731
732 RELEASE_ARRAYS(env, &jsrc);
733 return;
734}
735
736/*
737 * SOME FINE POINTS:
738 *
739 * In the above code, we ignored the return value of jpeg_read_scanlines,
740 * which is the number of scanlines actually read. We could get away with
741 * this because we asked for only one line at a time and we weren't using
742 * a suspending data source. See libjpeg.doc for more info.
743 *
744 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
745 * we should have done it beforehand to ensure that the space would be
746 * counted against the JPEG max_memory setting. In some systems the above
747 * code would risk an out-of-memory error. However, in general we don't
748 * know the output image dimensions before jpeg_start_decompress(), unless we
749 * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this.
750 *
751 * Scanlines are returned in the same order as they appear in the JPEG file,
752 * which is standardly top-to-bottom. If you must emit data bottom-to-top,
753 * you can use one of the virtual arrays provided by the JPEG memory manager
754 * to invert the data. See wrbmp.c for an example.
755 *
756 * As with compression, some operating modes may require temporary files.
757 * On some systems you may need to set up a signal handler to ensure that
758 * temporary files are deleted if the program is interrupted. See libjpeg.doc.
759 */