- /* get next code */
- readcode = code = getcode(ab_bits, ab_fin);
-
- /* end of image? */
- if (code == ab_fin) break;
-
- /* reset alphabet? */
- if (code == ab_clr)
- {
- /* reset main variables */
- ab_bits = bits + 1;
- ab_free = (1 << bits) + 2;
- ab_max = (1 << ab_bits) - 1;
- lastcode = -1;
- abcabca = -1;
-
- /* skip to next code */
- continue;
- }
-
- /* unknown code: special case (like in ABCABCA) */
- if (code >= ab_free)
- {
- code = lastcode; /* take last string */
- stack[pos++] = abcabca; /* add first character */
- }
-
- /* build the string for this code in the stack */
- while (code > ab_clr)
- {
- stack[pos++] = ab_tail[code];
- code = ab_prefix[code];
- }
- stack[pos] = code; /* push last code into the stack */
- abcabca = code; /* save for special case */
-
- /* make new entry in alphabet (only if NOT just cleared) */
- if (lastcode != -1)
- {
- ab_prefix[ab_free] = lastcode;
- ab_tail[ab_free] = code;
- ab_free++;
-
- if ((ab_free > ab_max) && (ab_bits < 12))
- {
- ab_bits++;
- ab_max = (1 << ab_bits) - 1;
- }
- }
-
- /* dump stack data to the buffer */
- while (pos >= 0)
- {
- (img->p)[x + (y * (img->w))] = (char)stack[pos--];
-
- if (++x >= (img->w))
- {
- x = 0;
-
- if (interl)
- {
- /* support for interlaced images */
- switch (pass)
- {
- case 1: y += 8; break;
- case 2: y += 8; break;
- case 3: y += 4; break;
- case 4: y += 2; break;
- }
- if (y >= (img->h))
- {
- switch (++pass)
- {
- case 2: y = 4; break;
- case 3: y = 2; break;
- case 4: y = 1; break;
- }
- }
- }
- else
- {
- /* non-interlaced */
- y++;
- }
- }
- }
-
- pos = 0;
- lastcode = readcode;
+ // get next code
+ readcode = code = getcode(stream, ab_bits, ab_fin);
+
+ // end of image?
+ if (code == ab_fin) break;
+
+ // reset alphabet?
+ if (code == ab_clr)
+ {
+ // reset main variables
+ ab_bits = bits + 1;
+ ab_free = (1 << bits) + 2;
+ ab_max = (1 << ab_bits) - 1;
+ lastcode = -1;
+ abcabca = -1;
+
+ // skip to next code
+ continue;
+ }
+
+ // unknown code: special case (like in ABCABCA)
+ if (code >= ab_free)
+ {
+ code = lastcode; // take last string
+ stack[pos++] = abcabca; // add first character
+ }
+
+ // build the string for this code in the stack
+ while (code > ab_clr)
+ {
+ stack[pos++] = ab_tail[code];
+ code = ab_prefix[code];
+
+ // Don't overflow. This shouldn't happen with normal
+ // GIF files, the allocSize of 4096+1 is enough. This
+ // will only happen with badly formed GIFs.
+ if (pos >= allocSize)
+ {
+ delete[] ab_prefix;
+ delete[] ab_tail;
+ delete[] stack;
+ return wxGIF_INVFORMAT;
+ }
+ }
+
+ if (pos >= allocSize)
+ {
+ delete[] ab_prefix;
+ delete[] ab_tail;
+ delete[] stack;
+ return wxGIF_INVFORMAT;
+ }
+
+ stack[pos] = code; // push last code into the stack
+ abcabca = code; // save for special case
+
+ // make new entry in alphabet (only if NOT just cleared)
+ if (lastcode != -1)
+ {
+ // Normally, after the alphabet is full and can't grow any
+ // further (ab_free == 4096), encoder should (must?) emit CLEAR
+ // to reset it. This checks whether we really got it, otherwise
+ // the GIF is damaged.
+ if (ab_free > ab_max)
+ {
+ delete[] ab_prefix;
+ delete[] ab_tail;
+ delete[] stack;
+ return wxGIF_INVFORMAT;
+ }
+
+ // This assert seems unnecessary since the condition above
+ // eliminates the only case in which it went false. But I really
+ // don't like being forced to ask "Who in .text could have
+ // written there?!" And I wouldn't have been forced to ask if
+ // this line had already been here.
+ wxASSERT(ab_free < allocSize);
+
+ ab_prefix[ab_free] = lastcode;
+ ab_tail[ab_free] = code;
+ ab_free++;
+
+ if ((ab_free > ab_max) && (ab_bits < 12))
+ {
+ ab_bits++;
+ ab_max = (1 << ab_bits) - 1;
+ }
+ }
+
+ // dump stack data to the image buffer
+ while (pos >= 0)
+ {
+ (img->p)[x + (y * (img->w))] = (char) stack[pos];
+ pos--;
+
+ if (++x >= (img->w))
+ {
+ x = 0;
+
+ if (interl)
+ {
+ // support for interlaced images
+ switch (pass)
+ {
+ case 1: y += 8; break;
+ case 2: y += 8; break;
+ case 3: y += 4; break;
+ case 4: y += 2; break;
+ }
+
+ /* loop until a valid y coordinate has been
+ found, Or if the maximum number of passes has
+ been reached, exit the loop, and stop image
+ decoding (At this point the image is successfully
+ decoded).
+ If we don't loop, but merely set y to some other
+ value, that new value might still be invalid depending
+ on the height of the image. This would cause out of
+ bounds writing.
+ */
+ while (y >= (img->h))
+ {
+ switch (++pass)
+ {
+ case 2: y = 4; break;
+ case 3: y = 2; break;
+ case 4: y = 1; break;
+
+ default:
+ /*
+ It's possible we arrive here. For example this
+ happens when the image is interlaced, and the
+ height is 1. Looking at the above cases, the
+ lowest possible y is 1. While the only valid
+ one would be 0 for an image of height 1. So
+ 'eventually' the loop will arrive here.
+ This case makes sure this while loop is
+ exited, as well as the 2 other ones.
+ */
+
+ // Set y to a valid coordinate so the local
+ // while loop will be exited. (y = 0 always
+ // is >= img->h since if img->h == 0 the
+ // image is never decoded)
+ y = 0;
+
+ // This will exit the other outer while loop
+ pos = -1;
+
+ // This will halt image decoding.
+ code = ab_fin;
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ // non-interlaced
+ y++;
+/*
+Normally image decoding is finished when an End of Information code is
+encountered (code == ab_fin) however some broken encoders write wrong
+"block byte counts" (The first byte value after the "code size" byte),
+being one value too high. It might very well be possible other variants
+of this problem occur as well. The only sensible solution seems to
+be to check for clipping.
+Example of wrong encoding:
+(1 * 1 B/W image, raster data stream follows in hex bytes)
+
+02 << B/W images have a code size of 2
+02 << Block byte count
+44 << LZW packed
+00 << Zero byte count (terminates data stream)
+
+Because the block byte count is 2, the zero byte count is used in the
+decoding process, and decoding is continued after this byte. (While it
+should signal an end of image)
+
+It should be:
+02
+02
+44
+01 << When decoded this correctly includes the End of Information code
+00
+
+Or (Worse solution):
+02
+01
+44
+00
+(The 44 doesn't include an End of Information code, but at least the
+decoder correctly skips to 00 now after decoding, and signals this
+as an End of Information itself)
+*/
+ if (y >= img->h)
+ {
+ code = ab_fin;
+ break;
+ }
+ }
+ }
+ }
+
+ pos = 0;
+ lastcode = readcode;