Have std/png call zlib.decoder.transform_io
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 8e5eee9..7202a7b 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -8340,13 +8340,13 @@
     uint32_t f_width;
     uint32_t f_height;
     uint64_t f_bytes_per_row;
-    uint64_t f_workbuf_index;
+    uint64_t f_workbuf_wi;
     uint64_t f_workbuf_length;
     uint8_t f_call_sequence;
     uint8_t f_depth;
     uint32_t f_src_pixfmt;
-    uint32_t f_chunk_length;
     uint32_t f_chunk_type;
+    uint64_t f_chunk_length;
     uint64_t f_frame_config_io_position;
     wuffs_base__pixel_swizzler f_swizzler;
 
@@ -30227,9 +30227,9 @@
     while (true) {
       {
         WUFFS_BASE__COROUTINE_SUSPENSION_POINT(15);
-        uint32_t t_9;
+        uint64_t t_9;
         if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
-          t_9 = wuffs_base__load_u32be__no_bounds_check(iop_a_src);
+          t_9 = ((uint64_t)(wuffs_base__load_u32be__no_bounds_check(iop_a_src)));
           iop_a_src += 4;
         } else {
           self->private_data.s_decode_image_config[0].scratch = 0;
@@ -30245,7 +30245,7 @@
             *scratch <<= 8;
             *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_9);
             if (num_bits_9 == 24) {
-              t_9 = ((uint32_t)(*scratch >> 32));
+              t_9 = ((uint64_t)(*scratch >> 32));
               break;
             }
             num_bits_9 += 8;
@@ -30489,6 +30489,9 @@
   uint8_t* io0_v_w WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
   uint8_t* io1_v_w WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
   uint8_t* io2_v_w WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  uint64_t v_w_mark = 0;
+  uint64_t v_r_mark = 0;
+  wuffs_base__status v_zlib_status = wuffs_base__make_status(NULL);
 
   const uint8_t* iop_a_src = NULL;
   const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
@@ -30522,9 +30525,9 @@
       status = wuffs_base__make_status(wuffs_base__note__end_of_data);
       goto ok;
     }
-    self->private_impl.f_workbuf_index = 0;
+    self->private_impl.f_workbuf_wi = 0;
     while (true) {
-      if ((self->private_impl.f_workbuf_index >= self->private_impl.f_workbuf_length) || (self->private_impl.f_workbuf_length >= ((uint64_t)(a_workbuf.len)))) {
+      if ((self->private_impl.f_workbuf_wi >= self->private_impl.f_workbuf_length) || (self->private_impl.f_workbuf_length >= ((uint64_t)(a_workbuf.len)))) {
         status = wuffs_base__make_status(wuffs_base__error__bad_workbuf_length);
         goto exit;
       }
@@ -30541,12 +30544,28 @@
             &io1_v_w,
             &io2_v_w,
             wuffs_base__slice_u8__subslice_ij(a_workbuf,
-            self->private_impl.f_workbuf_index,
+            self->private_impl.f_workbuf_wi,
             self->private_impl.f_workbuf_length));
         {
           const uint8_t *o_1_io2_a_src = io2_a_src;
           wuffs_base__io_reader__limit(&io2_a_src, iop_a_src,
-              ((uint64_t)(self->private_impl.f_chunk_length)));
+              self->private_impl.f_chunk_length);
+          v_w_mark = ((uint64_t)(iop_v_w - io0_v_w));
+          v_r_mark = ((uint64_t)(iop_a_src - io0_a_src));
+          {
+            u_w.meta.wi = ((size_t)(iop_v_w - u_w.data.ptr));
+            if (a_src) {
+              a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+            }
+            wuffs_base__status t_0 = wuffs_zlib__decoder__transform_io(&self->private_data.f_zlib, v_w, a_src, wuffs_base__utility__empty_slice_u8());
+            v_zlib_status = t_0;
+            iop_v_w = u_w.data.ptr + u_w.meta.wi;
+            if (a_src) {
+              iop_a_src = a_src->data.ptr + a_src->meta.ri;
+            }
+          }
+          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;
         }
         v_w = o_0_v_w;
@@ -30555,9 +30574,30 @@
         io1_v_w = o_0_io1_v_w;
         io2_v_w = o_0_io2_v_w;
       }
-      goto label__0__break;
+      if (wuffs_base__status__is_ok(&v_zlib_status)) {
+        goto label__0__break;
+      } else if (v_zlib_status.repr == wuffs_base__suspension__short_write) {
+        status = wuffs_base__make_status(wuffs_base__error__too_much_data);
+        goto exit;
+      } else if (v_zlib_status.repr != wuffs_base__suspension__short_read) {
+        status = v_zlib_status;
+        if (wuffs_base__status__is_error(&status)) {
+          goto exit;
+        } else if (wuffs_base__status__is_suspension(&status)) {
+          status = wuffs_base__make_status(wuffs_base__error__cannot_return_a_suspension);
+          goto exit;
+        }
+        goto ok;
+      } else if (self->private_impl.f_chunk_length == 0) {
+      }
+      status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+      WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
     }
     label__0__break:;
+    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;
+    }
     self->private_impl.f_call_sequence = 255;
 
     goto ok;
diff --git a/std/png/decode_png.wuffs b/std/png/decode_png.wuffs
index 7ce1a9a..3e9fcb6 100644
--- a/std/png/decode_png.wuffs
+++ b/std/png/decode_png.wuffs
@@ -29,7 +29,7 @@
 	// bytes_per_row doesn't include the 1 byte for the per-row filter.
 	bytes_per_row : base.u64[..= 0x07FF_FFF8],
 
-	workbuf_index  : base.u64,
+	workbuf_wi     : base.u64,
 	workbuf_length : base.u64[..= 0x0007_FFFF_F100_0007],
 
 	// Call sequence states:
@@ -63,8 +63,8 @@
 
 	src_pixfmt : base.u32,
 
-	chunk_length : base.u32,
 	chunk_type   : base.u32,
+	chunk_length : base.u64,
 
 	frame_config_io_position : base.u64,
 
@@ -171,12 +171,12 @@
 
 	// Read up until an IDAT chunk.
 	while true {
-		this.chunk_length = args.src.read_u32be?()
+		this.chunk_length = args.src.read_u32be_as_u64?()
 		this.chunk_type = args.src.read_u32le?()
 		if this.chunk_type == 'IDAT'le {
 			break
 		}
-		args.src.skip_u32?(n: this.chunk_length)
+		args.src.skip?(n: this.chunk_length)
 		// TODO: verify CRC-32 checksum.
 		args.src.skip_u32?(n: 4)
 	} endwhile
@@ -229,7 +229,10 @@
 }
 
 pub func decoder.decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader, blend: base.pixel_blend, workbuf: slice base.u8, opts: nptr base.decode_frame_options) {
-	var w : base.io_writer
+	var w           : base.io_writer
+	var w_mark      : base.u64
+	var r_mark      : base.u64
+	var zlib_status : base.status
 
 	if this.call_sequence < 4 {
 		this.decode_frame_config?(dst: nullptr, src: args.src)
@@ -239,19 +242,39 @@
 		return base."@end of data"
 	}
 
-	this.workbuf_index = 0
+	this.workbuf_wi = 0
 	while true {
-		if (this.workbuf_index >= this.workbuf_length) or (
+		if (this.workbuf_wi >= this.workbuf_length) or (
 			this.workbuf_length >= args.workbuf.length()) {
 			return base."#bad workbuf length"
 		}
-		io_bind (io: w, data: args.workbuf[this.workbuf_index .. this.workbuf_length]) {
-			io_limit (io: args.src, limit: this.chunk_length as base.u64) {
+		io_bind (io: w, data: args.workbuf[this.workbuf_wi .. this.workbuf_length]) {
+			io_limit (io: args.src, limit: this.chunk_length) {
+				w_mark = w.mark()
+				r_mark = args.src.mark()
+				zlib_status =? this.zlib.transform_io?(
+					dst: w, src: args.src, workbuf: this.util.empty_slice_u8())
+				this.chunk_length ~sat-= args.src.count_since(mark: r_mark)
+				this.workbuf_wi ~sat+= w.count_since(mark: w_mark)
 			}
 		}
-		break
+
+		if zlib_status.is_ok() {
+			break
+		} else if zlib_status == base."$short write" {
+			return base."#too much data"
+		} else if zlib_status <> base."$short read" {
+			return zlib_status
+		} else if this.chunk_length == 0 {
+			// TODO: move to the next IDAT.
+		}
+		yield? base."$short read"
 	} endwhile
 
+	if this.workbuf_wi <> this.workbuf_length {
+		return base."#not enough data"
+	}
+
 	this.call_sequence = 0xFF
 }