X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/72045d5768a126191a907bc640c28e81a11afdd6..8aea37a9df3a2f5ca949ff466bbf698a4b2e3062:/src/common/gifdecod.cpp diff --git a/src/common/gifdecod.cpp b/src/common/gifdecod.cpp index ab507b8d7f..9d8cc1dd71 100644 --- a/src/common/gifdecod.cpp +++ b/src/common/gifdecod.cpp @@ -24,6 +24,8 @@ #include #include #include "wx/gifdecod.h" +#include "wx/ptr_scpd.h" +#include "wx/scopeguard.h" @@ -38,20 +40,22 @@ public: // def ctor GIFImage(); - unsigned int w; /* width */ - unsigned int h; /* height */ - unsigned int left; /* x coord (in logical screen) */ - unsigned int top; /* y coord (in logical screen) */ - int transparent; /* transparent color index (-1 = none) */ - wxAnimationDisposal disposal; /* disposal method */ - long delay; /* delay in ms (-1 = unused) */ - unsigned char *p; /* bitmap */ - unsigned char *pal; /* palette */ - unsigned int ncolours; /* number of colours */ + unsigned int w; // width + unsigned int h; // height + unsigned int left; // x coord (in logical screen) + unsigned int top; // y coord (in logical screen) + int transparent; // transparent color index (-1 = none) + wxAnimationDisposal disposal; // disposal method + long delay; // delay in ms (-1 = unused) + unsigned char *p; // bitmap + unsigned char *pal; // palette + unsigned int ncolours; // number of colours DECLARE_NO_COPY_CLASS(GIFImage) }; +wxDECLARE_SCOPED_PTR(GIFImage, GIFImagePtr) +wxDEFINE_SCOPED_PTR(GIFImage, GIFImagePtr) //--------------------------------------------------------------------------- @@ -87,7 +91,7 @@ wxGIFDecoder::~wxGIFDecoder() void wxGIFDecoder::Destroy() { wxASSERT(m_nFrames==m_frames.GetCount()); - for (size_t i=0; ip); @@ -106,18 +110,19 @@ void wxGIFDecoder::Destroy() // This function was designed by Vaclav Slavik -bool wxGIFDecoder::ConvertToImage(size_t frame, wxImage *image) const +bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const { unsigned char *src, *dst, *pal; unsigned long i; int transparent; - /* just in case... */ + // just in case... image->Destroy(); - /* create the image */ + // create the image wxSize sz = GetFrameSize(frame); image->Create(sz.GetWidth(), sz.GetHeight()); + image->SetType(wxBITMAP_TYPE_GIF); if (!image->Ok()) return false; @@ -125,9 +130,9 @@ bool wxGIFDecoder::ConvertToImage(size_t frame, wxImage *image) const pal = GetPalette(frame); src = GetData(frame); dst = image->GetData(); - transparent = GetTransparentColour(frame); + transparent = GetTransparentColourIndex(frame); - /* set transparent colour mask */ + // set transparent colour mask if (transparent != -1) { for (i = 0; i < GetNcolours(frame); i++) @@ -164,7 +169,7 @@ bool wxGIFDecoder::ConvertToImage(size_t frame, wxImage *image) const image->SetPalette(wxPalette(GetNcolours(frame), r, g, b)); #endif // wxUSE_PALETTE - /* copy image data */ + // copy image data unsigned long npixel = sz.GetWidth() * sz.GetHeight(); for (i = 0; i < npixel; i++, src++) { @@ -186,30 +191,42 @@ bool wxGIFDecoder::ConvertToImage(size_t frame, wxImage *image) const // Get data for current frame -wxSize wxGIFDecoder::GetFrameSize(size_t frame) const +wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const { return wxSize(GetFrame(frame)->w, GetFrame(frame)->h); } -wxPoint wxGIFDecoder::GetFramePosition(size_t frame) const +wxPoint wxGIFDecoder::GetFramePosition(unsigned int frame) const { return wxPoint(GetFrame(frame)->left, GetFrame(frame)->top); } -wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(size_t frame) const +wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(unsigned int frame) const { return GetFrame(frame)->disposal; } -long wxGIFDecoder::GetDelay(size_t frame) const +long wxGIFDecoder::GetDelay(unsigned int frame) const { return GetFrame(frame)->delay; } -unsigned char* wxGIFDecoder::GetData(size_t frame) const { return (GetFrame(frame)->p); } -unsigned char* wxGIFDecoder::GetPalette(size_t frame) const { return (GetFrame(frame)->pal); } -unsigned int wxGIFDecoder::GetNcolours(size_t frame) const { return (GetFrame(frame)->ncolours); } -int wxGIFDecoder::GetTransparentColour(size_t frame) const { return (GetFrame(frame)->transparent); } +wxColour wxGIFDecoder::GetTransparentColour(unsigned int frame) const +{ + unsigned char *pal = GetFrame(frame)->pal; + int n = GetFrame(frame)->transparent; + if (n == -1) + return wxNullColour; + + return wxColour(pal[n*3 + 0], + pal[n*3 + 1], + pal[n*3 + 2]); +} + +unsigned char* wxGIFDecoder::GetData(unsigned int frame) const { return (GetFrame(frame)->p); } +unsigned char* wxGIFDecoder::GetPalette(unsigned int frame) const { return (GetFrame(frame)->pal); } +unsigned int wxGIFDecoder::GetNcolours(unsigned int frame) const { return (GetFrame(frame)->ncolours); } +int wxGIFDecoder::GetTransparentColourIndex(unsigned int frame) const { return (GetFrame(frame)->transparent); } @@ -222,17 +239,17 @@ int wxGIFDecoder::GetTransparentColour(size_t frame) const { return (GetFrame(f // int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) { - unsigned int mask; /* bit mask */ - unsigned int code; /* code (result) */ + unsigned int mask; // bit mask + unsigned int code; // code (result) - /* get remaining bits from last byte read */ + // get remaining bits from last byte read mask = (1 << bits) - 1; code = (m_lastbyte >> (8 - m_restbits)) & mask; - /* keep reading new bytes while needed */ + // keep reading new bytes while needed while (bits > m_restbits) { - /* if no bytes left in this block, read the next block */ + // if no bytes left in this block, read the next block if (m_restbyte == 0) { m_restbyte = (unsigned char)stream.GetC(); @@ -248,7 +265,7 @@ int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) break; } - /* prefetch data */ + // prefetch data stream.Read((void *) m_buffer, m_restbyte); if (stream.LastRead() != m_restbyte) { @@ -258,17 +275,17 @@ int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) m_bufp = m_buffer; } - /* read next byte and isolate the bits we need */ + // read next byte and isolate the bits we need m_lastbyte = (unsigned char) (*m_bufp++); mask = (1 << (bits - m_restbits)) - 1; code = code + ((m_lastbyte & mask) << m_restbits); m_restbyte--; - /* adjust total number of bits extracted from the buffer */ + // adjust total number of bits extracted from the buffer m_restbits = m_restbits + 8; } - /* find number of bits remaining for next code */ + // find number of bits remaining for next code m_restbits = (m_restbits - bits); return code; @@ -280,23 +297,24 @@ int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) // is 'bits'. Supports interlaced images (interl == 1). // Returns wxGIF_OK (== 0) on success, or an error code if something // fails (see header file for details) -wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits) +wxGIFErrorCode +wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits) { static const int allocSize = 4096 + 1; - int *ab_prefix = new int[allocSize]; /* alphabet (prefixes) */ + int *ab_prefix = new int[allocSize]; // alphabet (prefixes) if (ab_prefix == NULL) { return wxGIF_MEMERR; } - int *ab_tail = new int[allocSize]; /* alphabet (tails) */ + int *ab_tail = new int[allocSize]; // alphabet (tails) if (ab_tail == NULL) { delete[] ab_prefix; return wxGIF_MEMERR; } - int *stack = new int[allocSize]; /* decompression stack */ + int *stack = new int[allocSize]; // decompression stack if (stack == NULL) { delete[] ab_prefix; @@ -304,22 +322,22 @@ wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int inte return wxGIF_MEMERR; } - int ab_clr; /* clear code */ - int ab_fin; /* end of info code */ - int ab_bits; /* actual symbol width, in bits */ - int ab_free; /* first free position in alphabet */ - int ab_max; /* last possible character in alphabet */ - int pass; /* pass number in interlaced images */ - int pos; /* index into decompresion stack */ - unsigned int x, y; /* position in image buffer */ + int ab_clr; // clear code + int ab_fin; // end of info code + int ab_bits; // actual symbol width, in bits + int ab_free; // first free position in alphabet + int ab_max; // last possible character in alphabet + int pass; // pass number in interlaced images + int pos; // index into decompresion stack + unsigned int x, y; // position in image buffer int code, readcode, lastcode, abcabca; - /* these won't change */ + // these won't change ab_clr = (1 << bits); ab_fin = (1 << bits) + 1; - /* these will change through the decompression proccess */ + // these will change through the decompression proccess ab_bits = bits + 1; ab_free = (1 << bits) + 2; ab_max = (1 << ab_bits) - 1; @@ -328,41 +346,41 @@ wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int inte pass = 1; pos = x = y = 0; - /* reset decoder vars */ + // reset decoder vars m_restbits = 0; m_restbyte = 0; m_lastbyte = 0; do { - /* get next code */ + // get next code readcode = code = getcode(stream, ab_bits, ab_fin); - /* end of image? */ + // end of image? if (code == ab_fin) break; - /* reset alphabet? */ + // reset alphabet? if (code == ab_clr) { - /* reset main variables */ + // reset main variables ab_bits = bits + 1; ab_free = (1 << bits) + 2; ab_max = (1 << ab_bits) - 1; lastcode = -1; abcabca = -1; - /* skip to next code */ + // skip to next code continue; } - /* unknown code: special case (like in ABCABCA) */ + // unknown code: special case (like in ABCABCA) if (code >= ab_free) { - code = lastcode; /* take last string */ - stack[pos++] = abcabca; /* add first character */ + code = lastcode; // take last string + stack[pos++] = abcabca; // add first character } - /* build the string for this code in the stack */ + // build the string for this code in the stack while (code > ab_clr) { stack[pos++] = ab_tail[code]; @@ -388,10 +406,10 @@ wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int inte return wxGIF_INVFORMAT; } - stack[pos] = code; /* push last code into the stack */ - abcabca = code; /* save for special case */ + stack[pos] = code; // push last code into the stack + abcabca = code; // save for special case - /* make new entry in alphabet (only if NOT just cleared) */ + // make new entry in alphabet (only if NOT just cleared) if (lastcode != -1) { // Normally, after the alphabet is full and can't grow any @@ -424,7 +442,7 @@ wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int inte } } - /* dump stack data to the image buffer */ + // dump stack data to the image buffer while (pos >= 0) { (img->p)[x + (y * (img->w))] = (char) stack[pos]; @@ -436,7 +454,7 @@ wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int inte if (interl) { - /* support for interlaced images */ + // support for interlaced images switch (pass) { case 1: y += 8; break; @@ -493,7 +511,7 @@ wxGIFErrorCode wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int inte } else { - /* non-interlaced */ + // non-interlaced y++; /* Normally image decoding is finished when an End of Information code is @@ -580,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; @@ -589,13 +607,13 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) unsigned char buf[16]; bool anim = true; - /* check GIF signature */ + // check GIF signature if (!CanRead(stream)) return wxGIF_INVFORMAT; - /* check for animated GIF support (ver. >= 89a) */ + // check for animated GIF support (ver. >= 89a) - static const size_t headerSize = (3 + 3); + static const unsigned int headerSize = (3 + 3); stream.Read(buf, headerSize); if (stream.LastRead() != headerSize) { @@ -607,8 +625,8 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) anim = false; } - /* read logical screen descriptor block (LSDB) */ - static const size_t lsdbSize = (2 + 2 + 1 + 1 + 1); + // read logical screen descriptor block (LSDB) + static const unsigned int lsdbSize = (2 + 2 + 1 + 1 + 1); stream.Read(buf, lsdbSize); if (stream.LastRead() != lsdbSize) { @@ -618,18 +636,18 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) m_szAnimation.SetWidth( buf[0] + 256 * buf[1] ); m_szAnimation.SetHeight( buf[2] + 256 * buf[3] ); - if ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0)) + if (anim && ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0))) { return wxGIF_INVFORMAT; } - /* load global color map if available */ + // load global color map if available if ((buf[4] & 0x80) == 0x80) { int backgroundColIndex = buf[5]; global_ncolors = 2 << (buf[4] & 0x07); - size_t numBytes = 3 * global_ncolors; + unsigned int numBytes = 3 * global_ncolors; stream.Read(pal, numBytes); if (stream.LastRead() != numBytes) { @@ -641,8 +659,8 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) pal[backgroundColIndex*3 + 2]); } - /* transparent colour, disposal method and delay default to unused */ - transparent = -1; + // transparent colour, disposal method and delay default to unused + int transparent = -1; disposal = wxANIM_UNSPECIFIED; delay = -1; @@ -668,19 +686,19 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) break; // Alternative : "return wxGIF_INVFORMAT;" } - /* end of data? */ + // end of data? if (type == 0x3B) { done = true; } else - /* extension block? */ + // extension block? if (type == 0x21) { if (((unsigned char)stream.GetC()) == 0xF9) - /* graphics control extension, parse it */ + // graphics control extension, parse it { - static const size_t gceSize = 6; + static const unsigned int gceSize = 6; stream.Read(buf, gceSize); if (stream.LastRead() != gceSize) { @@ -688,51 +706,46 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) return wxGIF_INVFORMAT; } - /* read delay and convert from 1/100 of a second to ms */ + // 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 transparent colour index, if used + transparent = buf[1] & 0x01 ? buf[4] : -1; - /* read disposal method */ + // read disposal method disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1); } else - /* other extension, skip */ + // other extension, skip { while ((i = (unsigned char)stream.GetC()) != 0) { - stream.SeekI(i, wxFromCurrent); - if (stream.Eof()) + if (stream.Eof() || (stream.LastRead() == 0)) { done = true; break; } + stream.SeekI(i, wxFromCurrent); } } } else - /* image descriptor block? */ + // image descriptor block? if (type == 0x2C) { - /* allocate memory for IMAGEN struct */ - GIFImage *pimg = new GIFImage(); + // allocate memory for IMAGEN struct + 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 size_t idbSize = (2 + 2 + 2 + 2 + 1); + // 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]; @@ -743,12 +756,9 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) pimg->w = buf[4] + 256 * buf[5]; pimg->h = buf[6] + 256 * buf[7]; - if ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || - (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight())) - { - Destroy(); + if ( anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || + (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight())) ) return wxGIF_INVFORMAT; - } interl = ((buf[8] & 0x40)? 1 : 0); size = pimg->w * pimg->h; @@ -757,28 +767,22 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) pimg->disposal = disposal; pimg->delay = delay; - /* allocate memory for image and palette */ - pimg->p = (unsigned char *) malloc((size_t)size); + // 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)) - { - Destroy(); return wxGIF_MEMERR; - } - /* load local color map if available, else use global map */ + // load local color map if available, else use global map if ((buf[8] & 0x80) == 0x80) { unsigned int local_ncolors = 2 << (buf[8] & 0x07); - size_t numBytes = 3 * local_ncolors; + unsigned int numBytes = 3 * local_ncolors; stream.Read(pimg->pal, numBytes); pimg->ncolours = local_ncolors; if (stream.LastRead() != numBytes) - { - Destroy(); return wxGIF_INVFORMAT; - } } else { @@ -786,27 +790,23 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) pimg->ncolours = global_ncolors; } - /* get initial code size from first byte in raster data */ + // 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); + // decode image + wxGIFErrorCode result = dgif(stream, pimg.get(), interl, bits); if (result != wxGIF_OK) - { - Destroy(); return result; - } - /* add the image to our frame array */ - m_frames.Add((void*)pimg); + 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 this is not an animated GIF, exit after first image if (!anim) done = true; } @@ -818,7 +818,7 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) return wxGIF_INVFORMAT; } - /* try to read to the end of the stream */ + // try to read to the end of the stream while (type != 0x3B) { if (!stream.IsOk()) @@ -828,19 +828,24 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) if (type == 0x21) { - /* extension type */ + // extension type (void) stream.GetC(); - /* skip all data */ + // skip all data while ((i = (unsigned char)stream.GetC()) != 0) { + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } stream.SeekI(i, wxFromCurrent); } } else if (type == 0x2C) { - /* image descriptor block */ - static const size_t idbSize = (2 + 2 + 2 + 2 + 1); + // image descriptor block + static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); stream.Read(buf, idbSize); if (stream.LastRead() != idbSize) { @@ -848,32 +853,36 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) return wxGIF_INVFORMAT; } - /* local color map */ + // local color map if ((buf[8] & 0x80) == 0x80) { unsigned int local_ncolors = 2 << (buf[8] & 0x07); - wxFileOffset pos = stream.TellI(); wxFileOffset numBytes = 3 * local_ncolors; stream.SeekI(numBytes, wxFromCurrent); - if (stream.TellI() != (pos + numBytes)) - { - Destroy(); - return wxGIF_INVFORMAT; - } } - /* initial code size */ + // initial code size (void) stream.GetC(); + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } - /* skip all data */ + // skip all data while ((i = (unsigned char)stream.GetC()) != 0) { + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } stream.SeekI(i, wxFromCurrent); } } - else if ((type != 0x3B) && (type != 00)) /* testing */ + else if ((type != 0x3B) && (type != 00)) // testing { - /* images are OK, but couldn't read to the end of the stream */ + // images are OK, but couldn't read to the end of the stream return wxGIF_TRUNCATED; } }