Add wbmp.decoder.skip_frame
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4104385..51cc52a 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -4245,6 +4245,7 @@
uint32_t p_decode_image_config[1];
uint32_t p_decode_frame_config[1];
uint32_t p_decode_frame[1];
+ uint32_t p_skip_frame[1];
} private_impl;
struct {
@@ -4258,6 +4259,9 @@
uint8_t v_src[1];
uint8_t v_c;
} s_decode_frame[1];
+ struct {
+ uint64_t scratch;
+ } s_skip_frame[1];
} private_data;
#ifdef __cplusplus
@@ -13009,6 +13013,10 @@
// ---------------- Private Function Prototypes
+static wuffs_base__status //
+wuffs_wbmp__decoder__skip_frame(wuffs_wbmp__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
// ---------------- VTables
const wuffs_base__image_decoder__func_ptrs
@@ -13288,6 +13296,11 @@
}
} else if (self->private_impl.f_call_sequence == 1) {
} else if (self->private_impl.f_call_sequence == 2) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ status = wuffs_wbmp__decoder__skip_frame(self, a_src);
+ if (status.repr) {
+ goto suspend;
+ }
status = wuffs_base__make_status(wuffs_base__note__end_of_data);
goto ok;
} else {
@@ -13489,6 +13502,71 @@
return status;
}
+// -------- func wbmp.decoder.skip_frame
+
+static wuffs_base__status //
+wuffs_wbmp__decoder__skip_frame(wuffs_wbmp__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint64_t v_bytes_per_row = 0;
+ uint64_t v_total_bytes = 0;
+
+ uint8_t* iop_a_src = NULL;
+ uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ 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_skip_frame[0];
+ if (coro_susp_point) {
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ v_bytes_per_row = ((((uint64_t)(self->private_impl.f_width)) + 7) / 8);
+ v_total_bytes =
+ (v_bytes_per_row * ((uint64_t)(self->private_impl.f_height)));
+ self->private_data.s_skip_frame[0].scratch =
+ ((uint32_t)((v_total_bytes & 4294967295)));
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ if (self->private_data.s_skip_frame[0].scratch >
+ ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_skip_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_skip_frame[0].scratch;
+ self->private_impl.f_seen_frame = true;
+ self->private_impl.f_call_sequence = 2;
+
+ goto ok;
+ ok:
+ self->private_impl.p_skip_frame[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_skip_frame[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 wbmp.decoder.ack_metadata_chunk
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
diff --git a/std/wbmp/decode_wbmp.wuffs b/std/wbmp/decode_wbmp.wuffs
index 7671c21..442b3bd 100644
--- a/std/wbmp/decode_wbmp.wuffs
+++ b/std/wbmp/decode_wbmp.wuffs
@@ -101,7 +101,7 @@
} else if this.call_sequence == 1 {
// No-op.
} else if this.call_sequence == 2 {
- // TODO: skip frame.
+ this.skip_frame?(src: args.src)
return base."@end of data"
} else {
return base."@end of data"
@@ -200,6 +200,20 @@
this.call_sequence = 3
}
+pri func decoder.skip_frame?(src: base.io_reader) {
+ var bytes_per_row : base.u64[..= 0x20000000]
+ var total_bytes : base.u64
+
+ bytes_per_row = ((this.width as base.u64) + 7) / 8
+ total_bytes = bytes_per_row * (this.height as base.u64)
+
+ // TODO: total_bytes may be larger than UINT32_MAX.
+ args.src.skip?(n: (total_bytes & 0xFFFFFFFF) as base.u32)
+
+ this.seen_frame = true
+ this.call_sequence = 2
+}
+
pub func decoder.ack_metadata_chunk?(src: base.io_reader) {
// TODO: this final line shouldn't be necessary, here and in some other
// std/*/*.wuffs functions.
diff --git a/test/c/std/wbmp.c b/test/c/std/wbmp.c
index 0fc128d..fe492da 100644
--- a/test/c/std/wbmp.c
+++ b/test/c/std/wbmp.c
@@ -81,6 +81,35 @@
"test/data/muybridge-frame-000.wbmp", 0, SIZE_MAX, 30, 20, 0xFFFFFFFF);
}
+const char* test_wuffs_wbmp_decode_frame_config() {
+ CHECK_FOCUS(__func__);
+ wuffs_wbmp__decoder dec;
+ CHECK_STATUS("initialize",
+ wuffs_wbmp__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+
+ wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ CHECK_STRING(read_file(&src, "test/data/hat.wbmp"));
+ CHECK_STATUS("decode_frame_config #0",
+ wuffs_wbmp__decoder__decode_frame_config(&dec, &fc, &src));
+
+ wuffs_base__status status =
+ wuffs_wbmp__decoder__decode_frame_config(&dec, &fc, &src);
+ if (status.repr != wuffs_base__note__end_of_data) {
+ RETURN_FAIL("decode_frame_config #1: got \"%s\", want \"%s\"", status.repr,
+ wuffs_base__note__end_of_data);
+ }
+ if (src.meta.ri != src.meta.wi) {
+ RETURN_FAIL("at end of data: ri (%zu) doesn't equal wi (%zu)", src.meta.ri,
+ src.meta.wi);
+ }
+ return NULL;
+}
+
const char* test_wuffs_wbmp_decode_image_config() {
CHECK_FOCUS(__func__);
wuffs_wbmp__decoder dec;
@@ -136,6 +165,7 @@
// The empty comments forces clang-format to place one element per line.
proc tests[] = {
+ test_wuffs_wbmp_decode_frame_config, //
test_wuffs_wbmp_decode_image_config, //
test_wuffs_wbmp_decode_interface, //