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