0N/A/*
2362N/A * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include <stdio.h>
0N/A#include "jni.h"
0N/A#include "jni_util.h"
0N/A
0N/A#define OUTCODELENGTH 4097
0N/A
0N/A/* We use Get/ReleasePrimitiveArrayCritical functions to avoid
0N/A * the need to copy buffer elements.
0N/A *
0N/A * MAKE SURE TO:
0N/A *
0N/A * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around
0N/A * callbacks to Java.
0N/A * - call RELEASE_ARRAYS before returning to Java.
0N/A *
0N/A * Otherwise things will go horribly wrong. There may be memory leaks,
0N/A * excessive pinning, or even VM crashes!
0N/A *
0N/A * Note that GetPrimitiveArrayCritical may fail!
0N/A */
0N/A
0N/A#define GET_ARRAYS() \
0N/A prefix = (short *) \
0N/A (*env)->GetPrimitiveArrayCritical(env, prefixh, 0); \
0N/A if (prefix == 0) \
0N/A goto out_of_memory; \
0N/A suffix = (unsigned char *) \
0N/A (*env)->GetPrimitiveArrayCritical(env, suffixh, 0); \
0N/A if (suffix == 0) \
0N/A goto out_of_memory; \
0N/A outCode = (unsigned char *) \
0N/A (*env)->GetPrimitiveArrayCritical(env, outCodeh, 0); \
0N/A if (outCode == 0) \
0N/A goto out_of_memory; \
0N/A rasline = (unsigned char *) \
0N/A (*env)->GetPrimitiveArrayCritical(env, raslineh, 0); \
0N/A if (rasline == 0) \
0N/A goto out_of_memory; \
0N/A block = (unsigned char *) \
0N/A (*env)->GetPrimitiveArrayCritical(env, blockh, 0); \
0N/A if (block == 0) \
0N/A goto out_of_memory
0N/A
0N/A/*
0N/A * Note that it is important to check whether the arrays are NULL,
0N/A * because GetPrimitiveArrayCritical might have failed.
0N/A */
0N/A#define RELEASE_ARRAYS() \
0N/Aif (prefix) \
0N/A (*env)->ReleasePrimitiveArrayCritical(env, prefixh, prefix, 0); \
0N/Aif (suffix) \
0N/A (*env)->ReleasePrimitiveArrayCritical(env, suffixh, suffix, 0); \
0N/Aif (outCode) \
0N/A (*env)->ReleasePrimitiveArrayCritical(env, outCodeh, outCode, 0); \
0N/Aif (rasline) \
0N/A (*env)->ReleasePrimitiveArrayCritical(env, raslineh, rasline, 0); \
0N/Aif (block) \
0N/A (*env)->ReleasePrimitiveArrayCritical(env, blockh, block, 0)
0N/A
0N/A/* Place holders for the old native interface. */
0N/A
0N/Along
0N/Asun_awt_image_GifImageDecoder_parseImage()
0N/A{
0N/A return 0;
0N/A}
0N/A
0N/Avoid
0N/Asun_awt_image_GifImageDecoder_initIDs()
0N/A{
0N/A}
0N/A
0N/Astatic jmethodID readID;
0N/Astatic jmethodID sendID;
0N/Astatic jfieldID prefixID;
0N/Astatic jfieldID suffixID;
0N/Astatic jfieldID outCodeID;
0N/A
0N/AJNIEXPORT void JNICALL
0N/AJava_sun_awt_image_GifImageDecoder_initIDs(JNIEnv *env, jclass this)
0N/A{
0N/A readID = (*env)->GetMethodID(env, this, "readBytes", "([BII)I");
0N/A sendID = (*env)->GetMethodID(env, this, "sendPixels",
0N/A "(IIII[BLjava/awt/image/ColorModel;)I");
0N/A prefixID = (*env)->GetFieldID(env, this, "prefix", "[S");
0N/A suffixID = (*env)->GetFieldID(env, this, "suffix", "[B");
0N/A outCodeID = (*env)->GetFieldID(env, this, "outCode", "[B");
0N/A}
0N/A
0N/AJNIEXPORT jboolean JNICALL
0N/AJava_sun_awt_image_GifImageDecoder_parseImage(JNIEnv *env,
0N/A jobject this,
0N/A jint relx, jint rely,
0N/A jint width, jint height,
0N/A jint interlace,
0N/A jint initCodeSize,
0N/A jbyteArray blockh,
0N/A jbyteArray raslineh,
0N/A jobject cmh)
0N/A{
0N/A /* Patrick Naughton:
0N/A * Note that I ignore the possible existence of a local color map.
0N/A * I'm told there aren't many files around that use them, and the
0N/A * spec says it's defined for future use. This could lead to an
0N/A * error reading some files.
0N/A *
0N/A * Start reading the image data. First we get the intial code size
0N/A * and compute decompressor constant values, based on this code
0N/A * size.
0N/A *
0N/A * The GIF spec has it that the code size is the code size used to
0N/A * compute the above values is the code size given in the file,
0N/A * but the code size used in compression/decompression is the code
0N/A * size given in the file plus one. (thus the ++).
0N/A *
0N/A * Arthur van Hoff:
0N/A * The following narly code reads LZW compressed data blocks and
0N/A * dumps it into the image data. The input stream is broken up into
0N/A * blocks of 1-255 characters, each preceded by a length byte.
0N/A * 3-12 bit codes are read from these blocks. The codes correspond to
0N/A * entry is the hashtable (the prefix, suffix stuff), and the appropriate
0N/A * pixels are written to the image.
0N/A */
0N/A static int verbose = 0;
0N/A
0N/A int clearCode = (1 << initCodeSize);
0N/A int eofCode = clearCode + 1;
0N/A int bitMask;
0N/A int curCode;
0N/A int outCount;
0N/A
0N/A /* Variables used to form reading data */
0N/A int blockEnd = 0;
0N/A int remain = 0;
0N/A int byteoff = 0;
0N/A int accumbits = 0;
0N/A int accumdata = 0;
0N/A
0N/A /* Variables used to decompress the data */
0N/A int codeSize = initCodeSize + 1;
0N/A int maxCode = 1 << codeSize;
0N/A int codeMask = maxCode - 1;
0N/A int freeCode = clearCode + 2;
0N/A int code = 0;
0N/A int oldCode = 0;
0N/A unsigned char prevChar = 0;
0N/A
0N/A /* Temproray storage for decompression */
0N/A short *prefix;
0N/A unsigned char *suffix = NULL;
0N/A unsigned char *outCode = NULL;
0N/A unsigned char *rasline = NULL;
0N/A unsigned char *block = NULL;
0N/A
0N/A jshortArray prefixh = (*env)->GetObjectField(env, this, prefixID);
0N/A jbyteArray suffixh = (*env)->GetObjectField(env, this, suffixID);
0N/A jbyteArray outCodeh = (*env)->GetObjectField(env, this, outCodeID);
0N/A
0N/A int blockLength = 0;
0N/A
0N/A /* Variables used for writing pixels */
0N/A int x = width;
0N/A int y = 0;
0N/A int off = 0;
0N/A int passinc = interlace ? 8 : 1;
0N/A int passht = passinc;
0N/A int len;
0N/A
1125N/A /* We have verified the initial code size on the java layer.
1125N/A * Here we just check bounds for particular indexes. */
1125N/A if (freeCode >= 4096 || maxCode >= 4096) {
1125N/A return 0;
1125N/A }
0N/A if (blockh == 0 || raslineh == 0
0N/A || prefixh == 0 || suffixh == 0
0N/A || outCodeh == 0)
0N/A {
0N/A JNU_ThrowNullPointerException(env, 0);
0N/A return 0;
0N/A }
0N/A if (((*env)->GetArrayLength(env, prefixh) != 4096) ||
0N/A ((*env)->GetArrayLength(env, suffixh) != 4096) ||
0N/A ((*env)->GetArrayLength(env, outCodeh) != OUTCODELENGTH))
0N/A {
0N/A JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
0N/A return 0;
0N/A }
0N/A
0N/A if (verbose) {
0N/A fprintf(stdout, "Decompressing...");
0N/A }
0N/A
0N/A /* Fix for bugid 4216605 Some animated GIFs display corrupted. */
0N/A bitMask = clearCode - 1;
0N/A
0N/A GET_ARRAYS();
0N/A
0N/A /* Read codes until the eofCode is encountered */
0N/A for (;;) {
0N/A if (accumbits < codeSize) {
0N/A /* fill the buffer if needed */
0N/A while (remain < 2) {
0N/A if (blockEnd) {
0N/A /* Sometimes we have one last byte to process... */
0N/A if (remain == 1 && accumbits + 8 >= codeSize) {
0N/A remain--;
0N/A goto last_byte;
0N/A }
0N/A RELEASE_ARRAYS();
0N/A if (off > 0) {
0N/A (*env)->CallIntMethod(env, this, sendID,
0N/A relx, rely + y,
0N/A width, passht,
0N/A raslineh, cmh);
0N/A }
0N/A /* quietly accept truncated GIF images */
0N/A return 1;
0N/A }
0N/A /* move remaining bytes to the beginning of the buffer */
0N/A block[0] = block[byteoff];
0N/A byteoff = 0;
0N/A
0N/A RELEASE_ARRAYS();
0N/A /* fill the block */
0N/A len = (*env)->CallIntMethod(env, this, readID,
0N/A blockh, remain, blockLength + 1);
0N/A if ((*env)->ExceptionOccurred(env)) {
0N/A return 0;
0N/A }
0N/A GET_ARRAYS();
0N/A
0N/A remain += blockLength;
0N/A if (len > 0) {
0N/A remain -= (len - 1);
0N/A blockLength = 0;
0N/A } else {
0N/A blockLength = block[remain];
0N/A }
0N/A if (blockLength == 0) {
0N/A blockEnd = 1;
0N/A }
0N/A }
0N/A remain -= 2;
0N/A
0N/A /* 2 bytes at a time saves checking for accumbits < codeSize.
0N/A * We know we'll get enough and also that we can't overflow
0N/A * since codeSize <= 12.
0N/A */
0N/A accumdata += (block[byteoff++] & 0xff) << accumbits;
0N/A accumbits += 8;
0N/A last_byte:
0N/A accumdata += (block[byteoff++] & 0xff) << accumbits;
0N/A accumbits += 8;
0N/A }
0N/A
0N/A /* Compute the code */
0N/A code = accumdata & codeMask;
0N/A accumdata >>= codeSize;
0N/A accumbits -= codeSize;
0N/A
0N/A /*
0N/A * Interpret the code
0N/A */
0N/A if (code == clearCode) {
0N/A /* Clear code sets everything back to its initial value, then
0N/A * reads the immediately subsequent code as uncompressed data.
0N/A */
0N/A if (verbose) {
0N/A fprintf(stdout, ".");
0N/A fflush(stdout);
0N/A }
0N/A
0N/A /* Note that freeCode is one less than it is supposed to be,
0N/A * this is because it will be incremented next time round the loop
0N/A */
0N/A freeCode = clearCode + 1;
0N/A codeSize = initCodeSize + 1;
0N/A maxCode = 1 << codeSize;
0N/A codeMask = maxCode - 1;
0N/A
0N/A /* Continue if we've NOT reached the end, some Gif images
0N/A * contain bogus codes after the last clear code.
0N/A */
0N/A if (y < height) {
0N/A continue;
0N/A }
0N/A
0N/A /* pretend we've reached the end of the data */
0N/A code = eofCode;
0N/A }
0N/A
0N/A if (code == eofCode) {
0N/A /* make sure we read the whole block of pixels. */
0N/A flushit:
0N/A while (!blockEnd) {
0N/A if (verbose) {
0N/A fprintf(stdout, "flushing %d bytes\n", blockLength);
0N/A }
0N/A RELEASE_ARRAYS();
0N/A if ((*env)->CallIntMethod(env, this, readID,
0N/A blockh, 0, blockLength + 1) != 0
0N/A || (*env)->ExceptionOccurred(env))
0N/A {
0N/A /* quietly accept truncated GIF images */
0N/A return (!(*env)->ExceptionOccurred(env));
0N/A }
0N/A GET_ARRAYS();
0N/A blockLength = block[blockLength];
0N/A blockEnd = (blockLength == 0);
0N/A }
0N/A RELEASE_ARRAYS();
0N/A return 1;
0N/A }
0N/A
0N/A /* It must be data: save code in CurCode */
0N/A curCode = code;
0N/A outCount = OUTCODELENGTH;
0N/A
0N/A /* If greater or equal to freeCode, not in the hash table
0N/A * yet; repeat the last character decoded
0N/A */
0N/A if (curCode >= freeCode) {
0N/A if (curCode > freeCode) {
0N/A /*
0N/A * if we get a code too far outside our range, it
0N/A * could case the parser to start traversing parts
0N/A * of our data structure that are out of range...
0N/A */
0N/A goto flushit;
0N/A }
0N/A curCode = oldCode;
0N/A outCode[--outCount] = prevChar;
0N/A }
0N/A
0N/A /* Unless this code is raw data, pursue the chain pointed
0N/A * to by curCode through the hash table to its end; each
0N/A * code in the chain puts its associated output code on
0N/A * the output queue.
0N/A */
0N/A while (curCode > bitMask) {
0N/A outCode[--outCount] = suffix[curCode];
0N/A if (outCount == 0) {
0N/A /*
0N/A * In theory this should never happen since our
0N/A * prefix and suffix arrays are monotonically
0N/A * decreasing and so outCode will only be filled
0N/A * as much as those arrays, but I don't want to
0N/A * take that chance and the test is probably
0N/A * cheap compared to the read and write operations.
0N/A * If we ever do overflow the array, we will just
0N/A * flush the rest of the data and quietly accept
0N/A * the GIF as truncated here.
0N/A */
0N/A goto flushit;
0N/A }
0N/A curCode = prefix[curCode];
0N/A }
0N/A
0N/A /* The last code in the chain is treated as raw data. */
0N/A prevChar = (unsigned char)curCode;
0N/A outCode[--outCount] = prevChar;
0N/A
0N/A /* Now we put the data out to the Output routine. It's
0N/A * been stacked LIFO, so deal with it that way...
0N/A *
0N/A * Note that for some malformed images we have to skip
0N/A * current frame and continue with rest of data
0N/A * because we may have not enough info to interpret
0N/A * corrupted frame correctly.
0N/A * However, we can not skip frame without decoding it
0N/A * and therefore we have to continue looping through data
0N/A * but skip internal output loop.
0N/A *
0N/A * In particular this is is possible when
0N/A * width of the frame is set to zero. If
0N/A * global width (i.e. width of the logical screen)
0N/A * is zero too then zero-length scanline buffer
0N/A * is allocated in java code and we have no buffer to
0N/A * store decoded data in.
0N/A */
0N/A len = OUTCODELENGTH - outCount;
0N/A while ((width > 0) && (--len >= 0)) {
0N/A rasline[off++] = outCode[outCount++];
0N/A
0N/A /* Update the X-coordinate, and if it overflows, update the
0N/A * Y-coordinate
0N/A */
0N/A if (--x == 0) {
0N/A /* If a non-interlaced picture, just increment y to the next
0N/A * scan line. If it's interlaced, deal with the interlace as
0N/A * described in the GIF spec. Put the decoded scan line out
0N/A * to the screen if we haven't gone past the bottom of it
0N/A */
0N/A int count;
0N/A RELEASE_ARRAYS();
0N/A count = (*env)->CallIntMethod(env, this, sendID,
0N/A relx, rely + y,
0N/A width, passht,
0N/A raslineh, cmh);
0N/A if (count <= 0 || (*env)->ExceptionOccurred(env)) {
0N/A /* Nobody is listening any more. */
0N/A if (verbose) {
0N/A fprintf(stdout, "Orphan gif decoder quitting\n");
0N/A }
0N/A return 0;
0N/A }
0N/A GET_ARRAYS();
0N/A x = width;
0N/A off = 0;
0N/A /* pass inc ht ystart */
0N/A /* 0 8 8 0 */
0N/A /* 1 8 4 4 */
0N/A /* 2 4 2 2 */
0N/A /* 3 2 1 1 */
0N/A y += passinc;
0N/A while (y >= height) {
0N/A passinc = passht;
0N/A passht >>= 1;
0N/A y = passht;
0N/A if (passht == 0) {
0N/A goto flushit;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /* Build the hash table on-the-fly. No table is stored in the file. */
0N/A prefix[freeCode] = (short)oldCode;
0N/A suffix[freeCode] = prevChar;
0N/A oldCode = code;
0N/A
0N/A /* Point to the next slot in the table. If we exceed the
0N/A * maxCode, increment the code size unless
0N/A * it's already 12. If it is, do nothing: the next code
0N/A * decompressed better be CLEAR
0N/A */
0N/A if (++freeCode >= maxCode) {
0N/A if (codeSize < 12) {
0N/A codeSize++;
0N/A maxCode <<= 1;
0N/A codeMask = maxCode - 1;
0N/A } else {
0N/A /* Just in case */
0N/A freeCode = maxCode - 1;
0N/A }
0N/A }
0N/A }
0N/Aout_of_memory:
0N/A RELEASE_ARRAYS();
0N/A return 0;
0N/A}