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