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