1 package com.bumptech.glide.gifdecoder; 2 3 import android.util.Log; 4 5 import java.nio.BufferUnderflowException; 6 import java.nio.ByteBuffer; 7 import java.nio.ByteOrder; 8 9 import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR; 10 11 public class GifHeaderParser { 12 public static final String TAG = "GifHeaderParser"; 13 /** 14 * max decoder pixel stack size 15 */ 16 private static final int MAX_STACK_SIZE = 4096; 17 18 private final ByteBuffer rawData; 19 private GifHeader header = new GifHeader(); 20 21 // Raw data read working array 22 protected byte[] block = new byte[256]; // current data block 23 protected int blockSize = 0; // block size last graphic control extension info 24 protected boolean lctFlag; // local color table flag 25 protected int lctSize; // local color table size 26 private short[] prefix; 27 private byte[] suffix; 28 private byte[] pixelStack; 29 30 public GifHeaderParser(byte[] data) { 31 if (data != null) { 32 rawData = ByteBuffer.wrap(data); 33 rawData.rewind(); 34 rawData.order(ByteOrder.LITTLE_ENDIAN); 35 } else { 36 rawData = null; 37 header.status = GifDecoder.STATUS_OPEN_ERROR; 38 } 39 } 40 41 public GifHeader parseHeader() { 42 if (err()) { 43 return header; 44 } 45 46 readHeader(); 47 if (!err()) { 48 readContents(); 49 if (header.frameCount < 0) { 50 header.status = STATUS_FORMAT_ERROR; 51 } 52 } 53 54 return header; 55 } 56 57 /** 58 * Main file parser. Reads GIF content blocks. 59 */ 60 protected void readContents() { 61 // read GIF file content blocks 62 boolean done = false; 63 while (!(done || err())) { 64 int code = read(); 65 switch (code) { 66 case 0x2C: // image separator 67 readBitmap(); 68 break; 69 case 0x21: // extension 70 code = read(); 71 switch (code) { 72 case 0xf9: // graphics control extension 73 //Start a new frame 74 header.currentFrame = new GifFrame(); 75 readGraphicControlExt(); 76 break; 77 case 0xff: // application extension 78 readBlock(); 79 String app = ""; 80 for (int i = 0; i < 11; i++) { 81 app += (char) block[i]; 82 } 83 if (app.equals("NETSCAPE2.0")) { 84 readNetscapeExt(); 85 } else { 86 skip(); // don't care 87 } 88 break; 89 case 0xfe:// comment extension 90 skip(); 91 break; 92 case 0x01:// plain text extension 93 skip(); 94 break; 95 default: // uninteresting extension 96 skip(); 97 } 98 break; 99 case 0x3b: // terminator 100 done = true; 101 break; 102 case 0x00: // bad byte, but keep going and see what happens break; 103 default: 104 header.status = STATUS_FORMAT_ERROR; 105 } 106 } 107 } 108 109 /** 110 * Reads Graphics Control Extension values 111 */ 112 protected void readGraphicControlExt() { 113 read(); // block size 114 int packed = read(); // packed fields 115 header.currentFrame.dispose = (packed & 0x1c) >> 2; // disposal method 116 if (header.currentFrame.dispose == 0) { 117 header.currentFrame.dispose = 1; // elect to keep old image if discretionary 118 } 119 header.currentFrame.transparency = (packed & 1) != 0; 120 header.isTransparent |= header.currentFrame.transparency; 121 header.currentFrame.delay = readShort() * 10; // delay in milliseconds 122 header.currentFrame.transIndex = read(); // transparent color index 123 read(); // block terminator 124 } 125 126 /** 127 * Reads next frame image 128 */ 129 protected void readBitmap() { 130 header.currentFrame.ix = readShort(); // (sub)image position & size 131 header.currentFrame.iy = readShort(); 132 header.currentFrame.iw = readShort(); 133 header.currentFrame.ih = readShort(); 134 135 int packed = read(); 136 lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace 137 lctSize = (int) Math.pow(2, (packed & 0x07) + 1); 138 // 3 - sort flag 139 // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color 140 // table size 141 header.currentFrame.interlace = (packed & 0x40) != 0; 142 if (lctFlag) { 143 header.currentFrame.lct = readColorTable(lctSize); // read table 144 } else { 145 header.currentFrame.lct = null; //No local color table 146 } 147 148 header.currentFrame.bufferFrameStart = rawData.position(); //Save this as the decoding position pointer 149 150 skipBitmapData(); // false decode pixel data to advance buffer. 151 152 skip(); 153 if (err()) { 154 return; 155 } 156 157 header.frameCount++; 158 header.frames.add(header.currentFrame); // add image to frame 159 } 160 /** 161 * Reads Netscape extenstion to obtain iteration count 162 */ 163 protected void readNetscapeExt() { 164 do { 165 readBlock(); 166 if (block[0] == 1) { 167 // loop count sub-block 168 int b1 = ((int) block[1]) & 0xff; 169 int b2 = ((int) block[2]) & 0xff; 170 header.loopCount = (b2 << 8) | b1; 171 } 172 } while ((blockSize > 0) && !err()); 173 } 174 175 176 /** 177 * Reads GIF file header information. 178 */ 179 private void readHeader() { 180 String id = ""; 181 for (int i = 0; i < 6; i++) { 182 id += (char) read(); 183 } 184 if (!id.startsWith("GIF")) { 185 header.status = STATUS_FORMAT_ERROR; 186 return; 187 } 188 readLSD(); 189 if (header.gctFlag && !err()) { 190 header.gct = readColorTable(header.gctSize); 191 header.bgColor = header.gct[header.bgIndex]; 192 } 193 } 194 /** 195 * Reads Logical Screen Descriptor 196 */ 197 protected void readLSD() { 198 // logical screen size 199 header.width = readShort(); 200 header.height = readShort(); 201 // packed fields 202 int packed = read(); 203 header.gctFlag = (packed & 0x80) != 0; // 1 : global color table flag 204 // 2-4 : color resolution 205 // 5 : gct sort flag 206 header.gctSize = 2 << (packed & 7); // 6-8 : gct size 207 header.bgIndex = read(); // background color index 208 header.pixelAspect = read(); // pixel aspect ratio 209 210 //Now that we know the size, init scratch arrays 211 //TODO: these shouldn't go here. 212 // mainPixels = new byte[header.width * header.height]; 213 // mainScratch = new int[header.width * header.height]; 214 } 215 /** 216 * Reads color table as 256 RGB integer values 217 * 218 * @param ncolors int number of colors to read 219 * @return int array containing 256 colors (packed ARGB with full alpha) 220 */ 221 protected int[] readColorTable(int ncolors) { 222 int nbytes = 3 * ncolors; 223 int[] tab = null; 224 byte[] c = new byte[nbytes]; 225 226 try { 227 rawData.get(c); 228 229 tab = new int[256]; // max size to avoid bounds checks 230 int i = 0; 231 int j = 0; 232 while (i < ncolors) { 233 int r = ((int) c[j++]) & 0xff; 234 int g = ((int) c[j++]) & 0xff; 235 int b = ((int) c[j++]) & 0xff; 236 tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; 237 } 238 } catch (BufferUnderflowException e) { 239 Log.w(TAG, "Format Error Reading Color Table", e); 240 header.status = STATUS_FORMAT_ERROR; 241 } 242 243 return tab; 244 } 245 246 /** 247 * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. 248 */ 249 protected void skipBitmapData() { 250 int nullCode = -1; 251 int npix = header.width * header.height; 252 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; 253 254 if (prefix == null) { 255 prefix = new short[MAX_STACK_SIZE]; 256 } 257 if (suffix == null) { 258 suffix = new byte[MAX_STACK_SIZE]; 259 } 260 if (pixelStack == null) { 261 pixelStack = new byte[MAX_STACK_SIZE + 1]; 262 } 263 264 // Initialize GIF data stream decoder. 265 data_size = read(); 266 clear = 1 << data_size; 267 end_of_information = clear + 1; 268 available = clear + 2; 269 old_code = nullCode; 270 code_size = data_size + 1; 271 code_mask = (1 << code_size) - 1; 272 long start = System.currentTimeMillis(); 273 for (code = 0; code < clear; code++) { 274 prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException 275 suffix[code] = (byte) code; 276 } 277 278 start = System.currentTimeMillis(); 279 // Decode GIF pixel stream. 280 datum = bits = count = first = top = pi = bi = 0; 281 int iterations = 0; 282 for (i = 0; i < npix; ) { 283 iterations++; 284 if (top == 0) { 285 if (bits < code_size) { 286 // Load bytes until there are enough bits for a code. 287 if (count == 0) { 288 // Read a new data block. 289 count = readBlock(); 290 if (count <= 0) { 291 break; 292 } 293 bi = 0; 294 } 295 datum += (((int) block[bi]) & 0xff) << bits; 296 bits += 8; 297 bi++; 298 count--; 299 continue; 300 } 301 // Get the next code. 302 code = datum & code_mask; 303 datum >>= code_size; 304 bits -= code_size; 305 // Interpret the code 306 if ((code > available) || (code == end_of_information)) { 307 break; 308 } 309 if (code == clear) { 310 // Reset decoder. 311 code_size = data_size + 1; 312 code_mask = (1 << code_size) - 1; 313 available = clear + 2; 314 old_code = nullCode; 315 continue; 316 } 317 if (old_code == nullCode) { 318 pixelStack[top++] = suffix[code]; 319 old_code = code; 320 first = code; 321 continue; 322 } 323 in_code = code; 324 if (code == available) { 325 pixelStack[top++] = (byte) first; 326 code = old_code; 327 } 328 while (code > clear) { 329 pixelStack[top++] = suffix[code]; 330 code = prefix[code]; 331 } 332 first = ((int) suffix[code]) & 0xff; 333 // Add a new string to the string table, 334 if (available >= MAX_STACK_SIZE) { 335 break; 336 } 337 pixelStack[top++] = (byte) first; 338 prefix[available] = (short) old_code; 339 suffix[available] = (byte) first; 340 available++; 341 if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) { 342 code_size++; 343 code_mask += available; 344 } 345 old_code = in_code; 346 } 347 // Pop a pixel off the pixel stack. 348 top--; 349 i++; 350 } 351 } 352 353 /** 354 * Skips variable length blocks up to and including next zero length block. 355 */ 356 protected void skip() { 357 do { 358 readBlock(); 359 } while ((blockSize > 0) && !err()); 360 } 361 362 /** 363 * Reads next variable length block from input. 364 * 365 * @return number of bytes stored in "buffer" 366 */ 367 protected int readBlock() { 368 blockSize = read(); 369 int n = 0; 370 if (blockSize > 0) { 371 try { 372 int count; 373 while (n < blockSize) { 374 count = blockSize - n; 375 rawData.get(block, n, count); 376 377 n += count; 378 } 379 } catch (Exception e) { 380 Log.w(TAG, "Error Reading Block", e); 381 header.status = STATUS_FORMAT_ERROR; 382 } 383 } 384 return n; 385 } 386 387 /** 388 * Reads a single byte from the input stream. 389 */ 390 private int read() { 391 int curByte = 0; 392 try { 393 curByte = (rawData.get() & 0xFF); 394 } catch (Exception e) { 395 header.status = STATUS_FORMAT_ERROR; 396 } 397 return curByte; 398 } 399 400 /** 401 * Reads next 16-bit value, LSB first 402 */ 403 protected int readShort() { 404 // read 16-bit value 405 return rawData.getShort(); 406 } 407 408 private boolean err() { 409 return header.status != GifDecoder.STATUS_OK; 410 } 411 } 412