Allow an LZW literal width of 1
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 64c89b4..14d3e60 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -8102,7 +8102,7 @@
if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
return wuffs_base__make_empty_struct();
}
- if (a_lw < 2 || a_lw > 8) {
+ if (a_lw < 1 || a_lw > 8) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__make_empty_struct();
}
@@ -8158,7 +8158,7 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
self->private_impl.f_literal_width = 8;
- if (self->private_impl.f_set_literal_width_arg >= 2) {
+ if (self->private_impl.f_set_literal_width_arg > 0) {
self->private_impl.f_literal_width =
self->private_impl.f_set_literal_width_arg;
}
@@ -10702,7 +10702,7 @@
uint8_t t_2 = *iop_a_src++;
v_lw = t_2;
}
- if ((v_lw < 2) || (8 < v_lw)) {
+ if ((v_lw < 1) || (8 < v_lw)) {
status = wuffs_gif__error__bad_literal_width;
goto exit;
}
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index 50686f4..debe38a 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -844,8 +844,11 @@
this.lzw.reset!()
}
+ // Process the LZW literal width. The spec says that "images which have one
+ // color bit must be indicated as having a code size [i.e. literal width]
+ // of 2", but in practice, some encoders use a literal width of 1.
lw = args.src.read_u8?()
- if (lw < 2) or (8 < lw) {
+ if (lw < 1) or (8 < lw) {
return "#bad literal width"
}
this.lzw.set_literal_width!(lw:lw as base.u32)
diff --git a/std/lzw/decode_lzw.wuffs b/std/lzw/decode_lzw.wuffs
index 7f3698c..2a984ae 100644
--- a/std/lzw/decode_lzw.wuffs
+++ b/std/lzw/decode_lzw.wuffs
@@ -69,7 +69,7 @@
output array[8192 + 7] base.u8,
)
-pub func decoder.set_literal_width!(lw base.u32[2..8]) {
+pub func decoder.set_literal_width!(lw base.u32[1..8]) {
this.set_literal_width_arg = args.lw
}
@@ -82,7 +82,7 @@
// Initialize read_from state.
this.literal_width = 8
- if this.set_literal_width_arg >= 2 {
+ if this.set_literal_width_arg > 0 {
this.literal_width = this.set_literal_width_arg
}
this.clear_code = (1 as base.u32) << this.literal_width
diff --git a/test/c/std/lzw.c b/test/c/std/lzw.c
index 6b800a7..1a4c6f9 100644
--- a/test/c/std/lzw.c
+++ b/test/c/std/lzw.c
@@ -295,6 +295,59 @@
return NULL;
}
+const char* test_wuffs_lzw_decode_width_1() {
+ CHECK_FOCUS(__func__);
+
+ wuffs_base__io_buffer got = ((wuffs_base__io_buffer){
+ .data = global_got_slice,
+ });
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+
+ got.data.ptr[0] = 0xFF;
+ got.data.ptr[1] = 0xFF;
+ got.data.ptr[2] = 0xFF;
+ got.data.ptr[3] = 0xFF;
+
+ // Set src to be:
+ // 0b...._...._...._..10 0x010 Clear code.
+ // 0b...._...._...._00.. 0x000 Literal "0".
+ // 0b...._...._.001_.... 0x001 Literal "1".
+ // 0b...._..10_0..._.... 0x100 Back-ref "01".
+ // 0b...0_11.._...._.... 0x011 End code.
+ src.meta.wi = 2;
+ src.data.ptr[0] = 0x12;
+ src.data.ptr[1] = 0x0E;
+
+ wuffs_lzw__decoder dec;
+ const char* status = wuffs_lzw__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("initialize: \"%s\"", status);
+ }
+ wuffs_lzw__decoder__set_literal_width(&dec, 1);
+
+ status = wuffs_lzw__decoder__decode_io_writer(
+ &dec, wuffs_base__io_buffer__writer(&got),
+ wuffs_base__io_buffer__reader(&src), global_work_slice);
+ if (status) {
+ RETURN_FAIL("decode: \"%s\"", status);
+ }
+
+ if (got.meta.wi != 4) {
+ RETURN_FAIL("got.meta.wi: got %d, want 4", (int)(got.meta.wi));
+ }
+ uint8_t* g = got.data.ptr;
+ if ((g[0] != 0x00) || (g[1] != 0x01) || (g[2] != 0x00) || (g[3] != 0x01)) {
+ RETURN_FAIL(
+ "got {0x%02x, 0x%02x, 0x%02x, 0x%02x}, want {0x00, 0x01, 0x00, 0x01}",
+ (int)(g[0]), (int)(g[1]), (int)(g[2]), (int)(g[3]));
+ }
+ return NULL;
+}
+
// ---------------- LZW Benches
const char* do_bench_wuffs_lzw_decode(const char* filename,
@@ -368,6 +421,7 @@
test_wuffs_lzw_decode_output_bad, //
test_wuffs_lzw_decode_output_empty, //
test_wuffs_lzw_decode_pi, //
+ test_wuffs_lzw_decode_width_1, //
NULL,
};