1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/gifdecod.cpp
3 // Purpose:     wxGIFDecoder, GIF reader for wxImage and wxAnimation
4 // Author:      Guillermo Rodriguez Garcia <guille@iies.es>
5 // Version:     3.04
6 // RCS-ID:      $Id: gifdecod.cpp 62183 2009-09-28 09:40:20Z JS $
7 // Copyright:   (c) Guillermo Rodriguez Garcia
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 #if wxUSE_STREAMS && wxUSE_GIF
19 
20 #ifndef WX_PRECOMP
21     #include "wx/palette.h"
22     #include "wx/log.h"
23     #include "wx/intl.h"
24 #endif
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include "wx/gifdecod.h"
29 
30 
31 
32 //---------------------------------------------------------------------------
33 // GIFImage
34 //---------------------------------------------------------------------------
35 
36 // internal class for storing GIF image data
37 class GIFImage
38 {
39 public:
40     // def ctor
41     GIFImage();
42 
43     unsigned int w;                 // width
44     unsigned int h;                 // height
45     unsigned int left;              // x coord (in logical screen)
46     unsigned int top;               // y coord (in logical screen)
47     int transparent;                // transparent color index (-1 = none)
48     wxAnimationDisposal disposal;   // disposal method
49     long delay;                     // delay in ms (-1 = unused)
50     unsigned char *p;               // bitmap
51     unsigned char *pal;             // palette
52     unsigned int ncolours;          // number of colours
53 
54     DECLARE_NO_COPY_CLASS(GIFImage)
55 };
56 
57 
58 
59 //---------------------------------------------------------------------------
60 // GIFImage constructor
61 //---------------------------------------------------------------------------
GIFImage()62 GIFImage::GIFImage()
63 {
64     w = 0;
65     h = 0;
66     left = 0;
67     top = 0;
68     transparent = 0;
69     disposal = wxANIM_DONOTREMOVE;
70     delay = -1;
71     p = (unsigned char *) NULL;
72     pal = (unsigned char *) NULL;
73     ncolours = 0;
74 }
75 
76 //---------------------------------------------------------------------------
77 // wxGIFDecoder constructor and destructor
78 //---------------------------------------------------------------------------
79 
wxGIFDecoder()80 wxGIFDecoder::wxGIFDecoder()
81 {
82 }
83 
~wxGIFDecoder()84 wxGIFDecoder::~wxGIFDecoder()
85 {
86     Destroy();
87 }
88 
Destroy()89 void wxGIFDecoder::Destroy()
90 {
91     wxASSERT(m_nFrames==m_frames.GetCount());
92     for (unsigned int i=0; i<m_nFrames; i++)
93     {
94         GIFImage *f = (GIFImage*)m_frames[i];
95         free(f->p);
96         free(f->pal);
97         delete f;
98     }
99 
100     m_frames.Clear();
101     m_nFrames = 0;
102 }
103 
104 
105 //---------------------------------------------------------------------------
106 // Convert this image to a wxImage object
107 //---------------------------------------------------------------------------
108 
109 // This function was designed by Vaclav Slavik
110 
ConvertToImage(unsigned int frame,wxImage * image) const111 bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const
112 {
113     unsigned char *src, *dst, *pal;
114     unsigned long i;
115     int      transparent;
116 
117     // just in case...
118     image->Destroy();
119 
120     // create the image
121     wxSize sz = GetFrameSize(frame);
122     image->Create(sz.GetWidth(), sz.GetHeight());
123 
124     if (!image->Ok())
125         return false;
126 
127     pal = GetPalette(frame);
128     src = GetData(frame);
129     dst = image->GetData();
130     transparent = GetTransparentColourIndex(frame);
131 
132     // set transparent colour mask
133     if (transparent != -1)
134     {
135         for (i = 0; i < GetNcolours(frame); i++)
136         {
137             if ((pal[3 * i + 0] == 255) &&
138                 (pal[3 * i + 1] == 0) &&
139                 (pal[3 * i + 2] == 255))
140             {
141                 pal[3 * i + 2] = 254;
142             }
143         }
144 
145         pal[3 * transparent + 0] = 255,
146         pal[3 * transparent + 1] = 0,
147         pal[3 * transparent + 2] = 255;
148 
149         image->SetMaskColour(255, 0, 255);
150     }
151     else
152         image->SetMask(false);
153 
154 #if wxUSE_PALETTE
155     unsigned char r[256];
156     unsigned char g[256];
157     unsigned char b[256];
158 
159     for (i = 0; i < 256; i++)
160     {
161         r[i] = pal[3*i + 0];
162         g[i] = pal[3*i + 1];
163         b[i] = pal[3*i + 2];
164     }
165 
166     image->SetPalette(wxPalette(GetNcolours(frame), r, g, b));
167 #endif // wxUSE_PALETTE
168 
169     // copy image data
170     unsigned long npixel = sz.GetWidth() * sz.GetHeight();
171     for (i = 0; i < npixel; i++, src++)
172     {
173         *(dst++) = pal[3 * (*src) + 0];
174         *(dst++) = pal[3 * (*src) + 1];
175         *(dst++) = pal[3 * (*src) + 2];
176     }
177 
178     return true;
179 }
180 
181 
182 //---------------------------------------------------------------------------
183 // Data accessors
184 //---------------------------------------------------------------------------
185 
186 #define GetFrame(n)     ((GIFImage*)m_frames[n])
187 
188 
189 // Get data for current frame
190 
GetFrameSize(unsigned int frame) const191 wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const
192 {
193     return wxSize(GetFrame(frame)->w, GetFrame(frame)->h);
194 }
195 
GetFramePosition(unsigned int frame) const196 wxPoint wxGIFDecoder::GetFramePosition(unsigned int frame) const
197 {
198     return wxPoint(GetFrame(frame)->left, GetFrame(frame)->top);
199 }
200 
GetDisposalMethod(unsigned int frame) const201 wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(unsigned int frame) const
202 {
203     return GetFrame(frame)->disposal;
204 }
205 
GetDelay(unsigned int frame) const206 long wxGIFDecoder::GetDelay(unsigned int frame) const
207 {
208     return GetFrame(frame)->delay;
209 }
210 
GetTransparentColour(unsigned int frame) const211 wxColour wxGIFDecoder::GetTransparentColour(unsigned int frame) const
212 {
213     unsigned char *pal = GetFrame(frame)->pal;
214     int n = GetFrame(frame)->transparent;
215     if (n == -1)
216         return wxNullColour;
217 
218     return wxColour(pal[n*3 + 0],
219                     pal[n*3 + 1],
220                     pal[n*3 + 2]);
221 }
222 
GetData(unsigned int frame) const223 unsigned char* wxGIFDecoder::GetData(unsigned int frame) const    { return (GetFrame(frame)->p); }
GetPalette(unsigned int frame) const224 unsigned char* wxGIFDecoder::GetPalette(unsigned int frame) const { return (GetFrame(frame)->pal); }
GetNcolours(unsigned int frame) const225 unsigned int wxGIFDecoder::GetNcolours(unsigned int frame) const  { return (GetFrame(frame)->ncolours); }
GetTransparentColourIndex(unsigned int frame) const226 int wxGIFDecoder::GetTransparentColourIndex(unsigned int frame) const  { return (GetFrame(frame)->transparent); }
227 
228 
229 
230 //---------------------------------------------------------------------------
231 // GIF reading and decoding
232 //---------------------------------------------------------------------------
233 
234 // getcode:
235 //  Reads the next code from the file stream, with size 'bits'
236 //
getcode(wxInputStream & stream,int bits,int ab_fin)237 int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin)
238 {
239     unsigned int mask;          // bit mask
240     unsigned int code;          // code (result)
241 
242     // get remaining bits from last byte read
243     mask = (1 << bits) - 1;
244     code = (m_lastbyte >> (8 - m_restbits)) & mask;
245 
246     // keep reading new bytes while needed
247     while (bits > m_restbits)
248     {
249         // if no bytes left in this block, read the next block
250         if (m_restbyte == 0)
251         {
252             m_restbyte = (unsigned char)stream.GetC();
253 
254             /* Some encoders are a bit broken: instead of issuing
255              * an end-of-image symbol (ab_fin) they come up with
256              * a zero-length subblock!! We catch this here so
257              * that the decoder sees an ab_fin code.
258              */
259             if (m_restbyte == 0)
260             {
261                 code = ab_fin;
262                 break;
263             }
264 
265             // prefetch data
266             stream.Read((void *) m_buffer, m_restbyte);
267             if (stream.LastRead() != m_restbyte)
268             {
269                 code = ab_fin;
270                 return code;
271             }
272             m_bufp = m_buffer;
273         }
274 
275         // read next byte and isolate the bits we need
276         m_lastbyte = (unsigned char) (*m_bufp++);
277         mask       = (1 << (bits - m_restbits)) - 1;
278         code       = code + ((m_lastbyte & mask) << m_restbits);
279         m_restbyte--;
280 
281         // adjust total number of bits extracted from the buffer
282         m_restbits = m_restbits + 8;
283     }
284 
285     // find number of bits remaining for next code
286     m_restbits = (m_restbits - bits);
287 
288     return code;
289 }
290 
291 
292 // dgif:
293 //  GIF decoding function. The initial code size (aka root size)
294 //  is 'bits'. Supports interlaced images (interl == 1).
295 //  Returns wxGIF_OK (== 0) on success, or an error code if something
296 // fails (see header file for details)
297 wxGIFErrorCode
dgif(wxInputStream & stream,GIFImage * img,int interl,int bits)298 wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits)
299 {
300     static const int allocSize = 4096 + 1;
301     int *ab_prefix = new int[allocSize]; // alphabet (prefixes)
302     if (ab_prefix == NULL)
303     {
304         return wxGIF_MEMERR;
305     }
306 
307     int *ab_tail = new int[allocSize];   // alphabet (tails)
308     if (ab_tail == NULL)
309     {
310         delete[] ab_prefix;
311         return wxGIF_MEMERR;
312     }
313 
314     int *stack = new int[allocSize];     // decompression stack
315     if (stack == NULL)
316     {
317         delete[] ab_prefix;
318         delete[] ab_tail;
319         return wxGIF_MEMERR;
320     }
321 
322     int ab_clr;                     // clear code
323     int ab_fin;                     // end of info code
324     int ab_bits;                    // actual symbol width, in bits
325     int ab_free;                    // first free position in alphabet
326     int ab_max;                     // last possible character in alphabet
327     int pass;                       // pass number in interlaced images
328     int pos;                        // index into decompresion stack
329     unsigned int x, y;              // position in image buffer
330 
331     int code, readcode, lastcode, abcabca;
332 
333     // these won't change
334     ab_clr = (1 << bits);
335     ab_fin = (1 << bits) + 1;
336 
337     // these will change through the decompression proccess
338     ab_bits  = bits + 1;
339     ab_free  = (1 << bits) + 2;
340     ab_max   = (1 << ab_bits) - 1;
341     lastcode = -1;
342     abcabca  = -1;
343     pass     = 1;
344     pos = x = y = 0;
345 
346     // reset decoder vars
347     m_restbits = 0;
348     m_restbyte = 0;
349     m_lastbyte = 0;
350 
351     do
352     {
353         // get next code
354         readcode = code = getcode(stream, ab_bits, ab_fin);
355 
356         // end of image?
357         if (code == ab_fin) break;
358 
359         // reset alphabet?
360         if (code == ab_clr)
361         {
362             // reset main variables
363             ab_bits  = bits + 1;
364             ab_free  = (1 << bits) + 2;
365             ab_max   = (1 << ab_bits) - 1;
366             lastcode = -1;
367             abcabca  = -1;
368 
369             // skip to next code
370             continue;
371         }
372 
373         // unknown code: special case (like in ABCABCA)
374         if (code >= ab_free)
375         {
376             code = lastcode;            // take last string
377             stack[pos++] = abcabca;     // add first character
378         }
379 
380         // build the string for this code in the stack
381         while (code > ab_clr)
382         {
383             stack[pos++] = ab_tail[code];
384             code         = ab_prefix[code];
385 
386             // Don't overflow. This shouldn't happen with normal
387             // GIF files, the allocSize of 4096+1 is enough. This
388             // will only happen with badly formed GIFs.
389             if (pos >= allocSize)
390             {
391                 delete[] ab_prefix;
392                 delete[] ab_tail;
393                 delete[] stack;
394                 return wxGIF_INVFORMAT;
395             }
396         }
397 
398         if (pos >= allocSize)
399         {
400             delete[] ab_prefix;
401             delete[] ab_tail;
402             delete[] stack;
403             return wxGIF_INVFORMAT;
404         }
405 
406         stack[pos] = code;              // push last code into the stack
407         abcabca    = code;              // save for special case
408 
409         // make new entry in alphabet (only if NOT just cleared)
410         if (lastcode != -1)
411         {
412             // Normally, after the alphabet is full and can't grow any
413             // further (ab_free == 4096), encoder should (must?) emit CLEAR
414             // to reset it. This checks whether we really got it, otherwise
415             // the GIF is damaged.
416             if (ab_free > ab_max)
417             {
418                 delete[] ab_prefix;
419                 delete[] ab_tail;
420                 delete[] stack;
421                 return wxGIF_INVFORMAT;
422             }
423 
424             // This assert seems unnecessary since the condition above
425             // eliminates the only case in which it went false. But I really
426             // don't like being forced to ask "Who in .text could have
427             // written there?!" And I wouldn't have been forced to ask if
428             // this line had already been here.
429             wxASSERT(ab_free < allocSize);
430 
431             ab_prefix[ab_free] = lastcode;
432             ab_tail[ab_free]   = code;
433             ab_free++;
434 
435             if ((ab_free > ab_max) && (ab_bits < 12))
436             {
437                 ab_bits++;
438                 ab_max = (1 << ab_bits) - 1;
439             }
440         }
441 
442         // dump stack data to the image buffer
443         while (pos >= 0)
444         {
445             (img->p)[x + (y * (img->w))] = (char) stack[pos];
446             pos--;
447 
448             if (++x >= (img->w))
449             {
450                 x = 0;
451 
452                 if (interl)
453                 {
454                     // support for interlaced images
455                     switch (pass)
456                     {
457                         case 1: y += 8; break;
458                         case 2: y += 8; break;
459                         case 3: y += 4; break;
460                         case 4: y += 2; break;
461                     }
462 
463                     /* loop until a valid y coordinate has been
464                     found, Or if the maximum number of passes has
465                     been reached, exit the loop, and stop image
466                     decoding (At this point the image is successfully
467                     decoded).
468                     If we don't loop, but merely set y to some other
469                     value, that new value might still be invalid depending
470                     on the height of the image. This would cause out of
471                     bounds writing.
472                     */
473                     while (y >= (img->h))
474                     {
475                         switch (++pass)
476                         {
477                             case 2: y = 4; break;
478                             case 3: y = 2; break;
479                             case 4: y = 1; break;
480 
481                             default:
482                                 /*
483                                 It's possible we arrive here. For example this
484                                 happens when the image is interlaced, and the
485                                 height is 1. Looking at the above cases, the
486                                 lowest possible y is 1. While the only valid
487                                 one would be 0 for an image of height 1. So
488                                 'eventually' the loop will arrive here.
489                                 This case makes sure this while loop is
490                                 exited, as well as the 2 other ones.
491                                 */
492 
493                                 // Set y to a valid coordinate so the local
494                                 // while loop will be exited. (y = 0 always
495                                 // is >= img->h since if img->h == 0 the
496                                 // image is never decoded)
497                                 y = 0;
498 
499                                 // This will exit the other outer while loop
500                                 pos = -1;
501 
502                                 // This will halt image decoding.
503                                 code = ab_fin;
504 
505                                 break;
506                         }
507                     }
508                 }
509                 else
510                 {
511                     // non-interlaced
512                     y++;
513 /*
514 Normally image decoding is finished when an End of Information code is
515 encountered (code == ab_fin) however some broken encoders write wrong
516 "block byte counts" (The first byte value after the "code size" byte),
517 being one value too high. It might very well be possible other variants
518 of this problem occur as well. The only sensible solution seems to
519 be to check for clipping.
520 Example of wrong encoding:
521 (1 * 1 B/W image, raster data stream follows in hex bytes)
522 
523 02  << B/W images have a code size of 2
524 02  << Block byte count
525 44  << LZW packed
526 00  << Zero byte count (terminates data stream)
527 
528 Because the block byte count is 2, the zero byte count is used in the
529 decoding process, and decoding is continued after this byte. (While it
530 should signal an end of image)
531 
532 It should be:
533 02
534 02
535 44
536 01  << When decoded this correctly includes the End of Information code
537 00
538 
539 Or (Worse solution):
540 02
541 01
542 44
543 00
544 (The 44 doesn't include an End of Information code, but at least the
545 decoder correctly skips to 00 now after decoding, and signals this
546 as an End of Information itself)
547 */
548                     if (y >= img->h)
549                     {
550                         code = ab_fin;
551                         break;
552                     }
553                 }
554             }
555         }
556 
557         pos = 0;
558         lastcode = readcode;
559     }
560     while (code != ab_fin);
561 
562     delete [] ab_prefix ;
563     delete [] ab_tail ;
564     delete [] stack ;
565 
566     return wxGIF_OK;
567 }
568 
569 
570 // CanRead:
571 //  Returns true if the file looks like a valid GIF, false otherwise.
572 //
CanRead(wxInputStream & stream) const573 bool wxGIFDecoder::CanRead(wxInputStream &stream) const
574 {
575     unsigned char buf[3];
576 
577     if ( !stream.Read(buf, WXSIZEOF(buf)) )
578         return false;
579 
580     stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent);
581 
582     return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0;
583 }
584 
585 
586 // LoadGIF:
587 //  Reads and decodes one or more GIF images, depending on whether
588 //  animated GIF support is enabled. Can read GIFs with any bit
589 //  size (color depth), but the output images are always expanded
590 //  to 8 bits per pixel. Also, the image palettes always contain
591 //  256 colors, although some of them may be unused. Returns wxGIF_OK
592 //  (== 0) on success, or an error code if something fails (see
593 //  header file for details)
594 //
LoadGIF(wxInputStream & stream)595 wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream)
596 {
597     unsigned int  global_ncolors = 0;
598     int           bits, interl, i;
599     wxAnimationDisposal disposal;
600     long          size;
601     long          delay;
602     unsigned char type = 0;
603     unsigned char pal[768];
604     unsigned char buf[16];
605     bool anim = true;
606 
607     // check GIF signature
608     if (!CanRead(stream))
609         return wxGIF_INVFORMAT;
610 
611     // check for animated GIF support (ver. >= 89a)
612 
613     static const unsigned int headerSize = (3 + 3);
614     stream.Read(buf, headerSize);
615     if (stream.LastRead() != headerSize)
616     {
617         return wxGIF_INVFORMAT;
618     }
619 
620     if (memcmp(buf + 3, "89a", 3) < 0)
621     {
622         anim = false;
623     }
624 
625     // read logical screen descriptor block (LSDB)
626     static const unsigned int lsdbSize = (2 + 2 + 1 + 1 + 1);
627     stream.Read(buf, lsdbSize);
628     if (stream.LastRead() != lsdbSize)
629     {
630         return wxGIF_INVFORMAT;
631     }
632 
633     m_szAnimation.SetWidth( buf[0] + 256 * buf[1] );
634     m_szAnimation.SetHeight( buf[2] + 256 * buf[3] );
635 
636     if (anim && ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0)))
637     {
638         return wxGIF_INVFORMAT;
639     }
640 
641     // load global color map if available
642     if ((buf[4] & 0x80) == 0x80)
643     {
644         int backgroundColIndex = buf[5];
645 
646         global_ncolors = 2 << (buf[4] & 0x07);
647         unsigned int numBytes = 3 * global_ncolors;
648         stream.Read(pal, numBytes);
649         if (stream.LastRead() != numBytes)
650         {
651             return wxGIF_INVFORMAT;
652         }
653 
654         m_background.Set(pal[backgroundColIndex*3 + 0],
655                          pal[backgroundColIndex*3 + 1],
656                          pal[backgroundColIndex*3 + 2]);
657     }
658 
659     // transparent colour, disposal method and delay default to unused
660     int transparent = -1;
661     disposal = wxANIM_UNSPECIFIED;
662     delay = -1;
663 
664     bool done = false;
665     while (!done)
666     {
667         type = (unsigned char)stream.GetC();
668 
669         /*
670         If the end of file has been reached (or an error) and a ";"
671         (0x3B) hasn't been encountered yet, exit the loop. (Without this
672         check the while loop would loop endlessly.) Later on, in the next while
673         loop, the file will be treated as being truncated (But still
674         be decoded as far as possible). returning wxGIF_TRUNCATED is not
675         possible here since some init code is done after this loop.
676         */
677         if (stream.Eof())// || !stream.IsOk())
678         {
679             /*
680             type is set to some bogus value, so there's no
681             need to continue evaluating it.
682             */
683             break; // Alternative : "return wxGIF_INVFORMAT;"
684         }
685 
686         // end of data?
687         if (type == 0x3B)
688         {
689             done = true;
690         }
691         else
692         // extension block?
693         if (type == 0x21)
694         {
695             if (((unsigned char)stream.GetC()) == 0xF9)
696             // graphics control extension, parse it
697             {
698                 static const unsigned int gceSize = 6;
699                 stream.Read(buf, gceSize);
700                 if (stream.LastRead() != gceSize)
701                 {
702                     Destroy();
703                     return wxGIF_INVFORMAT;
704                 }
705 
706                 // read delay and convert from 1/100 of a second to ms
707                 delay = 10 * (buf[2] + 256 * buf[3]);
708 
709                 // read transparent colour index, if used
710                 transparent = buf[1] & 0x01 ? buf[4] : -1;
711 
712                 // read disposal method
713                 disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1);
714             }
715             else
716             // other extension, skip
717             {
718                 while ((i = (unsigned char)stream.GetC()) != 0)
719                 {
720                     if (stream.Eof() || (stream.LastRead() == 0))
721                     {
722                         done = true;
723                         break;
724                     }
725                     stream.SeekI(i, wxFromCurrent);
726                 }
727             }
728         }
729         else
730         // image descriptor block?
731         if (type == 0x2C)
732         {
733             // allocate memory for IMAGEN struct
734             GIFImage *pimg = new GIFImage();
735 
736             if (pimg == NULL)
737             {
738                 Destroy();
739                 return wxGIF_MEMERR;
740             }
741 
742             // fill in the data
743             static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1);
744             stream.Read(buf, idbSize);
745             if (stream.LastRead() != idbSize)
746             {
747                 Destroy();
748                 return wxGIF_INVFORMAT;
749             }
750 
751             pimg->left = buf[0] + 256 * buf[1];
752             pimg->top = buf[2] + 256 * buf[3];
753 /*
754             pimg->left = buf[4] + 256 * buf[5];
755             pimg->top = buf[4] + 256 * buf[5];
756 */
757             pimg->w = buf[4] + 256 * buf[5];
758             pimg->h = buf[6] + 256 * buf[7];
759 
760 #if 0
761             if (anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) ||
762                 (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight())))
763             {
764                 Destroy();
765                 return wxGIF_INVFORMAT;
766             }
767 #endif
768             if ( anim )
769             {
770                 // some GIF images specify incorrect animation size but we can
771                 // still open them if we fix up the animation size, see #9465
772                 if ( m_nFrames == 0 )
773                 {
774                     if ( pimg->w > (unsigned)m_szAnimation.x )
775                         m_szAnimation.x = pimg->w;
776                     if ( pimg->h > (unsigned)m_szAnimation.y )
777                         m_szAnimation.y = pimg->h;
778                 }
779                 else // subsequent frames
780                 {
781                     // check that we have valid size
782                     if ( (!pimg->w || pimg->w > (unsigned)m_szAnimation.x) ||
783                             (!pimg->h || pimg->h > (unsigned)m_szAnimation.y) )
784                     {
785                         wxLogError(_("Incorrect GIF frame size (%u, %d) for the frame #%u"),
786                                    pimg->w, pimg->h, m_nFrames);
787                         Destroy();
788                         return wxGIF_INVFORMAT;
789                     }
790                 }
791             }
792 
793             interl = ((buf[8] & 0x40)? 1 : 0);
794             size = pimg->w * pimg->h;
795 
796             pimg->transparent = transparent;
797             pimg->disposal = disposal;
798             pimg->delay = delay;
799 
800             // allocate memory for image and palette
801             pimg->p   = (unsigned char *) malloc((unsigned int)size);
802             pimg->pal = (unsigned char *) malloc(768);
803 
804             if ((!pimg->p) || (!pimg->pal))
805             {
806                 Destroy();
807                 return wxGIF_MEMERR;
808             }
809 
810             // load local color map if available, else use global map
811             if ((buf[8] & 0x80) == 0x80)
812             {
813                 unsigned int local_ncolors = 2 << (buf[8] & 0x07);
814                 unsigned int numBytes = 3 * local_ncolors;
815                 stream.Read(pimg->pal, numBytes);
816                 pimg->ncolours = local_ncolors;
817                 if (stream.LastRead() != numBytes)
818                 {
819                     Destroy();
820                     return wxGIF_INVFORMAT;
821                 }
822             }
823             else
824             {
825                 memcpy(pimg->pal, pal, 768);
826                 pimg->ncolours = global_ncolors;
827             }
828 
829             // get initial code size from first byte in raster data
830             bits = (unsigned char)stream.GetC();
831             if (bits == 0)
832             {
833                 Destroy();
834                 return wxGIF_INVFORMAT;
835             }
836 
837             // decode image
838             wxGIFErrorCode result = dgif(stream, pimg, interl, bits);
839             if (result != wxGIF_OK)
840             {
841                 Destroy();
842                 return result;
843             }
844 
845             // add the image to our frame array
846             m_frames.Add((void*)pimg);
847             m_nFrames++;
848 
849             // if this is not an animated GIF, exit after first image
850             if (!anim)
851                 done = true;
852         }
853     }
854 
855     if (m_nFrames <= 0)
856     {
857         Destroy();
858         return wxGIF_INVFORMAT;
859     }
860 
861     // try to read to the end of the stream
862     while (type != 0x3B)
863     {
864         if (!stream.IsOk())
865             return wxGIF_TRUNCATED;
866 
867         type = (unsigned char)stream.GetC();
868 
869         if (type == 0x21)
870         {
871             // extension type
872             (void) stream.GetC();
873 
874             // skip all data
875             while ((i = (unsigned char)stream.GetC()) != 0)
876             {
877                 if (stream.Eof() || (stream.LastRead() == 0))
878                 {
879                     Destroy();
880                     return wxGIF_INVFORMAT;
881                 }
882                 stream.SeekI(i, wxFromCurrent);
883             }
884         }
885         else if (type == 0x2C)
886         {
887             // image descriptor block
888             static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1);
889             stream.Read(buf, idbSize);
890             if (stream.LastRead() != idbSize)
891             {
892                 Destroy();
893                 return wxGIF_INVFORMAT;
894             }
895 
896             // local color map
897             if ((buf[8] & 0x80) == 0x80)
898             {
899                 unsigned int local_ncolors = 2 << (buf[8] & 0x07);
900                 wxFileOffset numBytes = 3 * local_ncolors;
901                 stream.SeekI(numBytes, wxFromCurrent);
902             }
903 
904             // initial code size
905             (void) stream.GetC();
906             if (stream.Eof() || (stream.LastRead() == 0))
907             {
908                 Destroy();
909                 return wxGIF_INVFORMAT;
910             }
911 
912             // skip all data
913             while ((i = (unsigned char)stream.GetC()) != 0)
914             {
915                 if (stream.Eof() || (stream.LastRead() == 0))
916                 {
917                     Destroy();
918                     return wxGIF_INVFORMAT;
919                 }
920                 stream.SeekI(i, wxFromCurrent);
921             }
922         }
923         else if ((type != 0x3B) && (type != 00)) // testing
924         {
925             // images are OK, but couldn't read to the end of the stream
926             return wxGIF_TRUNCATED;
927         }
928     }
929 
930     return wxGIF_OK;
931 }
932 
933 #endif // wxUSE_STREAMS && wxUSE_GIF
934