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