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