X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/870cf35c4596571462c5e2d1395428b135196b98..2ea60735163ce5ae73b8f089b0a982e65853c9f8:/src/common/gifdecod.cpp diff --git a/src/common/gifdecod.cpp b/src/common/gifdecod.cpp index 5437982d7b..27669b8d2a 100644 --- a/src/common/gifdecod.cpp +++ b/src/common/gifdecod.cpp @@ -19,11 +19,15 @@ #ifndef WX_PRECOMP #include "wx/palette.h" + #include "wx/intl.h" + #include "wx/log.h" #endif #include #include #include "wx/gifdecod.h" +#include "wx/scopedptr.h" +#include "wx/scopeguard.h" @@ -49,9 +53,11 @@ public: unsigned char *pal; // palette unsigned int ncolours; // number of colours - DECLARE_NO_COPY_CLASS(GIFImage) + wxDECLARE_NO_COPY_CLASS(GIFImage); }; +wxDECLARE_SCOPED_PTR(GIFImage, GIFImagePtr) +wxDEFINE_SCOPED_PTR(GIFImage, GIFImagePtr) //--------------------------------------------------------------------------- @@ -118,6 +124,7 @@ bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const // create the image wxSize sz = GetFrameSize(frame); image->Create(sz.GetWidth(), sz.GetHeight()); + image->SetType(wxBITMAP_TYPE_GIF); if (!image->Ok()) return false; @@ -186,7 +193,7 @@ bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const // Get data for current frame -wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const +wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const { return wxSize(GetFrame(frame)->w, GetFrame(frame)->h); } @@ -568,15 +575,13 @@ as an End of Information itself) // CanRead: // Returns true if the file looks like a valid GIF, false otherwise. // -bool wxGIFDecoder::CanRead(wxInputStream &stream) const +bool wxGIFDecoder::DoCanRead(wxInputStream &stream) const { unsigned char buf[3]; if ( !stream.Read(buf, WXSIZEOF(buf)) ) return false; - stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0; } @@ -593,7 +598,7 @@ bool wxGIFDecoder::CanRead(wxInputStream &stream) const wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) { unsigned int global_ncolors = 0; - int bits, interl, transparent, i; + int bits, interl, i; wxAnimationDisposal disposal; long size; long delay; @@ -655,7 +660,7 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) } // transparent colour, disposal method and delay default to unused - transparent = -1; + int transparent = -1; disposal = wxANIM_UNSPECIFIED; delay = -1; @@ -705,8 +710,7 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) delay = 10 * (buf[2] + 256 * buf[3]); // read transparent colour index, if used - if (buf[1] & 0x01) - transparent = buf[4]; + transparent = buf[1] & 0x01 ? buf[4] : -1; // read disposal method disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1); @@ -716,12 +720,12 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) { while ((i = (unsigned char)stream.GetC()) != 0) { - if (stream.Eof() || (stream.LastRead() == 0)) + if (stream.Eof() || (stream.LastRead() == 0) || + stream.SeekI(i, wxFromCurrent) == wxInvalidOffset) { done = true; break; } - stream.SeekI(i, wxFromCurrent); } } } @@ -730,22 +734,18 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) if (type == 0x2C) { // allocate memory for IMAGEN struct - GIFImage *pimg = new GIFImage(); + GIFImagePtr pimg(new GIFImage()); - if (pimg == NULL) - { - Destroy(); + 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) - { - Destroy(); return wxGIF_INVFORMAT; - } pimg->left = buf[0] + 256 * buf[1]; pimg->top = buf[2] + 256 * buf[3]; @@ -756,11 +756,29 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) pimg->w = buf[4] + 256 * buf[5]; pimg->h = buf[6] + 256 * buf[7]; - if (anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || - (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight()))) + if ( anim ) { - Destroy(); - return wxGIF_INVFORMAT; + // 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); @@ -775,10 +793,7 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) 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) @@ -788,10 +803,7 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) stream.Read(pimg->pal, numBytes); pimg->ncolours = local_ncolors; if (stream.LastRead() != numBytes) - { - Destroy(); return wxGIF_INVFORMAT; - } } else { @@ -802,21 +814,17 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) // get initial code size from first byte in raster data bits = (unsigned char)stream.GetC(); if (bits == 0) - { - Destroy(); return wxGIF_INVFORMAT; - } // decode image - wxGIFErrorCode result = dgif(stream, pimg, interl, bits); + wxGIFErrorCode result = dgif(stream, pimg.get(), interl, bits); if (result != wxGIF_OK) - { - Destroy(); return result; - } + + guardDestroy.Dismiss(); // add the image to our frame array - m_frames.Add((void*)pimg); + m_frames.Add(pimg.release()); m_nFrames++; // if this is not an animated GIF, exit after first image @@ -847,12 +855,12 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) // skip all data while ((i = (unsigned char)stream.GetC()) != 0) { - if (stream.Eof() || (stream.LastRead() == 0)) + if (stream.Eof() || (stream.LastRead() == 0) || + stream.SeekI(i, wxFromCurrent) == wxInvalidOffset) { Destroy(); return wxGIF_INVFORMAT; } - stream.SeekI(i, wxFromCurrent); } } else if (type == 0x2C) @@ -871,7 +879,11 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) { unsigned int local_ncolors = 2 << (buf[8] & 0x07); wxFileOffset numBytes = 3 * local_ncolors; - stream.SeekI(numBytes, wxFromCurrent); + if (stream.SeekI(numBytes, wxFromCurrent) == wxInvalidOffset) + { + Destroy(); + return wxGIF_INVFORMAT; + } } // initial code size @@ -885,12 +897,12 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) // skip all data while ((i = (unsigned char)stream.GetC()) != 0) { - if (stream.Eof() || (stream.LastRead() == 0)) + if (stream.Eof() || (stream.LastRead() == 0) || + stream.SeekI(i, wxFromCurrent) == wxInvalidOffset) { Destroy(); return wxGIF_INVFORMAT; } - stream.SeekI(i, wxFromCurrent); } } else if ((type != 0x3B) && (type != 00)) // testing