Let gif "ignore too much" quirk skip lzw errors
The modified test/data/*/*.gif files differ by only one byte:
00000000 47 49 46 38 39 61 02 00 02 00 81 00 00 00 00 ff |GIF89a..........|
00000010 11 00 ff 22 00 ff 33 00 ff 2c 00 00 00 00 02 00 |..."..3..,......|
-00000020 02 00 00 02 02 84 f1 00 3b |........;|
+00000020 02 00 00 02 02 84 5d 00 3b |......].;|
The etc-good-lzw.gif bits have changed, even though the
etc-good-lzw.etc.txt file only had comments added, due to a Go standard
library change: "compress/lzw: output a Clear code first, per GIF spec"
https://github.com/golang/go/commit/9c1dbdf60edbffeff10f58af21fa055eb0fdd29f
Updates PR #57
Updates https://crbug.com/1270631
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index ff21071..a8aeb09 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -31152,6 +31152,30 @@
goto label__outer__continue;
} else if (v_lzw_status.repr == wuffs_base__suspension__short_write) {
goto label__inner__continue;
+ } else if (self->private_impl.f_quirks[3] && (self->private_impl.f_dst_y >= self->private_impl.f_frame_rect_y1) && (self->private_impl.f_interlace == 0)) {
+ if (v_need_block_size || (v_block_size > 0)) {
+ self->private_data.s_decode_id_part2[0].scratch = ((uint32_t)(v_block_size));
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
+ if (self->private_data.s_decode_id_part2[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_id_part2[0].scratch -= ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_decode_id_part2[0].scratch;
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ status = wuffs_gif__decoder__skip_blocks(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ }
+ goto label__outer__break;
}
status = v_lzw_status;
if (wuffs_base__status__is_error(&status)) {
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index b5de857..f2a3309 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -954,6 +954,17 @@
continue.outer
} else if lzw_status == base."$short write" {
continue.inner
+ } else if this.quirks[QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA - QUIRKS_BASE] and
+ (this.dst_y >= this.frame_rect_y1) and (this.interlace == 0) {
+ // It's invalid LZW-compressed data, but we still have a full
+ // frame and have opted in to QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA,
+ // so treat it like the lzw_status.is_ok() case, other than not
+ // clearing this.previous_lzw_decode_ended_abruptly.
+ if need_block_size or (block_size > 0) {
+ args.src.skip_u32?(n: block_size as base.u32)
+ this.skip_blocks?(src: args.src)
+ }
+ break.outer
}
return lzw_status
} endwhile.inner
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index ddbdc83..b620bc8 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -1598,11 +1598,20 @@
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = g_src_slice_u8,
});
+
+ src.meta = wuffs_base__empty_io_buffer_meta();
+ CHECK_STRING(read_file(
+ &src, "test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif"));
+ CHECK_STRING(do_test_wuffs_gif_decode_expecting(
+ src, 0, wuffs_lzw__error__bad_code, false));
+
+ src.meta = wuffs_base__empty_io_buffer_meta();
CHECK_STRING(read_file(
&src, "test/data/artificial-gif/pixel-data-too-much-good-lzw.gif"));
+ CHECK_STRING(do_test_wuffs_gif_decode_expecting(
+ src, 0, wuffs_base__error__too_much_data, false));
- return do_test_wuffs_gif_decode_expecting(
- src, 0, wuffs_base__error__too_much_data, false);
+ return NULL;
}
const char* //
@@ -1611,11 +1620,20 @@
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = g_src_slice_u8,
});
+
+ src.meta = wuffs_base__empty_io_buffer_meta();
+ CHECK_STRING(read_file(
+ &src, "test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif"));
+ CHECK_STRING(do_test_wuffs_gif_decode_expecting(
+ src, WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA, NULL, false));
+
+ src.meta = wuffs_base__empty_io_buffer_meta();
CHECK_STRING(read_file(
&src, "test/data/artificial-gif/pixel-data-too-much-good-lzw.gif"));
+ CHECK_STRING(do_test_wuffs_gif_decode_expecting(
+ src, WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA, NULL, false));
- return do_test_wuffs_gif_decode_expecting(
- src, WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA, NULL, false);
+ return NULL;
}
const char* //
diff --git a/test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif b/test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif
new file mode 100644
index 0000000..d53dfba
--- /dev/null
+++ b/test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif
Binary files differ
diff --git a/test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif.make-artificial.txt b/test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif.make-artificial.txt
new file mode 100644
index 0000000..9ba0a36
--- /dev/null
+++ b/test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif.make-artificial.txt
@@ -0,0 +1,37 @@
+# Feed this file to script/make-artificial.go
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 2 2
+ palette {
+ 0x00 0x00 0xFF
+ 0x11 0x00 0xFF
+ 0x22 0x00 0xFF
+ 0x33 0x00 0xFF
+ }
+}
+
+frame {
+ frameLeftTopWidthHeight 0 0 2 2
+}
+
+# The frame area is 4 pixels and we supply 4 but then an invalid LZW code.
+# Compare with pixel-data-too-much-good-lzw.gif.make-artificial.txt
+#
+# The disassembly (see also std/lzw/README.md) is:
+#
+# 0x02 LZW literal width.
+# 0x02 GIF block length.
+# 0x84 0xF1 = 0b1111_0001_1000_0100 (little endian).
+# 0b...._...._...._.100 3-bit Clear code.
+# 0b...._...._..00_0... 3-bit Literal 0x00.
+# 0b...._...1_10.._.... 3-bit Copy code (2 bytes).
+# 0b...._000._...._.... 3-bit Literal 0x00.
+# 0b1111_...._...._.... 4-bit Invalid code.
+# 0x00 GIF block terminator.
+bytes 0x02 0x02 0x84 0xF1 0x00
+
+trailer
diff --git a/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif b/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif
index 573ec88..91ba6a3 100644
--- a/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif
+++ b/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif
Binary files differ
diff --git a/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif.make-artificial.txt b/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif.make-artificial.txt
index 5f02c1b..166c8cf 100644
--- a/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif.make-artificial.txt
+++ b/test/data/artificial-gif/pixel-data-too-much-good-lzw.gif.make-artificial.txt
@@ -17,7 +17,21 @@
frame {
frameLeftTopWidthHeight 0 0 2 2
}
-# The frame is 4 pixels, but we supply 5.
+
+# The frame area is 4 pixels but we supply 5 (that's still valid LZW data).
+# Compare with pixel-data-too-much-bad-lzw.gif.make-artificial.txt
+#
+# The equivalent bytes' disassembly (see also std/lzw/README.md) is:
+#
+# 0x02 LZW literal width.
+# 0x02 GIF block length.
+# 0x84 0x5D = 0b0101_1101_1000_0100 (little endian).
+# 0b...._...._...._.100 3-bit Clear code.
+# 0b...._...._..00_0... 3-bit Literal 0x00.
+# 0b...._...1_10.._.... 3-bit Copy code (2 bytes).
+# 0b...._110._...._.... 3-bit Copy code (2 bytes).
+# 0b0101_...._...._.... 4-bit End code.
+# 0x00 GIF block terminator.
lzw 2 0x00 0x00 0x00 0x00 0x00
trailer
diff --git a/test/nia-checksums-of-data.txt b/test/nia-checksums-of-data.txt
index 5c65b37..b3f390e 100644
--- a/test/nia-checksums-of-data.txt
+++ b/test/nia-checksums-of-data.txt
@@ -16,6 +16,7 @@
76c44866 test/data/artificial-gif/no-frames.gif
6ec818c3 test/data/artificial-gif/pixel-data-none.gif
5e57adb2 test/data/artificial-gif/pixel-data-not-enough.gif
+3e29f88a test/data/artificial-gif/pixel-data-too-much-bad-lzw.gif
3e29f88a test/data/artificial-gif/pixel-data-too-much-good-lzw.gif
f50d1d50 test/data/artificial-gif/small-frame-interlaced.gif
beaec397 test/data/artificial-gif/transparent-index.gif