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