diff options
Diffstat (limited to 'WebCore/platform/image-decoders/gif/GIFImageReader.cpp')
-rw-r--r-- | WebCore/platform/image-decoders/gif/GIFImageReader.cpp | 925 |
1 files changed, 0 insertions, 925 deletions
diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp deleted file mode 100644 index 1e033a3..0000000 --- a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp +++ /dev/null @@ -1,925 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Chris Saari <saari@netscape.com> - * Apple Computer - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* -The Graphics Interchange Format(c) is the copyright property of CompuServe -Incorporated. Only CompuServe Incorporated is authorized to define, redefine, -enhance, alter, modify or change in any way the definition of the format. - -CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free -license for the use of the Graphics Interchange Format(sm) in computer -software; computer software utilizing GIF(sm) must acknowledge ownership of the -Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in -User and Technical Documentation. Computer software utilizing GIF, which is -distributed or may be distributed without User or Technical Documentation must -display to the screen or printer a message acknowledging ownership of the -Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in -this case, the acknowledgement may be displayed in an opening screen or leading -banner, or a closing screen or trailing banner. A message such as the following -may be used: - - "The Graphics Interchange Format(c) is the Copyright property of - CompuServe Incorporated. GIF(sm) is a Service Mark property of - CompuServe Incorporated." - -For further information, please contact : - - CompuServe Incorporated - Graphics Technology Department - 5000 Arlington Center Boulevard - Columbus, Ohio 43220 - U. S. A. - -CompuServe Incorporated maintains a mailing list with all those individuals and -organizations who wish to receive copies of this document when it is corrected -or revised. This service is offered free of charge; please provide us with your -mailing address. -*/ - -#include "config.h" -#include "GIFImageReader.h" - -#include <string.h> -#include "GIFImageDecoder.h" -#include "ImageSource.h" - -using WebCore::GIFImageDecoder; - -// Define the Mozilla macro setup so that we can leave the macros alone. -#define PR_BEGIN_MACRO do { -#define PR_END_MACRO } while (0) - -/* - * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's' - * - * Note, the hold will never need to be bigger than 256 bytes to gather up in the hold, - * as each GIF block (except colormaps) can never be bigger than 256 bytes. - * Colormaps are directly copied in the resp. global_colormap or dynamically allocated local_colormap. - * So a fixed buffer in GIFImageReader is good enough. - * This buffer is only needed to copy left-over data from one GifWrite call to the next - */ -#define GETN(n,s) \ - PR_BEGIN_MACRO \ - bytes_to_consume = (n); \ - state = (s); \ - PR_END_MACRO - -/* Get a 16-bit value stored in little-endian format */ -#define GETINT16(p) ((p)[1]<<8|(p)[0]) - -//****************************************************************************** -// Send the data to the display front-end. -bool GIFImageReader::output_row() -{ - GIFFrameReader* gs = frame_reader; - - int drow_start, drow_end; - - drow_start = drow_end = gs->irow; - - /* - * Haeberli-inspired hack for interlaced GIFs: Replicate lines while - * displaying to diminish the "venetian-blind" effect as the image is - * loaded. Adjust pixel vertical positions to avoid the appearance of the - * image crawling up the screen as successive passes are drawn. - */ - if (gs->progressive_display && gs->interlaced && gs->ipass < 4) { - unsigned row_dup = 0, row_shift = 0; - - switch (gs->ipass) { - case 1: - row_dup = 7; - row_shift = 3; - break; - case 2: - row_dup = 3; - row_shift = 1; - break; - case 3: - row_dup = 1; - row_shift = 0; - break; - default: - break; - } - - drow_start -= row_shift; - drow_end = drow_start + row_dup; - - /* Extend if bottom edge isn't covered because of the shift upward. */ - if (((gs->height - 1) - drow_end) <= row_shift) - drow_end = gs->height - 1; - - /* Clamp first and last rows to upper and lower edge of image. */ - if (drow_start < 0) - drow_start = 0; - if ((unsigned)drow_end >= gs->height) - drow_end = gs->height - 1; - } - - /* Protect against too much image data */ - if ((unsigned)drow_start >= gs->height) - return true; - - // CALLBACK: Let the client know we have decoded a row. - if (clientptr && frame_reader && - !clientptr->haveDecodedRow(images_count - 1, frame_reader->rowbuf, frame_reader->rowend, - drow_start, drow_end - drow_start + 1, - gs->progressive_display && gs->interlaced && gs->ipass > 1)) - return false; - - gs->rowp = gs->rowbuf; - - if (!gs->interlaced) - gs->irow++; - else { - do { - switch (gs->ipass) - { - case 1: - gs->irow += 8; - if (gs->irow >= gs->height) { - gs->ipass++; - gs->irow = 4; - } - break; - - case 2: - gs->irow += 8; - if (gs->irow >= gs->height) { - gs->ipass++; - gs->irow = 2; - } - break; - - case 3: - gs->irow += 4; - if (gs->irow >= gs->height) { - gs->ipass++; - gs->irow = 1; - } - break; - - case 4: - gs->irow += 2; - if (gs->irow >= gs->height){ - gs->ipass++; - gs->irow = 0; - } - break; - - default: - break; - } - } while (gs->irow > (gs->height - 1)); - } - - return true; -} - -//****************************************************************************** -/* Perform Lempel-Ziv-Welch decoding */ -bool GIFImageReader::do_lzw(const unsigned char *q) -{ - GIFFrameReader* gs = frame_reader; - if (!gs) - return true; - - int code; - int incode; - const unsigned char *ch; - - /* Copy all the decoder state variables into locals so the compiler - * won't worry about them being aliased. The locals will be homed - * back into the GIF decoder structure when we exit. - */ - int avail = gs->avail; - int bits = gs->bits; - int cnt = count; - int codesize = gs->codesize; - int codemask = gs->codemask; - int oldcode = gs->oldcode; - int clear_code = gs->clear_code; - unsigned char firstchar = gs->firstchar; - int datum = gs->datum; - - if (!gs->prefix) { - gs->prefix = new unsigned short[MAX_BITS]; - memset(gs->prefix, 0, MAX_BITS * sizeof(short)); - } - - unsigned short *prefix = gs->prefix; - unsigned char *stackp = gs->stackp; - unsigned char *suffix = gs->suffix; - unsigned char *stack = gs->stack; - unsigned char *rowp = gs->rowp; - unsigned char *rowend = gs->rowend; - unsigned rows_remaining = gs->rows_remaining; - - if (rowp == rowend) - return true; - -#define OUTPUT_ROW \ - PR_BEGIN_MACRO \ - if (!output_row()) \ - return false; \ - rows_remaining--; \ - rowp = frame_reader->rowp; \ - if (!rows_remaining) \ - goto END; \ - PR_END_MACRO - - for (ch = q; cnt-- > 0; ch++) - { - /* Feed the next byte into the decoder's 32-bit input buffer. */ - datum += ((int) *ch) << bits; - bits += 8; - - /* Check for underflow of decoder's 32-bit input buffer. */ - while (bits >= codesize) - { - /* Get the leading variable-length symbol from the data stream */ - code = datum & codemask; - datum >>= codesize; - bits -= codesize; - - /* Reset the dictionary to its original state, if requested */ - if (code == clear_code) { - codesize = gs->datasize + 1; - codemask = (1 << codesize) - 1; - avail = clear_code + 2; - oldcode = -1; - continue; - } - - /* Check for explicit end-of-stream code */ - if (code == (clear_code + 1)) { - /* end-of-stream should only appear after all image data */ - if (!rows_remaining) - return true; - return clientptr ? clientptr->setFailed() : false; - } - - if (oldcode == -1) { - *rowp++ = suffix[code]; - if (rowp == rowend) - OUTPUT_ROW; - - firstchar = oldcode = code; - continue; - } - - incode = code; - if (code >= avail) { - *stackp++ = firstchar; - code = oldcode; - - if (stackp == stack + MAX_BITS) - return clientptr ? clientptr->setFailed() : false; - } - - while (code >= clear_code) - { - if (code >= MAX_BITS || code == prefix[code]) - return clientptr ? clientptr->setFailed() : false; - - // Even though suffix[] only holds characters through suffix[avail - 1], - // allowing code >= avail here lets us be more tolerant of malformed - // data. As long as code < MAX_BITS, the only risk is a garbled image, - // which is no worse than refusing to display it. - *stackp++ = suffix[code]; - code = prefix[code]; - - if (stackp == stack + MAX_BITS) - return clientptr ? clientptr->setFailed() : false; - } - - *stackp++ = firstchar = suffix[code]; - - /* Define a new codeword in the dictionary. */ - if (avail < 4096) { - prefix[avail] = oldcode; - suffix[avail] = firstchar; - avail++; - - /* If we've used up all the codewords of a given length - * increase the length of codewords by one bit, but don't - * exceed the specified maximum codeword size of 12 bits. - */ - if (((avail & codemask) == 0) && (avail < 4096)) { - codesize++; - codemask += avail; - } - } - oldcode = incode; - - /* Copy the decoded data out to the scanline buffer. */ - do { - *rowp++ = *--stackp; - if (rowp == rowend) { - OUTPUT_ROW; - } - } while (stackp > stack); - } - } - - END: - - /* Home the local copies of the GIF decoder state variables */ - gs->avail = avail; - gs->bits = bits; - gs->codesize = codesize; - gs->codemask = codemask; - count = cnt; - gs->oldcode = oldcode; - gs->firstchar = firstchar; - gs->datum = datum; - gs->stackp = stackp; - gs->rowp = rowp; - gs->rows_remaining = rows_remaining; - - return true; -} - - -/******************************************************************************/ -/* - * process data arriving from the stream for the gif decoder - */ - -bool GIFImageReader::read(const unsigned char *buf, unsigned len, - GIFImageDecoder::GIFQuery query, unsigned haltAtFrame) -{ - if (!len) { - // No new data has come in since the last call, just ignore this call. - return true; - } - - const unsigned char *q = buf; - - // Add what we have so far to the block - // If previous call to me left something in the hold first complete current block - // Or if we are filling the colormaps, first complete the colormap - unsigned char* p = 0; - if (state == gif_global_colormap) - p = global_colormap; - else if (state == gif_image_colormap) - p = frame_reader ? frame_reader->local_colormap : 0; - else if (bytes_in_hold) - p = hold; - else - p = 0; - - if (p || (state == gif_global_colormap) || (state == gif_image_colormap)) { - // Add what we have sofar to the block - unsigned l = len < bytes_to_consume ? len : bytes_to_consume; - if (p) - memcpy(p + bytes_in_hold, buf, l); - - if (l < bytes_to_consume) { - // Not enough in 'buf' to complete current block, get more - bytes_in_hold += l; - bytes_to_consume -= l; - if (clientptr) - clientptr->decodingHalted(0); - return false; - } - // Reset hold buffer count - bytes_in_hold = 0; - // Point 'q' to complete block in hold (or in colormap) - q = p; - } - - // Invariant: - // 'q' is start of current to be processed block (hold, colormap or buf) - // 'bytes_to_consume' is number of bytes to consume from 'buf' - // 'buf' points to the bytes to be consumed from the input buffer - // 'len' is number of bytes left in input buffer from position 'buf'. - // At entrance of the for loop will 'buf' will be moved 'bytes_to_consume' - // to point to next buffer, 'len' is adjusted accordingly. - // So that next round in for loop, q gets pointed to the next buffer. - - for (;len >= bytes_to_consume; q=buf) { - // Eat the current block from the buffer, q keeps pointed at current block - buf += bytes_to_consume; - len -= bytes_to_consume; - - switch (state) - { - case gif_lzw: - if (!do_lzw(q)) - return false; // If do_lzw() encountered an error, it has already called - // clientptr->setFailed(). - GETN(1, gif_sub_block); - break; - - case gif_lzw_start: - { - /* Initialize LZW parser/decoder */ - int datasize = *q; - // Since we use a codesize of 1 more than the datasize, we need to ensure - // that our datasize is strictly less than the MAX_LZW_BITS value (12). - // This sets the largest possible codemask correctly at 4095. - if (datasize >= MAX_LZW_BITS) - return clientptr ? clientptr->setFailed() : false; - int clear_code = 1 << datasize; - if (clear_code >= MAX_BITS) - return clientptr ? clientptr->setFailed() : false; - - if (frame_reader) { - frame_reader->datasize = datasize; - frame_reader->clear_code = clear_code; - frame_reader->avail = frame_reader->clear_code + 2; - frame_reader->oldcode = -1; - frame_reader->codesize = frame_reader->datasize + 1; - frame_reader->codemask = (1 << frame_reader->codesize) - 1; - - frame_reader->datum = frame_reader->bits = 0; - - /* init the tables */ - if (!frame_reader->suffix) - frame_reader->suffix = new unsigned char[MAX_BITS]; - // Clearing the whole suffix table lets us be more tolerant of bad data. - memset(frame_reader->suffix, 0, MAX_BITS); - for (int i = 0; i < frame_reader->clear_code; i++) - frame_reader->suffix[i] = i; - - if (!frame_reader->stack) - frame_reader->stack = new unsigned char[MAX_BITS]; - frame_reader->stackp = frame_reader->stack; - } - - GETN(1, gif_sub_block); - } - break; - - /* All GIF files begin with "GIF87a" or "GIF89a" */ - case gif_type: - { - if (!strncmp((char*)q, "GIF89a", 6)) - version = 89; - else if (!strncmp((char*)q, "GIF87a", 6)) - version = 87; - else - return clientptr ? clientptr->setFailed() : false; - GETN(7, gif_global_header); - } - break; - - case gif_global_header: - { - /* This is the height and width of the "screen" or - * frame into which images are rendered. The - * individual images can be smaller than the - * screen size and located with an origin anywhere - * within the screen. - */ - - screen_width = GETINT16(q); - screen_height = GETINT16(q + 2); - - // CALLBACK: Inform the decoderplugin of our size. - if (clientptr && !clientptr->setSize(screen_width, screen_height)) - return false; - - screen_bgcolor = q[5]; - global_colormap_size = 2<<(q[4]&0x07); - - if ((q[4] & 0x80) && global_colormap_size > 0) { /* global map */ - // Get the global colormap - const unsigned size = 3*global_colormap_size; - - // Malloc the color map, but only if we're not just counting frames. - if (query != GIFImageDecoder::GIFFrameCountQuery) - global_colormap = new unsigned char[size]; - - if (len < size) { - // Use 'hold' pattern to get the global colormap - GETN(size, gif_global_colormap); - break; - } - - // Copy everything and go directly to gif_image_start. - if (global_colormap) - memcpy(global_colormap, buf, size); - buf += size; - len -= size; - } - - GETN(1, gif_image_start); - - // q[6] = Pixel Aspect Ratio - // Not used - // float aspect = (float)((q[6] + 15) / 64.0); - } - break; - - case gif_global_colormap: - // Everything is already copied into global_colormap - GETN(1, gif_image_start); - break; - - case gif_image_start: - { - if (*q == ';') { /* terminator */ - GETN(0, gif_done); - break; - } - - if (*q == '!') { /* extension */ - GETN(2, gif_extension); - break; - } - - /* If we get anything other than ',' (image separator), '!' - * (extension), or ';' (trailer), there is extraneous data - * between blocks. The GIF87a spec tells us to keep reading - * until we find an image separator, but GIF89a says such - * a file is corrupt. We follow GIF89a and bail out. */ - if (*q != ',') - return clientptr ? clientptr->setFailed() : false; - - GETN(9, gif_image_header); - } - break; - - case gif_extension: - { - int len = count = q[1]; - gstate es = gif_skip_block; - - switch (*q) - { - case 0xf9: - es = gif_control_extension; - break; - - case 0x01: - // ignoring plain text extension - break; - - case 0xff: - es = gif_application_extension; - break; - - case 0xfe: - es = gif_consume_comment; - break; - } - - if (len) - GETN(len, es); - else - GETN(1, gif_image_start); - } - break; - - case gif_consume_block: - if (!*q) - GETN(1, gif_image_start); - else - GETN(*q, gif_skip_block); - break; - - case gif_skip_block: - GETN(1, gif_consume_block); - break; - - case gif_control_extension: - { - if (query != GIFImageDecoder::GIFFrameCountQuery) { - if (!frame_reader) - frame_reader = new GIFFrameReader(); - } - - if (frame_reader) { - if (*q & 0x1) { - frame_reader->tpixel = q[3]; - frame_reader->is_transparent = true; - } else { - frame_reader->is_transparent = false; - // ignoring gfx control extension - } - // NOTE: This relies on the values in the FrameDisposalMethod enum - // matching those in the GIF spec! - frame_reader->disposal_method = (WebCore::RGBA32Buffer::FrameDisposalMethod)(((*q) >> 2) & 0x7); - // Some specs say 3rd bit (value 4), other specs say value 3 - // Let's choose 3 (the more popular) - if (frame_reader->disposal_method == 4) - frame_reader->disposal_method = WebCore::RGBA32Buffer::DisposeOverwritePrevious; - frame_reader->delay_time = GETINT16(q + 1) * 10; - } - GETN(1, gif_consume_block); - } - break; - - case gif_comment_extension: - { - if (*q) - GETN(*q, gif_consume_comment); - else - GETN(1, gif_image_start); - } - break; - - case gif_consume_comment: - GETN(1, gif_comment_extension); - break; - - case gif_application_extension: - /* Check for netscape application extension */ - if (!strncmp((char*)q, "NETSCAPE2.0", 11) || - !strncmp((char*)q, "ANIMEXTS1.0", 11)) - GETN(1, gif_netscape_extension_block); - else - GETN(1, gif_consume_block); - break; - - /* Netscape-specific GIF extension: animation looping */ - case gif_netscape_extension_block: - if (*q) - GETN(*q, gif_consume_netscape_extension); - else - GETN(1, gif_image_start); - break; - - /* Parse netscape-specific application extensions */ - case gif_consume_netscape_extension: - { - int netscape_extension = q[0] & 7; - - /* Loop entire animation specified # of times. Only read the - loop count during the first iteration. */ - if (netscape_extension == 1) { - loop_count = GETINT16(q + 1); - - /* Zero loop count is infinite animation loop request */ - if (loop_count == 0) - loop_count = WebCore::cAnimationLoopInfinite; - - GETN(1, gif_netscape_extension_block); - } - /* Wait for specified # of bytes to enter buffer */ - else if (netscape_extension == 2) { - // Don't do this, this extension doesn't exist (isn't used at all) - // and doesn't do anything, as our streaming/buffering takes care of it all... - // See: http://semmix.pl/color/exgraf/eeg24.htm - GETN(1, gif_netscape_extension_block); - } else { - // 0,3-7 are yet to be defined netscape extension codes - return clientptr ? clientptr->setFailed() : false; - } - - break; - } - - case gif_image_header: - { - unsigned height, width, x_offset, y_offset; - - /* Get image offsets, with respect to the screen origin */ - x_offset = GETINT16(q); - y_offset = GETINT16(q + 2); - - /* Get image width and height. */ - width = GETINT16(q + 4); - height = GETINT16(q + 6); - - /* Work around broken GIF files where the logical screen - * size has weird width or height. We assume that GIF87a - * files don't contain animations. - */ - if ((images_decoded == 0) && - ((screen_height < height) || (screen_width < width) || - (version == 87))) - { - screen_height = height; - screen_width = width; - x_offset = 0; - y_offset = 0; - - // CALLBACK: Inform the decoderplugin of our size. - if (clientptr && !clientptr->setSize(screen_width, screen_height)) - return false; - } - - /* Work around more broken GIF files that have zero image - width or height */ - if (!height || !width) { - height = screen_height; - width = screen_width; - if (!height || !width) - return clientptr ? clientptr->setFailed() : false; - } - - if (query == GIFImageDecoder::GIFSizeQuery || haltAtFrame == images_decoded) { - // The decoder needs to stop. Hand back the number of bytes we consumed from - // buffer minus 9 (the amount we consumed to read the header). - if (clientptr) - clientptr->decodingHalted(len + 9); - GETN(9, gif_image_header); - return true; - } - - images_count = images_decoded + 1; - - if (query == GIFImageDecoder::GIFFullQuery && !frame_reader) - frame_reader = new GIFFrameReader(); - - if (frame_reader) { - frame_reader->x_offset = x_offset; - frame_reader->y_offset = y_offset; - frame_reader->height = height; - frame_reader->width = width; - - /* This case will never be taken if this is the first image */ - /* being decoded. If any of the later images are larger */ - /* than the screen size, we need to reallocate buffers. */ - if (screen_width < width) { - /* XXX Deviant! */ - - delete []frame_reader->rowbuf; - screen_width = width; - frame_reader->rowbuf = new unsigned char[screen_width]; - } else if (!frame_reader->rowbuf) { - frame_reader->rowbuf = new unsigned char[screen_width]; - } - - if (!frame_reader->rowbuf) - return clientptr ? clientptr->setFailed() : false; - if (screen_height < height) - screen_height = height; - - if (q[8] & 0x40) { - frame_reader->interlaced = true; - frame_reader->ipass = 1; - } else { - frame_reader->interlaced = false; - frame_reader->ipass = 0; - } - - if (images_decoded == 0) { - frame_reader->progressive_display = true; - } else { - /* Overlaying interlaced, transparent GIFs over - existing image data using the Haeberli display hack - requires saving the underlying image in order to - avoid jaggies at the transparency edges. We are - unprepared to deal with that, so don't display such - images progressively */ - frame_reader->progressive_display = false; - } - - /* Clear state from last image */ - frame_reader->irow = 0; - frame_reader->rows_remaining = frame_reader->height; - frame_reader->rowend = frame_reader->rowbuf + frame_reader->width; - frame_reader->rowp = frame_reader->rowbuf; - - /* bits per pixel is q[8]&0x07 */ - } - - if (q[8] & 0x80) /* has a local colormap? */ - { - int num_colors = 2 << (q[8] & 0x7); - const unsigned size = 3*num_colors; - unsigned char *map = frame_reader ? frame_reader->local_colormap : 0; - if (frame_reader && (!map || (num_colors > frame_reader->local_colormap_size))) { - delete []map; - map = new unsigned char[size]; - if (!map) - return clientptr ? clientptr->setFailed() : false; - } - - /* Switch to the new local palette after it loads */ - if (frame_reader) { - frame_reader->local_colormap = map; - frame_reader->local_colormap_size = num_colors; - frame_reader->is_local_colormap_defined = true; - } - - if (len < size) { - // Use 'hold' pattern to get the image colormap - GETN(size, gif_image_colormap); - break; - } - // Copy everything and directly go to gif_lzw_start - if (frame_reader) - memcpy(frame_reader->local_colormap, buf, size); - buf += size; - len -= size; - } else if (frame_reader) { - /* Switch back to the global palette */ - frame_reader->is_local_colormap_defined = false; - } - GETN(1, gif_lzw_start); - } - break; - - case gif_image_colormap: - // Everything is already copied into local_colormap - GETN(1, gif_lzw_start); - break; - - case gif_sub_block: - { - if ((count = *q) != 0) - /* Still working on the same image: Process next LZW data block */ - { - /* Make sure there are still rows left. If the GIF data */ - /* is corrupt, we may not get an explicit terminator. */ - if (frame_reader && frame_reader->rows_remaining == 0) { - /* This is an illegal GIF, but we remain tolerant. */ - GETN(1, gif_sub_block); - } - GETN(count, gif_lzw); - } - else - /* See if there are any more images in this sequence. */ - { - images_decoded++; - - // CALLBACK: The frame is now complete. - if (clientptr && frame_reader && !clientptr->frameComplete(images_decoded - 1, frame_reader->delay_time, frame_reader->disposal_method)) - return false; // frameComplete() has already called - // clientptr->setFailed(). - - /* Clear state from this image */ - if (frame_reader) { - frame_reader->is_local_colormap_defined = false; - frame_reader->is_transparent = false; - } - - GETN(1, gif_image_start); - } - } - break; - - case gif_done: - // When the GIF is done, we can stop. - if (clientptr) - clientptr->gifComplete(); - return true; - - // We shouldn't ever get here. - default: - break; - } - } - - // Copy the leftover into gs->hold - bytes_in_hold = len; - if (len) { - // Add what we have sofar to the block - unsigned char* p; - if (state == gif_global_colormap) - p = global_colormap; - else if (state == gif_image_colormap) - p = frame_reader ? frame_reader->local_colormap : 0; - else - p = hold; - if (p) - memcpy(p, buf, len); - bytes_to_consume -= len; - } - - if (clientptr) - clientptr->decodingHalted(0); - return false; -} |