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