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