10f49c87b2f26f3e086f021461b7e5409a7d42be0Sam Juddpackage com.bumptech.glide.gifdecoder;
24f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
34f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Juddimport android.util.Log;
44f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
54f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Juddimport java.nio.BufferUnderflowException;
64f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Juddimport java.nio.ByteBuffer;
74f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Juddimport java.nio.ByteOrder;
84f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
90f49c87b2f26f3e086f021461b7e5409a7d42be0Sam Juddimport static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR;
104f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
114f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Juddpublic class GifHeaderParser {
124f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    public static final String TAG = "GifHeaderParser";
134f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    /**
144f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * max decoder pixel stack size
154f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
164f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private static final int MAX_STACK_SIZE = 4096;
174f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
184f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private final ByteBuffer rawData;
194f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private GifHeader header = new GifHeader();
204f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
214f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    // Raw data read working array
224f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected byte[] block = new byte[256]; // current data block
234f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected int blockSize = 0; // block size last graphic control extension info
244f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected boolean lctFlag; // local color table flag
254f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected int lctSize; // local color table size
264f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private short[] prefix;
274f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private byte[] suffix;
284f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private byte[] pixelStack;
294f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
304f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    public GifHeaderParser(byte[] data) {
314f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (data != null) {
324f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            rawData = ByteBuffer.wrap(data);
334f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            rawData.rewind();
344f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            rawData.order(ByteOrder.LITTLE_ENDIAN);
354f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        } else {
364f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            rawData = null;
374f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.status = GifDecoder.STATUS_OPEN_ERROR;
384f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
394f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
404f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
414f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    public GifHeader parseHeader() {
424f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (err()) {
434f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            return header;
444f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
454f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
464f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        readHeader();
474f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (!err()) {
484f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            readContents();
494f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            if (header.frameCount < 0) {
504f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                header.status = STATUS_FORMAT_ERROR;
514f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            }
524f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
534f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
544f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        return header;
554f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
564f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
574f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    /**
584f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Main file parser. Reads GIF content blocks.
594f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
604f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void readContents() {
614f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // read GIF file content blocks
624f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        boolean done = false;
634f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        while (!(done || err())) {
644f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            int code = read();
654f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            switch (code) {
664f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                case 0x2C: // image separator
674f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    readBitmap();
684f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    break;
694f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                case 0x21: // extension
704f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code = read();
714f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    switch (code) {
724f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        case 0xf9: // graphics control extension
734f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            //Start a new frame
744f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            header.currentFrame = new GifFrame();
754f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            readGraphicControlExt();
764f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            break;
774f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        case 0xff: // application extension
784f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            readBlock();
794f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            String app = "";
804f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            for (int i = 0; i < 11; i++) {
814f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                                app += (char) block[i];
824f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            }
834f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            if (app.equals("NETSCAPE2.0")) {
844f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                                readNetscapeExt();
854f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            } else {
864f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                                skip(); // don't care
874f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            }
884f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            break;
894f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        case 0xfe:// comment extension
904f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            skip();
914f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            break;
924f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        case 0x01:// plain text extension
934f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            skip();
944f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            break;
954f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        default: // uninteresting extension
964f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            skip();
974f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    }
984f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    break;
994f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                case 0x3b: // terminator
1004f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    done = true;
1014f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    break;
1024f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                case 0x00: // bad byte, but keep going and see what happens break;
1034f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                default:
1044f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    header.status = STATUS_FORMAT_ERROR;
1054f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            }
1064f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1074f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
1084f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1094f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    /**
1104f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads Graphics Control Extension values
1114f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
1124f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void readGraphicControlExt() {
1134f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        read(); // block size
1144f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int packed = read(); // packed fields
1154f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.dispose = (packed & 0x1c) >> 2; // disposal method
1164f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (header.currentFrame.dispose == 0) {
1174f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.currentFrame.dispose = 1; // elect to keep old image if discretionary
1184f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1194f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.transparency = (packed & 1) != 0;
1204f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.isTransparent |= header.currentFrame.transparency;
1214f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.delay = readShort() * 10; // delay in milliseconds
1224f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.transIndex = read(); // transparent color index
1234f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        read(); // block terminator
1244f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
1254f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1264f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     /**
1274f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads next frame image
1284f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
1294f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void readBitmap() {
1304f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.ix = readShort(); // (sub)image position & size
1314f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.iy = readShort();
1324f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.iw = readShort();
1334f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.ih = readShort();
1344f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1354f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int packed = read();
1364f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace
1374f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
1384f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // 3 - sort flag
1394f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color
1404f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // table size
1414f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.interlace = (packed & 0x40) != 0;
1424f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (lctFlag) {
1434f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.currentFrame.lct = readColorTable(lctSize); // read table
1444f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        } else {
1454f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.currentFrame.lct = null; //No local color table
1464f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1474f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1484f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.currentFrame.bufferFrameStart = rawData.position(); //Save this as the decoding position pointer
1494f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1504f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        skipBitmapData();  // false decode pixel data to advance buffer.
1514f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1524f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        skip();
1534f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (err()) {
1544f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            return;
1554f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1564f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1574f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.frameCount++;
1584f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.frames.add(header.currentFrame); // add image to frame
1594f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
1604f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd       /**
1614f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads Netscape extenstion to obtain iteration count
1624f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
1634f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void readNetscapeExt() {
1644f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        do {
1654f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            readBlock();
1664f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            if (block[0] == 1) {
1674f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                // loop count sub-block
1684f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                int b1 = ((int) block[1]) & 0xff;
1694f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                int b2 = ((int) block[2]) & 0xff;
1704f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                header.loopCount = (b2 << 8) | b1;
1714f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            }
1724f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        } while ((blockSize > 0) && !err());
1734f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
1744f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1754f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
1764f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd       /**
1774f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads GIF file header information.
1784f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
1794f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private void readHeader() {
1804f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        String id = "";
1814f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        for (int i = 0; i < 6; i++) {
1824f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            id += (char) read();
1834f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1844f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (!id.startsWith("GIF")) {
1854f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.status = STATUS_FORMAT_ERROR;
1864f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            return;
1874f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1884f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        readLSD();
1894f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (header.gctFlag && !err()) {
1904f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.gct = readColorTable(header.gctSize);
1914f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.bgColor = header.gct[header.bgIndex];
1924f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
1934f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
1944f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     /**
1954f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads Logical Screen Descriptor
1964f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
1974f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void readLSD() {
1984f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // logical screen size
1994f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.width = readShort();
2004f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.height = readShort();
2014f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // packed fields
2024f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int packed = read();
2034f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
2044f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // 2-4 : color resolution
2054f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // 5 : gct sort flag
2064f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.gctSize = 2 << (packed & 7); // 6-8 : gct size
2074f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.bgIndex = read(); // background color index
2084f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        header.pixelAspect = read(); // pixel aspect ratio
2094f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2104f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        //Now that we know the size, init scratch arrays
2114f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        //TODO: these shouldn't go here.
2124f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd//        mainPixels = new byte[header.width * header.height];
2134f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd//        mainScratch = new int[header.width * header.height];
2144f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
2154f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     /**
2164f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads color table as 256 RGB integer values
2174f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     *
2184f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * @param ncolors int number of colors to read
2194f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * @return int array containing 256 colors (packed ARGB with full alpha)
2204f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
2214f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected int[] readColorTable(int ncolors) {
2224f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int nbytes = 3 * ncolors;
2234f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int[] tab = null;
2244f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        byte[] c = new byte[nbytes];
2254f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2264f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        try {
2274f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            rawData.get(c);
2284f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2294f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            tab = new int[256]; // max size to avoid bounds checks
2304f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            int i = 0;
2314f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            int j = 0;
2324f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            while (i < ncolors) {
2334f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                int r = ((int) c[j++]) & 0xff;
2344f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                int g = ((int) c[j++]) & 0xff;
2354f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                int b = ((int) c[j++]) & 0xff;
2364f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
2374f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            }
2384f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        } catch (BufferUnderflowException e) {
2394f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            Log.w(TAG, "Format Error Reading Color Table", e);
2404f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.status = STATUS_FORMAT_ERROR;
2414f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
2424f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2434f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        return tab;
2444f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
2454f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2464f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd      /**
2474f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick.
2484f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
2494f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void skipBitmapData() {
2504f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int nullCode = -1;
2514f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int npix = header.width * header.height;
2524f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;
2534f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2544f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (prefix == null) {
2554f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            prefix = new short[MAX_STACK_SIZE];
2564f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
2574f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (suffix == null) {
2584f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            suffix = new byte[MAX_STACK_SIZE];
2594f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
2604f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (pixelStack == null) {
2614f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            pixelStack = new byte[MAX_STACK_SIZE + 1];
2624f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
2634f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2644f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // Initialize GIF data stream decoder.
2654f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        data_size = read();
2664f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        clear = 1 << data_size;
2674f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        end_of_information = clear + 1;
2684f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        available = clear + 2;
2694f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        old_code = nullCode;
2704f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        code_size = data_size + 1;
2714f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        code_mask = (1 << code_size) - 1;
2724f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        long start = System.currentTimeMillis();
2734f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        for (code = 0; code < clear; code++) {
2744f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException
2754f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            suffix[code] = (byte) code;
2764f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
2774f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
2784f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        start = System.currentTimeMillis();
2794f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // Decode GIF pixel stream.
2804f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        datum = bits = count = first = top = pi = bi = 0;
2814f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int iterations = 0;
2824f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        for (i = 0; i < npix; ) {
2834f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            iterations++;
2844f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            if (top == 0) {
2854f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if (bits < code_size) {
2864f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    // Load bytes until there are enough bits for a code.
2874f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    if (count == 0) {
2884f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        // Read a new data block.
2894f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        count = readBlock();
2904f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        if (count <= 0) {
2914f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                            break;
2924f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        }
2934f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                        bi = 0;
2944f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    }
2954f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    datum += (((int) block[bi]) & 0xff) << bits;
2964f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    bits += 8;
2974f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    bi++;
2984f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    count--;
2994f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    continue;
3004f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3014f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                // Get the next code.
3024f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                code = datum & code_mask;
3034f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                datum >>= code_size;
3044f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                bits -= code_size;
3054f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                // Interpret the code
3064f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if ((code > available) || (code == end_of_information)) {
3074f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    break;
3084f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3094f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if (code == clear) {
3104f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    // Reset decoder.
3114f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code_size = data_size + 1;
3124f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code_mask = (1 << code_size) - 1;
3134f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    available = clear + 2;
3144f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    old_code = nullCode;
3154f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    continue;
3164f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3174f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if (old_code == nullCode) {
3184f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    pixelStack[top++] = suffix[code];
3194f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    old_code = code;
3204f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    first = code;
3214f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    continue;
3224f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3234f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                in_code = code;
3244f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if (code == available) {
3254f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    pixelStack[top++] = (byte) first;
3264f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code = old_code;
3274f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3284f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                while (code > clear) {
3294f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    pixelStack[top++] = suffix[code];
3304f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code = prefix[code];
3314f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3324f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                first = ((int) suffix[code]) & 0xff;
3334f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                // Add a new string to the string table,
3344f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if (available >= MAX_STACK_SIZE) {
3354f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    break;
3364f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3374f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                pixelStack[top++] = (byte) first;
3384f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                prefix[available] = (short) old_code;
3394f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                suffix[available] = (byte) first;
3404f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                available++;
3414f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {
3424f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code_size++;
3434f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    code_mask += available;
3444f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3454f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                old_code = in_code;
3464f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            }
3474f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            // Pop a pixel off the pixel stack.
3484f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            top--;
3494f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            i++;
3504f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
3514f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
3524f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
3534f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd      /**
3544f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Skips variable length blocks up to and including next zero length block.
3554f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
3564f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected void skip() {
3574f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        do {
3584f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            readBlock();
3594f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        } while ((blockSize > 0) && !err());
3604f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
3614f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
3624f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     /**
3634f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads next variable length block from input.
3644f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     *
3654f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * @return number of bytes stored in "buffer"
3664f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
3674f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected int readBlock() {
3684f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        blockSize = read();
3694f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int n = 0;
3704f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        if (blockSize > 0) {
3714f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            try {
3724f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                int count;
3734f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                while (n < blockSize) {
3744f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    count = blockSize - n;
3754f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    rawData.get(block, n, count);
3764f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
3774f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                    n += count;
3784f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                }
3794f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            } catch (Exception e) {
3804f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                Log.w(TAG, "Error Reading Block", e);
3814f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd                header.status = STATUS_FORMAT_ERROR;
3824f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            }
3834f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
3844f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        return n;
3854f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
3864f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
3874f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd      /**
3884f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads a single byte from the input stream.
3894f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
3904f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private int read() {
3914f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        int curByte = 0;
3924f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        try {
3934f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            curByte = (rawData.get() & 0xFF);
3944f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        } catch (Exception e) {
3954f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd            header.status = STATUS_FORMAT_ERROR;
3964f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        }
3974f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        return curByte;
3984f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
3994f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
4004f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    /**
4014f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     * Reads next 16-bit value, LSB first
4024f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd     */
4034f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    protected int readShort() {
4044f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        // read 16-bit value
4054f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        return rawData.getShort();
4064f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
4074f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd
4084f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    private boolean err() {
4094f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd        return header.status != GifDecoder.STATUS_OK;
4104f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd    }
4114f96c1a82e7d2db4863ac63dd00a261e9f0746b1Sam Judd}
412