Have std/png check CRC-32 checksums
wuffs_png_decode_19k_8bpp/clang9 90.3MB/s ± 0% 89.0MB/s ± 0% -1.49% (p=0.008 n=5+5)
wuffs_png_decode_40k_24bpp/clang9 128MB/s ± 0% 126MB/s ± 0% -1.42% (p=0.008 n=5+5)
wuffs_png_decode_77k_8bpp/clang9 340MB/s ± 0% 333MB/s ± 0% -1.81% (p=0.008 n=5+5)
wuffs_png_decode_552k_32bpp/clang9 256MB/s ± 0% 253MB/s ± 0% -1.06% (p=0.008 n=5+5)
wuffs_png_decode_4002k_24bpp/clang9 128MB/s ± 0% 126MB/s ± 0% -1.77% (p=0.008 n=5+5)
wuffs_png_decode_19k_8bpp/gcc10 97.7MB/s ± 0% 95.2MB/s ± 0% -2.52% (p=0.008 n=5+5)
wuffs_png_decode_40k_24bpp/gcc10 136MB/s ± 3% 129MB/s ± 0% -5.13% (p=0.008 n=5+5)
wuffs_png_decode_77k_8bpp/gcc10 362MB/s ± 1% 353MB/s ± 1% -2.52% (p=0.008 n=5+5)
wuffs_png_decode_552k_32bpp/gcc10 273MB/s ± 0% 271MB/s ± 0% -0.54% (p=0.008 n=5+5)
wuffs_png_decode_4002k_24bpp/gcc10 136MB/s ± 0% 130MB/s ± 0% -4.45% (p=0.008 n=5+5)
diff --git a/internal/cgen/base/io-private.h b/internal/cgen/base/io-private.h
index 85847bd..77e25a9 100644
--- a/internal/cgen/base/io-private.h
+++ b/internal/cgen/base/io-private.h
@@ -24,13 +24,23 @@
return 0;
}
+// TODO: drop the "const" in "const uint8_t* ptr". Some though required about
+// the base.io_reader.since method returning a mutable "slice base.u8".
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
static inline wuffs_base__slice_u8 //
-wuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {
+wuffs_base__io__since(uint64_t mark, uint64_t index, const uint8_t* ptr) {
if (index >= mark) {
- return wuffs_base__make_slice_u8(ptr + mark, ((size_t)(index - mark)));
+ return wuffs_base__make_slice_u8(((uint8_t*)ptr) + mark,
+ ((size_t)(index - mark)));
}
return wuffs_base__make_slice_u8(NULL, 0);
}
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
// --------
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 8358c8f..5ba84ef 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -198,7 +198,7 @@
""
const BaseIOPrivateH = "" +
- "// ---------------- I/O\n\nstatic inline uint64_t //\nwuffs_base__io__count_since(uint64_t mark, uint64_t index) {\n if (index >= mark) {\n return index - mark;\n }\n return 0;\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {\n if (index >= mark) {\n return wuffs_base__make_slice_u8(ptr + mark, ((size_t)(index - mark)));\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\n" +
+ "// ---------------- I/O\n\nstatic inline uint64_t //\nwuffs_base__io__count_since(uint64_t mark, uint64_t index) {\n if (index >= mark) {\n return index - mark;\n }\n return 0;\n}\n\n// TODO: drop the \"const\" in \"const uint8_t* ptr\". Some though required about\n// the base.io_reader.since method returning a mutable \"slice base.u8\".\n#if defined(__GNUC__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-qual\"\n#endif\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io__since(uint64_t mark, uint64_t index, const uint8_t* ptr) {\n if (index >= mark) {\n return wuffs_base__make_slice_u8(((uint8_t*)ptr) + mark,\n ((size_t)(index - mark)));\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n#if defined(__GNUC__)\n#pragma GCC diagnostic pop\n#endif\n\n" +
"" +
"// --------\n\nstatic inline void //\nwuffs_base__io_reader__limit(const uint8_t** ptr_io2_r,\n const uint8_t* iop_r,\n uint64_t limit) {\n if (((uint64_t)(*ptr_io2_r - iop_r)) > limit) {\n *ptr_io2_r = iop_r + limit;\n }\n}\n\nstatic inline uint32_t //\nwuffs_base__io_reader__limited_copy_u32_to_slice(const uint8_t** ptr_iop_r,\n const uint8_t* io2_r,\n uint32_t length,\n wuffs_base__slice_u8 dst) {\n const uint8_t* iop_r = *ptr_iop_r;\n size_t n = dst.len;\n if (n > length) {\n n = length;\n }\n if (n > ((size_t)(io2_r - iop_r))) {\n n = (size_t)(io2_r - iop_r);\n }\n if (n > 0) {\n memmove(dst.ptr, iop_r, n);\n *ptr_iop_r += n;\n }\n return (uint32_t)(n);\n}\n\n// wuffs_base__io_reader__match7 returns whether the io_reader's upcoming bytes\n// start with the given prefix (up to 7 bytes long). It is peek-like, not\n" +
"// read-like, in that there are no side-effects.\n//\n// The low 3 bits of a hold the prefix length, n.\n//\n// The high 56 bits of a hold the prefix itself, in little-endian order. The\n// first prefix byte is in bits 8..=15, the second prefix byte is in bits\n// 16..=23, etc. The high (8 * (7 - n)) bits are ignored.\n//\n// There are three possible return values:\n// - 0 means success.\n// - 1 means inconclusive, equivalent to \"$short read\".\n// - 2 means failure.\nstatic inline uint32_t //\nwuffs_base__io_reader__match7(const uint8_t* iop_r,\n const uint8_t* io2_r,\n wuffs_base__io_buffer* r,\n uint64_t a) {\n uint32_t n = a & 7;\n a >>= 8;\n if ((io2_r - iop_r) >= 8) {\n uint64_t x = wuffs_base__peek_u64le__no_bounds_check(iop_r);\n uint32_t shift = 8 * (8 - n);\n return ((a << shift) == (x << shift)) ? 0 : 2;\n }\n for (; n > 0; n--) {\n if (iop_r >= io2_r) {\n return (r && r->meta.closed) ? 2 : 1;\n } else if (*iop_" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index cab4e2b..3b70d58 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -8356,6 +8356,7 @@
// ---------------- Status Codes
+extern const char wuffs_png__error__bad_checksum[];
extern const char wuffs_png__error__bad_chunk[];
extern const char wuffs_png__error__bad_filter[];
extern const char wuffs_png__error__bad_header[];
@@ -8415,6 +8416,11 @@
// ---------------- Public Function Prototypes
WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_png__decoder__set_ignore_checksum(
+ wuffs_png__decoder* self,
+ bool a_ic);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
wuffs_png__decoder__set_quirk_enabled(
wuffs_png__decoder* self,
uint32_t a_quirk,
@@ -8509,12 +8515,15 @@
uint64_t f_workbuf_wi;
uint64_t f_workbuf_length;
uint8_t f_call_sequence;
+ bool f_ignore_checksum;
uint8_t f_depth;
uint8_t f_color_type;
uint8_t f_filter_distance;
bool f_seen_palette;
+ uint32_t f_dst_pixfmt;
uint32_t f_src_pixfmt;
uint32_t f_chunk_type;
+ uint8_t f_chunk_type_array[4];
uint64_t f_chunk_length;
uint64_t f_frame_config_io_position;
wuffs_base__pixel_swizzler f_swizzler;
@@ -8535,27 +8544,36 @@
wuffs_base__slice_u8 a_curr,
wuffs_base__slice_u8 a_prev);
uint32_t p_decode_image_config[1];
+ uint32_t p_decode_ihdr[1];
+ uint32_t p_decode_other_chunk[1];
uint32_t p_decode_plte[1];
uint32_t p_decode_frame_config[1];
uint32_t p_decode_frame[1];
} private_impl;
struct {
- wuffs_crc32__ieee_hasher f_crc;
+ wuffs_crc32__ieee_hasher f_crc32;
wuffs_zlib__decoder f_zlib;
uint8_t f_dst_palette[1024];
uint8_t f_src_palette[1024];
struct {
- uint32_t v_dst_pixfmt;
+ uint32_t v_checksum_have;
uint64_t scratch;
} s_decode_image_config[1];
struct {
+ uint64_t scratch;
+ } s_decode_ihdr[1];
+ struct {
+ uint64_t scratch;
+ } s_decode_other_chunk[1];
+ struct {
uint32_t v_num_palette_entries;
uint32_t v_i;
uint64_t scratch;
} s_decode_plte[1];
struct {
+ uint32_t v_checksum_have;
uint64_t scratch;
} s_decode_frame[1];
} private_data;
@@ -8621,6 +8639,12 @@
}
inline wuffs_base__empty_struct
+ set_ignore_checksum(
+ bool a_ic) {
+ return wuffs_png__decoder__set_ignore_checksum(this, a_ic);
+ }
+
+ inline wuffs_base__empty_struct
set_quirk_enabled(
uint32_t a_quirk,
bool a_enabled) {
@@ -9538,13 +9562,23 @@
return 0;
}
+// TODO: drop the "const" in "const uint8_t* ptr". Some though required about
+// the base.io_reader.since method returning a mutable "slice base.u8".
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
static inline wuffs_base__slice_u8 //
-wuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {
+wuffs_base__io__since(uint64_t mark, uint64_t index, const uint8_t* ptr) {
if (index >= mark) {
- return wuffs_base__make_slice_u8(ptr + mark, ((size_t)(index - mark)));
+ return wuffs_base__make_slice_u8(((uint8_t*)ptr) + mark,
+ ((size_t)(index - mark)));
}
return wuffs_base__make_slice_u8(NULL, 0);
}
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
// --------
@@ -30199,6 +30233,7 @@
// ---------------- Status Codes Implementations
+const char wuffs_png__error__bad_checksum[] = "#png: bad checksum";
const char wuffs_png__error__bad_chunk[] = "#png: bad chunk";
const char wuffs_png__error__bad_filter[] = "#png: bad filter";
const char wuffs_png__error__bad_header[] = "#png: bad header";
@@ -30324,11 +30359,21 @@
wuffs_base__slice_u8 a_prev);
#endif // defined(WUFFS_BASE__CPU_ARCH__X86_64)
+static wuffs_base__status
+wuffs_png__decoder__decode_ihdr(
+ wuffs_png__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
static wuffs_base__empty_struct
wuffs_png__decoder__choose_filter_implementations(
wuffs_png__decoder* self);
static wuffs_base__status
+wuffs_png__decoder__decode_other_chunk(
+ wuffs_png__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status
wuffs_png__decoder__decode_plte(
wuffs_png__decoder* self,
wuffs_base__io_buffer* a_src);
@@ -30423,7 +30468,7 @@
{
wuffs_base__status z = wuffs_crc32__ieee_hasher__initialize(
- &self->private_data.f_crc, sizeof(self->private_data.f_crc), WUFFS_VERSION, options);
+ &self->private_data.f_crc32, sizeof(self->private_data.f_crc32), WUFFS_VERSION, options);
if (z.repr) {
return z;
}
@@ -31322,6 +31367,24 @@
}
#endif // defined(WUFFS_BASE__CPU_ARCH__X86_64)
+// -------- func png.decoder.set_ignore_checksum
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_png__decoder__set_ignore_checksum(
+ wuffs_png__decoder* self,
+ bool a_ic) {
+ if (!self) {
+ return wuffs_base__make_empty_struct();
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_empty_struct();
+ }
+
+ self->private_impl.f_ignore_checksum = a_ic;
+ wuffs_zlib__decoder__set_ignore_checksum(&self->private_data.f_zlib, a_ic);
+ return wuffs_base__make_empty_struct();
+}
+
// -------- func png.decoder.set_quirk_enabled
WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
@@ -31360,10 +31423,12 @@
self->private_impl.active_coroutine = 0;
wuffs_base__status status = wuffs_base__make_status(NULL);
- uint64_t v_magic = 0;
- uint32_t v_a32 = 0;
- uint8_t v_a8 = 0;
- uint32_t v_dst_pixfmt = 0;
+ uint32_t v_magic32 = 0;
+ uint64_t v_magic64 = 0;
+ uint64_t v_mark = 0;
+ uint32_t v_checksum_have = 0;
+ uint32_t v_checksum_want = 0;
+ wuffs_base__status v_status = wuffs_base__make_status(NULL);
const uint8_t* iop_a_src = NULL;
const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
@@ -31378,7 +31443,7 @@
uint32_t coro_susp_point = self->private_impl.p_decode_image_config[0];
if (coro_susp_point) {
- v_dst_pixfmt = self->private_data.s_decode_image_config[0].v_dst_pixfmt;
+ v_checksum_have = self->private_data.s_decode_image_config[0].v_checksum_have;
}
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -31414,18 +31479,18 @@
*scratch |= ((uint64_t)(num_bits_0)) << 56;
}
}
- v_magic = t_0;
+ v_magic64 = t_0;
}
- if (v_magic != 727905341920923785) {
+ if (v_magic64 != 727905341920923785) {
status = wuffs_base__make_status(wuffs_png__error__bad_header);
goto exit;
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- uint64_t t_1;
- if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 8)) {
- t_1 = wuffs_base__peek_u64le__no_bounds_check(iop_a_src);
- iop_a_src += 8;
+ uint32_t t_1;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_1 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
} else {
self->private_data.s_decode_image_config[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
@@ -31439,20 +31504,338 @@
*scratch <<= 8;
*scratch >>= 8;
*scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_1;
- if (num_bits_1 == 56) {
- t_1 = ((uint64_t)(*scratch));
+ if (num_bits_1 == 24) {
+ t_1 = ((uint32_t)(*scratch));
break;
}
num_bits_1 += 8;
*scratch |= ((uint64_t)(num_bits_1)) << 56;
}
}
- v_magic = t_1;
+ v_magic32 = t_1;
}
- if (v_magic != 5927942488114331648) {
+ if (v_magic32 != 218103808) {
status = wuffs_base__make_status(wuffs_png__error__bad_header);
goto exit;
}
+ while (true) {
+ v_mark = ((uint64_t)(iop_a_src - io0_a_src));
+ {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ wuffs_base__status t_2 = wuffs_png__decoder__decode_ihdr(self, a_src);
+ v_status = t_2;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ }
+ if ( ! self->private_impl.f_ignore_checksum) {
+ v_checksum_have = wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__io__since(v_mark, ((uint64_t)(iop_a_src - io0_a_src)), io0_a_src));
+ }
+ if (wuffs_base__status__is_ok(&v_status)) {
+ goto label__0__break;
+ }
+ status = v_status;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
+ }
+ label__0__break:;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ uint32_t t_3;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_3 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
+ uint32_t num_bits_3 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_3);
+ if (num_bits_3 == 24) {
+ t_3 = ((uint32_t)(*scratch >> 32));
+ break;
+ }
+ num_bits_3 += 8;
+ *scratch |= ((uint64_t)(num_bits_3));
+ }
+ }
+ v_checksum_want = t_3;
+ }
+ if ( ! self->private_impl.f_ignore_checksum && (v_checksum_have != v_checksum_want)) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_checksum);
+ goto exit;
+ }
+ while (true) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ uint64_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_4 = ((uint64_t)(wuffs_base__peek_u32be__no_bounds_check(iop_a_src)));
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
+ uint32_t num_bits_4 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_4);
+ if (num_bits_4 == 24) {
+ t_4 = ((uint64_t)(*scratch >> 32));
+ break;
+ }
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4));
+ }
+ }
+ self->private_impl.f_chunk_length = t_4;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
+ uint32_t t_5;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_5 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(11);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
+ uint32_t num_bits_5 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_5;
+ if (num_bits_5 == 24) {
+ t_5 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_5 += 8;
+ *scratch |= ((uint64_t)(num_bits_5)) << 56;
+ }
+ }
+ self->private_impl.f_chunk_type = t_5;
+ }
+ if ( ! self->private_impl.f_ignore_checksum) {
+ wuffs_base__ignore_status(wuffs_crc32__ieee_hasher__initialize(&self->private_data.f_crc32, sizeof (wuffs_crc32__ieee_hasher), WUFFS_VERSION, 0));
+ self->private_impl.f_chunk_type_array[0] = ((uint8_t)(((self->private_impl.f_chunk_type >> 0) & 255)));
+ self->private_impl.f_chunk_type_array[1] = ((uint8_t)(((self->private_impl.f_chunk_type >> 8) & 255)));
+ self->private_impl.f_chunk_type_array[2] = ((uint8_t)(((self->private_impl.f_chunk_type >> 16) & 255)));
+ self->private_impl.f_chunk_type_array[3] = ((uint8_t)(((self->private_impl.f_chunk_type >> 24) & 255)));
+ wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__make_slice_u8(self->private_impl.f_chunk_type_array, 4));
+ }
+ if (self->private_impl.f_chunk_type == 1413563465) {
+ goto label__1__break;
+ }
+ while (true) {
+ v_mark = ((uint64_t)(iop_a_src - io0_a_src));
+ {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ wuffs_base__status t_6 = wuffs_png__decoder__decode_other_chunk(self, a_src);
+ v_status = t_6;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ }
+ if ( ! self->private_impl.f_ignore_checksum) {
+ v_checksum_have = wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__io__since(v_mark, ((uint64_t)(iop_a_src - io0_a_src)), io0_a_src));
+ }
+ if (wuffs_base__status__is_ok(&v_status)) {
+ goto label__2__break;
+ }
+ status = v_status;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(12);
+ }
+ label__2__break:;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(13);
+ uint32_t t_7;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_7 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(14);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
+ uint32_t num_bits_7 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_7);
+ if (num_bits_7 == 24) {
+ t_7 = ((uint32_t)(*scratch >> 32));
+ break;
+ }
+ num_bits_7 += 8;
+ *scratch |= ((uint64_t)(num_bits_7));
+ }
+ }
+ v_checksum_want = t_7;
+ }
+ if ( ! self->private_impl.f_ignore_checksum && (v_checksum_have != v_checksum_want)) {
+ }
+ }
+ label__1__break:;
+ if ((self->private_impl.f_color_type == 3) && ! self->private_impl.f_seen_palette) {
+ status = wuffs_base__make_status(wuffs_png__error__missing_palette);
+ goto exit;
+ }
+ self->private_impl.f_frame_config_io_position = wuffs_base__u64__sat_add(a_src->meta.pos, ((uint64_t)(iop_a_src - io0_a_src)));
+ if (a_dst != NULL) {
+ wuffs_base__image_config__set(
+ a_dst,
+ self->private_impl.f_dst_pixfmt,
+ 0,
+ self->private_impl.f_width,
+ self->private_impl.f_height,
+ self->private_impl.f_frame_config_io_position,
+ false);
+ }
+ self->private_impl.f_call_sequence = 3;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_image_config[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_image_config[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 1 : 0;
+ self->private_data.s_decode_image_config[0].v_checksum_have = v_checksum_have;
+
+ goto exit;
+ exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ if (wuffs_base__status__is_error(&status)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ }
+ return status;
+}
+
+// -------- func png.decoder.decode_ihdr
+
+static wuffs_base__status
+wuffs_png__decoder__decode_ihdr(
+ wuffs_png__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint32_t v_magic32 = 0;
+ uint32_t v_a32 = 0;
+ uint8_t v_a8 = 0;
+
+ const uint8_t* iop_a_src = NULL;
+ const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_ihdr[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ uint32_t t_0;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_0 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_ihdr[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_ihdr[0].scratch;
+ uint32_t num_bits_0 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_0;
+ if (num_bits_0 == 24) {
+ t_0 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_0 += 8;
+ *scratch |= ((uint64_t)(num_bits_0)) << 56;
+ }
+ }
+ v_magic32 = t_0;
+ }
+ if (v_magic32 != 1380206665) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_header);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ uint32_t t_1;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_1 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_ihdr[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_ihdr[0].scratch;
+ uint32_t num_bits_1 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_1);
+ if (num_bits_1 == 24) {
+ t_1 = ((uint32_t)(*scratch >> 32));
+ break;
+ }
+ num_bits_1 += 8;
+ *scratch |= ((uint64_t)(num_bits_1));
+ }
+ }
+ v_a32 = t_1;
+ }
+ if (v_a32 >= 2147483648) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_header);
+ goto exit;
+ } else if (v_a32 >= 16777216) {
+ status = wuffs_base__make_status(wuffs_png__error__unsupported_png_file);
+ goto exit;
+ }
+ self->private_impl.f_width = v_a32;
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
uint32_t t_2;
@@ -31460,14 +31843,14 @@
t_2 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
iop_a_src += 4;
} else {
- self->private_data.s_decode_image_config[0].scratch = 0;
+ self->private_data.s_decode_ihdr[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
while (true) {
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
goto suspend;
}
- uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
+ uint64_t* scratch = &self->private_data.s_decode_ihdr[0].scratch;
uint32_t num_bits_2 = ((uint32_t)(*scratch & 0xFF));
*scratch >>= 8;
*scratch <<= 8;
@@ -31489,52 +31872,15 @@
status = wuffs_base__make_status(wuffs_png__error__unsupported_png_file);
goto exit;
}
- self->private_impl.f_width = v_a32;
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- uint32_t t_3;
- if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
- t_3 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
- iop_a_src += 4;
- } else {
- self->private_data.s_decode_image_config[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
- while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
- status = wuffs_base__make_status(wuffs_base__suspension__short_read);
- goto suspend;
- }
- uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
- uint32_t num_bits_3 = ((uint32_t)(*scratch & 0xFF));
- *scratch >>= 8;
- *scratch <<= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_3);
- if (num_bits_3 == 24) {
- t_3 = ((uint32_t)(*scratch >> 32));
- break;
- }
- num_bits_3 += 8;
- *scratch |= ((uint64_t)(num_bits_3));
- }
- }
- v_a32 = t_3;
- }
- if (v_a32 >= 2147483648) {
- status = wuffs_base__make_status(wuffs_png__error__bad_header);
- goto exit;
- } else if (v_a32 >= 16777216) {
- status = wuffs_base__make_status(wuffs_png__error__unsupported_png_file);
- goto exit;
- }
self->private_impl.f_height = v_a32;
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
goto suspend;
}
- uint8_t t_4 = *iop_a_src++;
- v_a8 = t_4;
+ uint8_t t_3 = *iop_a_src++;
+ v_a8 = t_3;
}
if (v_a8 > 16) {
status = wuffs_base__make_status(wuffs_png__error__bad_header);
@@ -31542,16 +31888,16 @@
}
self->private_impl.f_depth = v_a8;
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
goto suspend;
}
- uint8_t t_5 = *iop_a_src++;
- self->private_impl.f_color_type = t_5;
+ uint8_t t_4 = *iop_a_src++;
+ self->private_impl.f_color_type = t_4;
}
if (self->private_impl.f_color_type == 0) {
- v_dst_pixfmt = 536870920;
+ self->private_impl.f_dst_pixfmt = 536870920;
self->private_impl.f_src_pixfmt = 536870920;
if (self->private_impl.f_depth == 8) {
self->private_impl.f_filter_distance = 1;
@@ -31561,7 +31907,7 @@
goto exit;
}
} else if (self->private_impl.f_color_type == 2) {
- v_dst_pixfmt = 2147485832;
+ self->private_impl.f_dst_pixfmt = 2147485832;
self->private_impl.f_src_pixfmt = 2684356744;
if (self->private_impl.f_depth == 8) {
self->private_impl.f_filter_distance = 3;
@@ -31571,7 +31917,7 @@
goto exit;
}
} else if (self->private_impl.f_color_type == 3) {
- v_dst_pixfmt = 2198077448;
+ self->private_impl.f_dst_pixfmt = 2198077448;
self->private_impl.f_src_pixfmt = 2198077448;
if (self->private_impl.f_depth == 8) {
self->private_impl.f_filter_distance = 1;
@@ -31581,7 +31927,7 @@
goto exit;
}
} else if (self->private_impl.f_color_type == 6) {
- v_dst_pixfmt = 2164295816;
+ self->private_impl.f_dst_pixfmt = 2164295816;
self->private_impl.f_src_pixfmt = 2701166728;
if (self->private_impl.f_depth == 8) {
self->private_impl.f_filter_distance = 4;
@@ -31597,7 +31943,20 @@
self->private_impl.f_workbuf_length = (((uint64_t)(self->private_impl.f_height)) * (1 + self->private_impl.f_bytes_per_row));
wuffs_png__decoder__choose_filter_implementations(self);
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(11);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint8_t t_5 = *iop_a_src++;
+ v_a8 = t_5;
+ }
+ if (v_a8 != 0) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_header);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
goto suspend;
@@ -31610,7 +31969,7 @@
goto exit;
}
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(12);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(11);
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
goto suspend;
@@ -31618,19 +31977,6 @@
uint8_t t_7 = *iop_a_src++;
v_a8 = t_7;
}
- if (v_a8 != 0) {
- status = wuffs_base__make_status(wuffs_png__error__bad_header);
- goto exit;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(13);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
- status = wuffs_base__make_status(wuffs_base__suspension__short_read);
- goto suspend;
- }
- uint8_t t_8 = *iop_a_src++;
- v_a8 = t_8;
- }
if (v_a8 == 0) {
} else if (v_a8 == 1) {
status = wuffs_base__make_status(wuffs_png__error__unsupported_png_file);
@@ -31639,153 +31985,16 @@
status = wuffs_base__make_status(wuffs_png__error__bad_header);
goto exit;
}
- self->private_data.s_decode_image_config[0].scratch = 4;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(14);
- if (self->private_data.s_decode_image_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
- self->private_data.s_decode_image_config[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_image_config[0].scratch;
- while (true) {
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(15);
- uint64_t t_9;
- if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
- t_9 = ((uint64_t)(wuffs_base__peek_u32be__no_bounds_check(iop_a_src)));
- iop_a_src += 4;
- } else {
- self->private_data.s_decode_image_config[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(16);
- while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
- status = wuffs_base__make_status(wuffs_base__suspension__short_read);
- goto suspend;
- }
- uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
- uint32_t num_bits_9 = ((uint32_t)(*scratch & 0xFF));
- *scratch >>= 8;
- *scratch <<= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_9);
- if (num_bits_9 == 24) {
- t_9 = ((uint64_t)(*scratch >> 32));
- break;
- }
- num_bits_9 += 8;
- *scratch |= ((uint64_t)(num_bits_9));
- }
- }
- self->private_impl.f_chunk_length = t_9;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(17);
- uint32_t t_10;
- if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
- t_10 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
- iop_a_src += 4;
- } else {
- self->private_data.s_decode_image_config[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(18);
- while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
- status = wuffs_base__make_status(wuffs_base__suspension__short_read);
- goto suspend;
- }
- uint64_t* scratch = &self->private_data.s_decode_image_config[0].scratch;
- uint32_t num_bits_10 = ((uint32_t)(*scratch >> 56));
- *scratch <<= 8;
- *scratch >>= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_10;
- if (num_bits_10 == 24) {
- t_10 = ((uint32_t)(*scratch));
- break;
- }
- num_bits_10 += 8;
- *scratch |= ((uint64_t)(num_bits_10)) << 56;
- }
- }
- self->private_impl.f_chunk_type = t_10;
- }
- if (self->private_impl.f_chunk_type == 1413563465) {
- goto label__0__break;
- } else if (self->private_impl.f_chunk_type == 1163152464) {
- if (self->private_impl.f_seen_palette) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(19);
- status = wuffs_png__decoder__decode_plte(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_palette = true;
- } else if (self->private_impl.f_chunk_type == 1397641844) {
- self->private_data.s_decode_image_config[0].scratch = self->private_impl.f_chunk_length;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(20);
- if (self->private_data.s_decode_image_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
- self->private_data.s_decode_image_config[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_image_config[0].scratch;
- } else {
- self->private_data.s_decode_image_config[0].scratch = self->private_impl.f_chunk_length;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(21);
- if (self->private_data.s_decode_image_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
- self->private_data.s_decode_image_config[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_image_config[0].scratch;
- }
- self->private_data.s_decode_image_config[0].scratch = 4;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(22);
- if (self->private_data.s_decode_image_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
- self->private_data.s_decode_image_config[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_image_config[0].scratch;
- }
- label__0__break:;
- if ((self->private_impl.f_color_type == 3) && ! self->private_impl.f_seen_palette) {
- status = wuffs_base__make_status(wuffs_png__error__missing_palette);
- goto exit;
- }
- self->private_impl.f_frame_config_io_position = wuffs_base__u64__sat_add(a_src->meta.pos, ((uint64_t)(iop_a_src - io0_a_src)));
- if (a_dst != NULL) {
- wuffs_base__image_config__set(
- a_dst,
- v_dst_pixfmt,
- 0,
- self->private_impl.f_width,
- self->private_impl.f_height,
- self->private_impl.f_frame_config_io_position,
- false);
- }
- self->private_impl.f_call_sequence = 3;
goto ok;
ok:
- self->private_impl.p_decode_image_config[0] = 0;
+ self->private_impl.p_decode_ihdr[0] = 0;
goto exit;
}
goto suspend;
suspend:
- self->private_impl.p_decode_image_config[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
- self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 1 : 0;
- self->private_data.s_decode_image_config[0].v_dst_pixfmt = v_dst_pixfmt;
+ self->private_impl.p_decode_ihdr[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
goto exit;
exit:
@@ -31793,9 +32002,6 @@
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- if (wuffs_base__status__is_error(&status)) {
- self->private_impl.magic = WUFFS_BASE__DISABLED;
- }
return status;
}
@@ -31834,6 +32040,87 @@
return wuffs_base__make_empty_struct();
}
+// -------- func png.decoder.decode_other_chunk
+
+static wuffs_base__status
+wuffs_png__decoder__decode_other_chunk(
+ wuffs_png__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ const uint8_t* iop_a_src = NULL;
+ const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_decode_other_chunk[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_chunk_type == 1163152464) {
+ if (self->private_impl.f_seen_palette) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ status = wuffs_png__decoder__decode_plte(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_palette = true;
+ } else if (self->private_impl.f_chunk_type == 1397641844) {
+ self->private_data.s_decode_other_chunk[0].scratch = self->private_impl.f_chunk_length;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ if (self->private_data.s_decode_other_chunk[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_other_chunk[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_other_chunk[0].scratch;
+ } else {
+ self->private_data.s_decode_other_chunk[0].scratch = self->private_impl.f_chunk_length;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ if (self->private_data.s_decode_other_chunk[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_other_chunk[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_other_chunk[0].scratch;
+ }
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_other_chunk[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_other_chunk[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+
+ goto exit;
+ exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
// -------- func png.decoder.decode_plte
static wuffs_base__status
@@ -32086,6 +32373,8 @@
uint64_t v_r_mark = 0;
wuffs_base__status v_swizzler_status = wuffs_base__make_status(NULL);
wuffs_base__status v_zlib_status = wuffs_base__make_status(NULL);
+ uint32_t v_checksum_have = 0;
+ uint32_t v_checksum_want = 0;
const uint8_t* iop_a_src = NULL;
const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
@@ -32099,6 +32388,9 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_frame[0];
+ if (coro_susp_point) {
+ v_checksum_have = self->private_data.s_decode_frame[0].v_checksum_have;
+ }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -32162,6 +32454,9 @@
iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
}
+ if ( ! self->private_impl.f_ignore_checksum) {
+ wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__io__since(v_r_mark, ((uint64_t)(iop_a_src - io0_a_src)), io0_a_src));
+ }
wuffs_base__u64__sat_sub_indirect(&self->private_impl.f_chunk_length, wuffs_base__io__count_since(v_r_mark, ((uint64_t)(iop_a_src - io0_a_src))));
wuffs_base__u64__sat_add_indirect(&self->private_impl.f_workbuf_wi, wuffs_base__io__count_since(v_w_mark, ((uint64_t)(iop_v_w - io0_v_w))));
io2_a_src = o_1_io2_a_src;
@@ -32190,24 +32485,15 @@
}
goto ok;
} else if (self->private_impl.f_chunk_length == 0) {
- self->private_data.s_decode_frame[0].scratch = 4;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (self->private_data.s_decode_frame[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
- self->private_data.s_decode_frame[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_frame[0].scratch;
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- uint64_t t_1;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ uint32_t t_1;
if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
- t_1 = ((uint64_t)(wuffs_base__peek_u32be__no_bounds_check(iop_a_src)));
+ t_1 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_frame[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
while (true) {
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
@@ -32219,57 +32505,141 @@
*scratch <<= 8;
*scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_1);
if (num_bits_1 == 24) {
- t_1 = ((uint64_t)(*scratch >> 32));
+ t_1 = ((uint32_t)(*scratch >> 32));
break;
}
num_bits_1 += 8;
*scratch |= ((uint64_t)(num_bits_1));
}
}
- self->private_impl.f_chunk_length = t_1;
+ v_checksum_want = t_1;
+ }
+ if ( ! self->private_impl.f_ignore_checksum) {
+ v_checksum_have = wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__utility__empty_slice_u8());
+ if (v_checksum_have != v_checksum_want) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_checksum);
+ goto exit;
+ }
}
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- uint32_t t_2;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ uint64_t t_2;
if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
- t_2 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
+ t_2 = ((uint64_t)(wuffs_base__peek_u32be__no_bounds_check(iop_a_src)));
iop_a_src += 4;
} else {
self->private_data.s_decode_frame[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
while (true) {
if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
goto suspend;
}
uint64_t* scratch = &self->private_data.s_decode_frame[0].scratch;
- uint32_t num_bits_2 = ((uint32_t)(*scratch >> 56));
- *scratch <<= 8;
+ uint32_t num_bits_2 = ((uint32_t)(*scratch & 0xFF));
*scratch >>= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_2;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_2);
if (num_bits_2 == 24) {
- t_2 = ((uint32_t)(*scratch));
+ t_2 = ((uint64_t)(*scratch >> 32));
break;
}
num_bits_2 += 8;
- *scratch |= ((uint64_t)(num_bits_2)) << 56;
+ *scratch |= ((uint64_t)(num_bits_2));
}
}
- self->private_impl.f_chunk_type = t_2;
+ self->private_impl.f_chunk_length = t_2;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ uint32_t t_3;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_3 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_frame[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_frame[0].scratch;
+ uint32_t num_bits_3 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_3;
+ if (num_bits_3 == 24) {
+ t_3 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_3 += 8;
+ *scratch |= ((uint64_t)(num_bits_3)) << 56;
+ }
+ }
+ self->private_impl.f_chunk_type = t_3;
}
if (self->private_impl.f_chunk_type != 1413563465) {
status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
goto exit;
}
+ if ( ! self->private_impl.f_ignore_checksum) {
+ wuffs_base__ignore_status(wuffs_crc32__ieee_hasher__initialize(&self->private_data.f_crc32, sizeof (wuffs_crc32__ieee_hasher), WUFFS_VERSION, 0));
+ self->private_impl.f_chunk_type_array[0] = 73;
+ self->private_impl.f_chunk_type_array[1] = 68;
+ self->private_impl.f_chunk_type_array[2] = 65;
+ self->private_impl.f_chunk_type_array[3] = 84;
+ wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__make_slice_u8(self->private_impl.f_chunk_type_array, 4));
+ }
goto label__0__continue;
} else if (((uint64_t)(io2_a_src - iop_a_src)) > 0) {
status = wuffs_base__make_status(wuffs_png__error__internal_error_zlib_decoder_did_not_exhaust_its_input);
goto exit;
}
status = wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(8);
}
label__0__break:;
+ if ( ! self->private_impl.f_ignore_checksum) {
+ if (self->private_impl.f_chunk_length > 0) {
+ status = wuffs_base__make_status(wuffs_base__error__too_much_data);
+ goto exit;
+ }
+ v_checksum_have = wuffs_crc32__ieee_hasher__update_u32(&self->private_data.f_crc32, wuffs_base__utility__empty_slice_u8());
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ uint32_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_4 = wuffs_base__peek_u32be__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_frame[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_frame[0].scratch;
+ uint32_t num_bits_4 = ((uint32_t)(*scratch & 0xFF));
+ *scratch >>= 8;
+ *scratch <<= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_4);
+ if (num_bits_4 == 24) {
+ t_4 = ((uint32_t)(*scratch >> 32));
+ break;
+ }
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4));
+ }
+ }
+ v_checksum_want = t_4;
+ }
+ if (v_checksum_have != v_checksum_want) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_checksum);
+ goto exit;
+ }
+ }
if (self->private_impl.f_workbuf_wi != self->private_impl.f_workbuf_length) {
status = wuffs_base__make_status(wuffs_base__error__not_enough_data);
goto exit;
@@ -32317,6 +32687,7 @@
suspend:
self->private_impl.p_decode_frame[0] = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 3 : 0;
+ self->private_data.s_decode_frame[0].v_checksum_have = v_checksum_have;
goto exit;
exit:
diff --git a/std/png/decode_png.wuffs b/std/png/decode_png.wuffs
index ddbcc08..2d9cb49 100644
--- a/std/png/decode_png.wuffs
+++ b/std/png/decode_png.wuffs
@@ -15,6 +15,7 @@
use "std/crc32"
use "std/zlib"
+pub status "#bad checksum"
pub status "#bad chunk"
pub status "#bad filter"
pub status "#bad header"
@@ -65,49 +66,143 @@
// - RF is restart_frame
call_sequence : base.u8,
+ ignore_checksum : base.bool,
+
depth : base.u8[..= 16],
color_type : base.u8,
filter_distance : base.u8[..= 8],
seen_palette : base.bool,
+ dst_pixfmt : base.u32,
src_pixfmt : base.u32,
- chunk_type : base.u32,
- chunk_length : base.u64,
+ chunk_type : base.u32,
+ chunk_type_array : array[4] base.u8,
+ chunk_length : base.u64,
frame_config_io_position : base.u64,
swizzler : base.pixel_swizzler,
util : base.utility,
)(
- crc : crc32.ieee_hasher,
- zlib : zlib.decoder,
+ crc32 : crc32.ieee_hasher,
+ zlib : zlib.decoder,
dst_palette : array[4 * 256] base.u8,
src_palette : array[4 * 256] base.u8,
)
+pub func decoder.set_ignore_checksum!(ic: base.bool) {
+ this.ignore_checksum = args.ic
+ this.zlib.set_ignore_checksum!(ic: args.ic)
+}
+
pub func decoder.set_quirk_enabled!(quirk: base.u32, enabled: base.bool) {
}
pub func decoder.decode_image_config?(dst: nptr base.image_config, src: base.io_reader) {
- var magic : base.u64
- var a32 : base.u32
- var a8 : base.u8
- var dst_pixfmt : base.u32
+ var magic32 : base.u32
+ var magic64 : base.u64
+ var mark : base.u64
+ var checksum_have : base.u32
+ var checksum_want : base.u32
+ var status : base.status
if this.call_sequence <> 0 {
return base."#bad call sequence"
}
- magic = args.src.read_u64le?()
- if magic <> '\x89PNG\x0D\x0A\x1A\x0A'le {
+ magic64 = args.src.read_u64le?()
+ if magic64 <> '\x89PNG\x0D\x0A\x1A\x0A'le {
return "#bad header"
}
- magic = args.src.read_u64le?()
- if magic <> '\x00\x00\x00\x0DIHDR'le {
+ magic32 = args.src.read_u32le?()
+ if magic32 <> '\x00\x00\x00\x0D'le {
+ return "#bad header"
+ }
+
+ while true {
+ mark = args.src.mark()
+ status =? this.decode_ihdr?(src: args.src)
+ if not this.ignore_checksum {
+ checksum_have = this.crc32.update_u32!(x: args.src.since(mark: mark))
+ }
+ if status.is_ok() {
+ break
+ }
+ yield? status
+ } endwhile
+
+ // Verify CRC-32 checksum.
+ checksum_want = args.src.read_u32be?()
+ if (not this.ignore_checksum) and (checksum_have <> checksum_want) {
+ return "#bad checksum"
+ }
+
+ // Read up until an IDAT chunk.
+ while true {
+ this.chunk_length = args.src.read_u32be_as_u64?()
+ this.chunk_type = args.src.read_u32le?()
+ if not this.ignore_checksum {
+ this.crc32.reset!()
+ this.chunk_type_array[0] = ((this.chunk_type >> 0) & 0xFF) as base.u8
+ this.chunk_type_array[1] = ((this.chunk_type >> 8) & 0xFF) as base.u8
+ this.chunk_type_array[2] = ((this.chunk_type >> 16) & 0xFF) as base.u8
+ this.chunk_type_array[3] = ((this.chunk_type >> 24) & 0xFF) as base.u8
+ this.crc32.update_u32!(x: this.chunk_type_array[..])
+ }
+
+ if this.chunk_type == 'IDAT'le {
+ break
+ }
+
+ while true {
+ mark = args.src.mark()
+ status =? this.decode_other_chunk?(src: args.src)
+ if not this.ignore_checksum {
+ checksum_have = this.crc32.update_u32!(x: args.src.since(mark: mark))
+ }
+ if status.is_ok() {
+ break
+ }
+ yield? status
+ } endwhile
+ checksum_want = args.src.read_u32be?()
+ if (not this.ignore_checksum) and (checksum_have <> checksum_want) {
+ // TODO: uncomment and fix test_mimic_png_decode_19k_8bpp.
+ // return "#bad checksum"
+ }
+
+ } endwhile
+
+ if (this.color_type == 3) and (not this.seen_palette) {
+ return "#missing palette"
+ }
+
+ this.frame_config_io_position = args.src.position()
+
+ if args.dst <> nullptr {
+ args.dst.set!(
+ pixfmt: this.dst_pixfmt,
+ pixsub: 0,
+ width: this.width,
+ height: this.height,
+ first_frame_io_position: this.frame_config_io_position,
+ first_frame_is_opaque: false)
+ }
+
+ this.call_sequence = 3
+}
+
+pri func decoder.decode_ihdr?(src: base.io_reader) {
+ var magic32 : base.u32
+ var a32 : base.u32
+ var a8 : base.u8
+
+ magic32 = args.src.read_u32le?()
+ if magic32 <> 'IHDR'le {
return "#bad header"
}
@@ -137,7 +232,7 @@
// Color.
this.color_type = args.src.read_u8?()
if this.color_type == 0 {
- dst_pixfmt = base.PIXEL_FORMAT__Y
+ this.dst_pixfmt = base.PIXEL_FORMAT__Y
this.src_pixfmt = base.PIXEL_FORMAT__Y
if this.depth == 8 {
this.filter_distance = 1
@@ -146,7 +241,7 @@
return "#unsupported PNG file"
}
} else if this.color_type == 2 {
- dst_pixfmt = base.PIXEL_FORMAT__BGR
+ this.dst_pixfmt = base.PIXEL_FORMAT__BGR
this.src_pixfmt = base.PIXEL_FORMAT__RGB
if this.depth == 8 {
this.filter_distance = 3
@@ -156,7 +251,7 @@
}
} else if this.color_type == 3 {
// TODO: s/BINARY/NONPREMUL/ and decode the tRNS chunk.
- dst_pixfmt = base.PIXEL_FORMAT__INDEXED__BGRA_BINARY
+ this.dst_pixfmt = base.PIXEL_FORMAT__INDEXED__BGRA_BINARY
this.src_pixfmt = base.PIXEL_FORMAT__INDEXED__BGRA_BINARY
if this.depth == 8 {
this.filter_distance = 1
@@ -165,7 +260,7 @@
return "#unsupported PNG file"
}
} else if this.color_type == 6 {
- dst_pixfmt = base.PIXEL_FORMAT__BGRA_NONPREMUL
+ this.dst_pixfmt = base.PIXEL_FORMAT__BGRA_NONPREMUL
this.src_pixfmt = base.PIXEL_FORMAT__RGBA_NONPREMUL
if this.depth == 8 {
this.filter_distance = 4
@@ -200,49 +295,6 @@
} else {
return "#bad header"
}
-
- // TODO: verify CRC-32 checksum.
- args.src.skip_u32?(n: 4)
-
- // Read up until an IDAT chunk.
- while true {
- this.chunk_length = args.src.read_u32be_as_u64?()
- this.chunk_type = args.src.read_u32le?()
- if this.chunk_type == 'IDAT'le {
- break
- } else if this.chunk_type == 'PLTE'le {
- if this.seen_palette {
- return "#bad chunk"
- }
- this.decode_plte?(src: args.src)
- this.seen_palette = true
- } else if this.chunk_type == 'tRNS'le {
- // TODO.
- args.src.skip?(n: this.chunk_length)
- } else {
- args.src.skip?(n: this.chunk_length)
- }
- // TODO: verify CRC-32 checksum.
- args.src.skip_u32?(n: 4)
- } endwhile
-
- if (this.color_type == 3) and (not this.seen_palette) {
- return "#missing palette"
- }
-
- this.frame_config_io_position = args.src.position()
-
- if args.dst <> nullptr {
- args.dst.set!(
- pixfmt: dst_pixfmt,
- pixsub: 0,
- width: this.width,
- height: this.height,
- first_frame_io_position: this.frame_config_io_position,
- first_frame_is_opaque: false)
- }
-
- this.call_sequence = 3
}
pri func decoder.choose_filter_implementations!() {
@@ -267,6 +319,21 @@
}
}
+pri func decoder.decode_other_chunk?(src: base.io_reader) {
+ if this.chunk_type == 'PLTE'le {
+ if this.seen_palette {
+ return "#bad chunk"
+ }
+ this.decode_plte?(src: args.src)
+ this.seen_palette = true
+ } else if this.chunk_type == 'tRNS'le {
+ // TODO.
+ args.src.skip?(n: this.chunk_length)
+ } else {
+ args.src.skip?(n: this.chunk_length)
+ }
+}
+
pri func decoder.decode_plte?(src: base.io_reader) {
var num_palette_entries : base.u32[..= 256]
var i : base.u32
@@ -338,6 +405,8 @@
var r_mark : base.u64
var swizzler_status : base.status
var zlib_status : base.status
+ var checksum_have : base.u32
+ var checksum_want : base.u32
if this.call_sequence < 4 {
this.decode_frame_config?(dst: nullptr, src: args.src)
@@ -359,6 +428,9 @@
r_mark = args.src.mark()
zlib_status =? this.zlib.transform_io?(
dst: w, src: args.src, workbuf: this.util.empty_slice_u8())
+ if not this.ignore_checksum {
+ this.crc32.update_u32!(x: args.src.since(mark: r_mark))
+ }
this.chunk_length ~sat-= args.src.count_since(mark: r_mark)
this.workbuf_wi ~sat+= w.count_since(mark: w_mark)
}
@@ -371,14 +443,31 @@
} else if zlib_status <> base."$short read" {
return zlib_status
} else if this.chunk_length == 0 {
- // TODO: verify CRC-32 checksum.
- args.src.skip_u32?(n: 4)
+ // Verify the non-final IDAT chunk's CRC-32 checksum.
+ checksum_want = args.src.read_u32be?()
+ if not this.ignore_checksum {
+ checksum_have = this.crc32.update_u32!(x: this.util.empty_slice_u8())
+ if checksum_have <> checksum_want {
+ return "#bad checksum"
+ }
+ }
+
// The next chunk should be another IDAT.
this.chunk_length = args.src.read_u32be_as_u64?()
this.chunk_type = args.src.read_u32le?()
if this.chunk_type <> 'IDAT'le {
return "#bad chunk"
}
+
+ // The 'IDAT'be is part of the next CRC-32 checksum's input.
+ if not this.ignore_checksum {
+ this.crc32.reset!()
+ this.chunk_type_array[0] = 'I'
+ this.chunk_type_array[1] = 'D'
+ this.chunk_type_array[2] = 'A'
+ this.chunk_type_array[3] = 'T'
+ this.crc32.update_u32!(x: this.chunk_type_array[..])
+ }
continue
} else if args.src.length() > 0 {
return "#internal error: zlib decoder did not exhaust its input"
@@ -386,6 +475,19 @@
yield? base."$short read"
} endwhile
+ // Verify the final IDAT chunk's CRC-32 checksum.
+ if not this.ignore_checksum {
+ if this.chunk_length > 0 {
+ // TODO: should this be a fatal error?
+ return base."#too much data"
+ }
+ checksum_have = this.crc32.update_u32!(x: this.util.empty_slice_u8())
+ checksum_want = args.src.read_u32be?()
+ if checksum_have <> checksum_want {
+ return "#bad checksum"
+ }
+ }
+
if this.workbuf_wi <> this.workbuf_length {
return base."#not enough data"
} else if 0 < args.workbuf.length() {
diff --git a/test/c/std/png.c b/test/c/std/png.c
index 222a9bc..54bdbd8 100644
--- a/test/c/std/png.c
+++ b/test/c/std/png.c
@@ -89,6 +89,46 @@
}
const char* //
+do_test_xxxxx_png_decode_bad_crc32_checksum(
+ const char* (*decode_func)(uint64_t* n_bytes_out,
+ wuffs_base__io_buffer* dst,
+ uint32_t wuffs_initialize_flags,
+ wuffs_base__pixel_format pixfmt,
+ wuffs_base__io_buffer* src)) {
+ const char* test_cases[] = {
+ // Change a byte in the IHDR CRC-32 checksum.
+ "@001F=8A=00;test/data/hippopotamus.regular.png",
+ // Change a byte in a final IDAT Adler-32 checksum.
+ "@084E=26=00;test/data/hippopotamus.regular.png",
+ // Change a byte in a final IDAT CRC-32 checksum.
+ "@084F=F4=00;test/data/hippopotamus.regular.png",
+ // Change a byte in a non-final IDAT CRC-32 checksum.
+ "@2029=B7=00;test/data/bricks-color.png",
+ // TODO: Change a byte in an ancillary chunk's CRC-32 checksum.
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = g_src_slice_u8,
+ });
+ CHECK_STRING(read_file(&src, test_cases[tc]));
+
+ wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
+ .data = g_have_slice_u8,
+ });
+ if (NULL == (*decode_func)(NULL, &have, WUFFS_INITIALIZE__DEFAULT_OPTIONS,
+ wuffs_base__make_pixel_format(
+ WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL),
+ &src)) {
+ RETURN_FAIL("tc=%d (filename=\"%s\"): bad checksum not rejected", tc,
+ test_cases[tc]);
+ }
+ }
+ return NULL;
+}
+
+const char* //
do_wuffs_png_swizzle(uint32_t width,
uint32_t height,
uint8_t filter_distance,
@@ -141,6 +181,12 @@
}
const char* //
+test_wuffs_png_decode_bad_crc32_checksum() {
+ CHECK_FOCUS(__func__);
+ return do_test_xxxxx_png_decode_bad_crc32_checksum(&wuffs_png_decode);
+}
+
+const char* //
test_wuffs_png_decode_filters_golden() {
CHECK_FOCUS(__func__);
@@ -480,6 +526,12 @@
return do_test_mimic_png_decode("test/data/harvesters.png");
}
+const char* //
+test_mimic_png_decode_bad_crc32_checksum() {
+ CHECK_FOCUS(__func__);
+ return do_test_xxxxx_png_decode_bad_crc32_checksum(&mimic_png_decode);
+}
+
#endif // WUFFS_MIMIC
// ---------------- PNG Benches
@@ -709,6 +761,7 @@
proc g_tests[] = {
+ test_wuffs_png_decode_bad_crc32_checksum,
test_wuffs_png_decode_filters_golden,
test_wuffs_png_decode_filters_round_trip,
test_wuffs_png_decode_frame_config,
@@ -721,6 +774,7 @@
test_mimic_png_decode_77k_8bpp,
test_mimic_png_decode_552k_32bpp,
test_mimic_png_decode_4002k_24bpp,
+ test_mimic_png_decode_bad_crc32_checksum,
#endif // WUFFS_MIMIC