1package com.bumptech.glide.gifdecoder;
2
3import android.util.Log;
4
5import java.nio.BufferUnderflowException;
6import java.nio.ByteBuffer;
7import java.nio.ByteOrder;
8
9import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR;
10
11public 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