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