- type = (unsigned char)m_f->GetC();
-
- /* end of data? */
- if (type == 0x3B)
- {
- done = TRUE;
- }
- else
- /* extension block? */
- if (type == 0x21)
- {
- if (((unsigned char)m_f->GetC()) == 0xF9)
- /* graphics control extension, parse it */
- {
- m_f->Read(buf, 6);
-
- /* read delay and convert from 1/100 of a second to ms */
- delay = 10 * (buf[2] + 256 * buf[3]);
-
- /* read transparent colour index, if used */
- if (buf[1] & 0x01)
- transparent = buf[4];
-
- /* read disposal method */
- disposal = (buf[1] & 0x1C) - 1;
- }
- else
- /* other extension, skip */
- {
- while ((i = (unsigned char)m_f->GetC()) != 0)
- {
- m_f->SeekI(i, wxFromCurrent);
- }
- }
- }
- else
- /* image descriptor block? */
- if (type == 0x2C)
- {
- /* allocate memory for IMAGEN struct */
- pimg = (*ppimg) = new GIFImage();
-
- if (pimg == NULL)
- {
- Destroy();
- return wxGIF_MEMERR;
- }
-
- /* fill in the data */
- m_f->Read(buf, 9);
- pimg->left = buf[4] + 256 * buf[5];
- pimg->top = buf[4] + 256 * buf[5];
- pimg->w = buf[4] + 256 * buf[5];
- pimg->h = buf[6] + 256 * buf[7];
- interl = ((buf[8] & 0x40)? 1 : 0);
- size = pimg->w * pimg->h;
-
- pimg->transparent = transparent;
- pimg->disposal = disposal;
- pimg->delay = delay;
- pimg->next = NULL;
- pimg->prev = pprev;
- pprev = pimg;
- ppimg = &pimg->next;
-
- /* allocate memory for image and palette */
- pimg->p = (unsigned char *) malloc((size_t)size);
- pimg->pal = (unsigned char *) malloc(768);
-
- if ((!pimg->p) || (!pimg->pal))
- {
- Destroy();
- return wxGIF_MEMERR;
- }
-
- /* load local color map if available, else use global map */
- if ((buf[8] & 0x80) == 0x80)
- {
- ncolors = 2 << (buf[8] & 0x07);
- m_f->Read(pimg->pal, 3 * ncolors);
- }
- else
- memcpy(pimg->pal, pal, 768);
-
- /* get initial code size from first byte in raster data */
- bits = (unsigned char)m_f->GetC();
-
- /* decode image */
- dgif(pimg, interl, bits);
- m_nimages++;
-
- /* if this is not an animated GIF, exit after first image */
- if (!m_anim)
- done = TRUE;
- }
+ type = stream.GetC();
+
+ /*
+ If the end of file has been reached (or an error) and a ";"
+ (GIF_MARKER_ENDOFDATA) hasn't been encountered yet, exit the loop. (Without this
+ check the while loop would loop endlessly.) Later on, in the next while
+ loop, the file will be treated as being truncated (But still
+ be decoded as far as possible). returning wxGIF_TRUNCATED is not
+ possible here since some init code is done after this loop.
+ */
+ if (stream.Eof())// || !stream.IsOk())
+ {
+ /*
+ type is set to some bogus value, so there's no
+ need to continue evaluating it.
+ */
+ break; // Alternative : "return wxGIF_INVFORMAT;"
+ }
+
+ switch (type)
+ {
+ case GIF_MARKER_ENDOFDATA:
+ done = true;
+ break;
+ case GIF_MARKER_EXT:
+ switch (stream.GetC())
+ {
+ case GIF_MARKER_EXT_GRAPHICS_CONTROL:
+ {
+ // graphics control extension, parse it
+
+ static const unsigned int gceSize = 6;
+ stream.Read(buf, gceSize);
+ if (stream.LastRead() != gceSize)
+ {
+ Destroy();
+ return wxGIF_INVFORMAT;
+ }
+
+ // read delay and convert from 1/100 of a second to ms
+ delay = 10 * (buf[2] + 256 * buf[3]);
+
+ // read transparent colour index, if used
+ transparent = buf[1] & 0x01 ? buf[4] : -1;
+
+ // read disposal method
+ disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1);
+ break;
+ }
+ case GIF_MARKER_EXT_COMMENT:
+ {
+ int len = stream.GetC();
+ while (len)
+ {
+ if ( stream.Eof() )
+ {
+ done = true;
+ break;
+ }
+
+ wxCharBuffer charbuf(len);
+ stream.Read(charbuf.data(), len);
+ if ( (int) stream.LastRead() != len )
+ {
+ done = true;
+ break;
+ }
+
+ comment += wxConvertMB2WX(charbuf.data());
+
+ len = stream.GetC();
+ }
+
+ break;
+ }
+ default:
+ // other extension, skip
+ while ((i = stream.GetC()) != 0)
+ {
+ if (stream.Eof() || (stream.LastRead() == 0) ||
+ stream.SeekI(i, wxFromCurrent) == wxInvalidOffset)
+ {
+ done = true;
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case GIF_MARKER_SEP:
+ {
+ // allocate memory for IMAGEN struct
+ GIFImagePtr pimg(new GIFImage());
+
+ wxScopeGuard guardDestroy = wxMakeObjGuard(*this, &wxGIFDecoder::Destroy);
+
+ if ( !pimg.get() )
+ return wxGIF_MEMERR;
+
+ // fill in the data
+ static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1);
+ stream.Read(buf, idbSize);
+ if (stream.LastRead() != idbSize)
+ return wxGIF_INVFORMAT;
+
+ pimg->comment = comment;
+ comment.clear();
+ pimg->left = buf[0] + 256 * buf[1];
+ pimg->top = buf[2] + 256 * buf[3];
+ /*
+ pimg->left = buf[4] + 256 * buf[5];
+ pimg->top = buf[4] + 256 * buf[5];
+ */
+ pimg->w = buf[4] + 256 * buf[5];
+ pimg->h = buf[6] + 256 * buf[7];
+
+ if ( anim )
+ {
+ // some GIF images specify incorrect animation size but we can
+ // still open them if we fix up the animation size, see #9465
+ if ( m_nFrames == 0 )
+ {
+ if ( pimg->w > (unsigned)m_szAnimation.x )
+ m_szAnimation.x = pimg->w;
+ if ( pimg->h > (unsigned)m_szAnimation.y )
+ m_szAnimation.y = pimg->h;
+ }
+ else // subsequent frames
+ {
+ // check that we have valid size
+ if ( (!pimg->w || pimg->w > (unsigned)m_szAnimation.x) ||
+ (!pimg->h || pimg->h > (unsigned)m_szAnimation.y) )
+ {
+ wxLogError(_("Incorrect GIF frame size (%u, %d) for "
+ "the frame #%u"),
+ pimg->w, pimg->h, m_nFrames);
+ return wxGIF_INVFORMAT;
+ }
+ }
+ }
+
+ interl = ((buf[8] & 0x40)? 1 : 0);
+ size = pimg->w * pimg->h;
+
+ pimg->transparent = transparent;
+ pimg->disposal = disposal;
+ pimg->delay = delay;
+
+ // allocate memory for image and palette
+ pimg->p = (unsigned char *) malloc((unsigned int)size);
+ pimg->pal = (unsigned char *) malloc(768);
+
+ if ((!pimg->p) || (!pimg->pal))
+ return wxGIF_MEMERR;
+
+ // load local color map if available, else use global map
+ if ((buf[8] & 0x80) == 0x80)
+ {
+ unsigned int local_ncolors = 2 << (buf[8] & 0x07);
+ unsigned int numBytes = 3 * local_ncolors;
+ stream.Read(pimg->pal, numBytes);
+ pimg->ncolours = local_ncolors;
+ if (stream.LastRead() != numBytes)
+ return wxGIF_INVFORMAT;
+ }
+ else
+ {
+ memcpy(pimg->pal, pal, 768);
+ pimg->ncolours = global_ncolors;
+ }
+
+ // get initial code size from first byte in raster data
+ bits = stream.GetC();
+ if (bits == 0)
+ return wxGIF_INVFORMAT;
+
+ // decode image
+ wxGIFErrorCode result = dgif(stream, pimg.get(), interl, bits);
+ if (result != wxGIF_OK)
+ return result;
+
+ guardDestroy.Dismiss();
+
+ // add the image to our frame array
+ m_frames.Add(pimg.release());
+ m_nFrames++;
+
+ // if this is not an animated GIF, exit after first image
+ if (!anim)
+ done = true;
+ break;
+ }
+ }