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