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