Implement io_limit
diff --git a/internal/cgen/base/io-private.h b/internal/cgen/base/io-private.h
index 851732b..61a247b 100644
--- a/internal/cgen/base/io-private.h
+++ b/internal/cgen/base/io-private.h
@@ -34,6 +34,15 @@
// --------
+static inline void //
+wuffs_base__io_reader__limit(const uint8_t** ptr_io2_r,
+ const uint8_t* iop_r,
+ uint64_t limit) {
+ if (((uint64_t)(*ptr_io2_r - iop_r)) > limit) {
+ *ptr_io2_r = iop_r + limit;
+ }
+}
+
static inline uint32_t //
wuffs_base__io_reader__limited_copy_u32_to_slice(const uint8_t** ptr_iop_r,
const uint8_t* io2_r,
@@ -131,6 +140,15 @@
return (uint64_t)(n);
}
+static inline void //
+wuffs_base__io_writer__limit(uint8_t** ptr_io2_w,
+ uint8_t* iop_w,
+ uint64_t limit) {
+ if (((uint64_t)(*ptr_io2_w - iop_w)) > limit) {
+ *ptr_io2_w = iop_w + limit;
+ }
+}
+
static inline uint32_t //
wuffs_base__io_writer__limited_copy_u32_from_history(uint8_t** ptr_iop_w,
uint8_t* io1_w,
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 2b6b7be..f992c1f 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -185,15 +185,15 @@
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, index - mark);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\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__load_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_r != ((uint8_t)(a))) {\n return 2;\n }\n iop_r++;\n a >>= 8;\n }\n return 0;\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_reader__set(wuffs_base__io_buffer* b,\n const uint8_t** ptr_iop_r,\n c" +
- "onst uint8_t** ptr_io0_r,\n const uint8_t** ptr_io1_r,\n const uint8_t** ptr_io2_r,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = data.len;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_r = data.ptr;\n *ptr_io0_r = data.ptr;\n *ptr_io1_r = data.ptr;\n *ptr_io2_r = data.ptr + data.len;\n\n return b;\n}\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__load_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_" +
+ "r != ((uint8_t)(a))) {\n return 2;\n }\n iop_r++;\n a >>= 8;\n }\n return 0;\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_reader__set(wuffs_base__io_buffer* b,\n const uint8_t** ptr_iop_r,\n const uint8_t** ptr_io0_r,\n const uint8_t** ptr_io1_r,\n const uint8_t** ptr_io2_r,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = data.len;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_r = data.ptr;\n *ptr_io0_r = data.ptr;\n *ptr_io1_r = data.ptr;\n *ptr_io2_r = data.ptr + data.len;\n\n return b;\n}\n\n" +
"" +
- "// --------\n\nstatic inline uint64_t //\nwuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint64_t)(n);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_history(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n if (!distance) {\n return 0;\n }\n uint8_t* p = *ptr_iop_w;\n if ((size_t)(p - io1_w) < (size_t)(distance)) {\n return 0;\n }\n uint8_t* q = p - distance;\n size_t n = (size_t)(io2_w - " +
- "p);\n if ((size_t)(length) > n) {\n length = (uint32_t)(n);\n } else {\n n = (size_t)(length);\n }\n // TODO: unrolling by 3 seems best for the std/deflate benchmarks, but that\n // is mostly because 3 is the minimum length for the deflate format. This\n // function implementation shouldn't overfit to that one format. Perhaps the\n // limited_copy_u32_from_history Wuffs method should also take an unroll hint\n // argument, and the cgen can look if that argument is the constant\n // expression '3'.\n //\n // See also wuffs_base__io_writer__limited_copy_u32_from_history_fast below.\n //\n // Alternatively or additionally, have a sloppy_limited_copy_u32_from_history\n // method that copies 8 bytes at a time, which can more than length bytes?\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\n// wuffs_base__io_writer__limited_copy_u32_from_history_fast is like the\n// wuffs_base__io_writer__limited_copy" +
- "_u32_from_history function above, but has\n// stronger pre-conditions. The caller needs to prove that:\n// - distance > 0\n// - distance <= (*ptr_iop_w - io1_w)\n// - length <= (io2_w - *ptr_iop_w)\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_history_fast(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n uint8_t* p = *ptr_iop_w;\n uint8_t* q = p - distance;\n uint32_t n = length;\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_reader(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n " +
- " uint32_t length,\n const uint8_t** ptr_iop_r,\n const uint8_t* io2_r) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = length;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n const uint8_t* iop_r = *ptr_iop_r;\n if (n > ((size_t)(io2_r - iop_r))) {\n n = (size_t)(io2_r - iop_r);\n }\n if (n > 0) {\n memmove(iop_w, iop_r, n);\n *ptr_iop_w += n;\n *ptr_iop_r += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n uint32_t length,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > length) {\n n = length;\n }\n if (n > ((size_t)(io2_w - iop_w))) {\n" +
- " n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_writer__set(wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_w,\n uint8_t** ptr_io0_w,\n uint8_t** ptr_io1_w,\n uint8_t** ptr_io2_w,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = 0;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_w = data.ptr;\n *ptr_io0_w = data.ptr;\n *ptr_io1_w = data.ptr;\n *ptr_io2_w = data.ptr + data.len;\n\n return b;\n}\n\n" +
+ "// --------\n\nstatic inline uint64_t //\nwuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint64_t)(n);\n}\n\nstatic inline void //\nwuffs_base__io_writer__limit(uint8_t** ptr_io2_w,\n uint8_t* iop_w,\n uint64_t limit) {\n if (((uint64_t)(*ptr_io2_w - iop_w)) > limit) {\n *ptr_io2_w = iop_w + limit;\n }\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_history(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n " +
+ " uint32_t distance) {\n if (!distance) {\n return 0;\n }\n uint8_t* p = *ptr_iop_w;\n if ((size_t)(p - io1_w) < (size_t)(distance)) {\n return 0;\n }\n uint8_t* q = p - distance;\n size_t n = (size_t)(io2_w - p);\n if ((size_t)(length) > n) {\n length = (uint32_t)(n);\n } else {\n n = (size_t)(length);\n }\n // TODO: unrolling by 3 seems best for the std/deflate benchmarks, but that\n // is mostly because 3 is the minimum length for the deflate format. This\n // function implementation shouldn't overfit to that one format. Perhaps the\n // limited_copy_u32_from_history Wuffs method should also take an unroll hint\n // argument, and the cgen can look if that argument is the constant\n // expression '3'.\n //\n // See also wuffs_base__io_writer__limited_copy_u32_from_history_fast below.\n //\n // Alternatively or additionally, have a sloppy_limited_copy_u32_from_history\n // method that copies 8 bytes at a time, which can more than length bytes?\n for (; n >= 3; " +
+ "n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\n// wuffs_base__io_writer__limited_copy_u32_from_history_fast is like the\n// wuffs_base__io_writer__limited_copy_u32_from_history function above, but has\n// stronger pre-conditions. The caller needs to prove that:\n// - distance > 0\n// - distance <= (*ptr_iop_w - io1_w)\n// - length <= (io2_w - *ptr_iop_w)\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_history_fast(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n uint8_t* p = *ptr_iop_w;\n uint8_t* q = p - distance;\n uint32_t n = length;\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n" +
+ " }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_reader(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n uint32_t length,\n const uint8_t** ptr_iop_r,\n const uint8_t* io2_r) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = length;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n const uint8_t* iop_r = *ptr_iop_r;\n if (n > ((size_t)(io2_r - iop_r))) {\n n = (size_t)(io2_r - iop_r);\n }\n if (n > 0) {\n memmove(iop_w, iop_r, n);\n *ptr_iop_w += n;\n *ptr_iop_r += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__limited_copy_u32_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n " +
+ " uint32_t length,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > length) {\n n = length;\n }\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_writer__set(wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_w,\n uint8_t** ptr_io0_w,\n uint8_t** ptr_io1_w,\n uint8_t** ptr_io2_w,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = 0;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_w = data.ptr;\n *ptr_io0_w = data.ptr;\n *ptr_io1_w = data.ptr;\n *ptr_io2_w = data.ptr + data.len;\n\n return b;\n}\n\n" +
"" +
"// ---------------- I/O (Utility)\n\n#define wuffs_base__utility__empty_io_reader wuffs_base__empty_io_reader\n#define wuffs_base__utility__empty_io_writer wuffs_base__empty_io_writer\n" +
""
diff --git a/internal/cgen/statement.go b/internal/cgen/statement.go
index 7ff3efe..487f663 100644
--- a/internal/cgen/statement.go
+++ b/internal/cgen/statement.go
@@ -245,34 +245,47 @@
cTyp, qualifier = "writer", ""
}
name := e.Ident().Str(g.tm)
- b.printf("wuffs_base__io_buffer* %s%d_%s%s = %s%s;\n",
- oPrefix, ioBindNum, prefix, name, prefix, name)
-
- // TODO: save / restore all iop vars, not just for local IO vars? How
- // does this work if the io_bind body advances these pointers, either
- // directly or by calling other funcs?
- if e.Operator() == 0 {
- b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
- qualifier, oPrefix, ioBindNum, iopPrefix, prefix, name, iopPrefix, prefix, name)
- b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
- qualifier, oPrefix, ioBindNum, io0Prefix, prefix, name, io0Prefix, prefix, name)
- b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
- qualifier, oPrefix, ioBindNum, io1Prefix, prefix, name, io1Prefix, prefix, name)
- b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
- qualifier, oPrefix, ioBindNum, io2Prefix, prefix, name, io2Prefix, prefix, name)
- }
if n.Keyword() == t.IDIOBind {
- b.printf("%s%s = wuffs_base__io_%s__set(\n&%s%s,\n&%s%s%s,\n&%s%s%s,\n&%s%s%s,\n&%s%s%s,\n",
- prefix, name, cTyp, uPrefix, name, iopPrefix, prefix, name,
- io0Prefix, prefix, name, io1Prefix, prefix, name, io2Prefix, prefix, name)
+ b.printf("wuffs_base__io_buffer* %s%d_%s%s = %s%s;\n",
+ oPrefix, ioBindNum, prefix, name,
+ prefix, name)
+ b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ qualifier, oPrefix, ioBindNum, iopPrefix, prefix, name,
+ iopPrefix, prefix, name)
+ b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ qualifier, oPrefix, ioBindNum, io0Prefix, prefix, name,
+ io0Prefix, prefix, name)
+ b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ qualifier, oPrefix, ioBindNum, io1Prefix, prefix, name,
+ io1Prefix, prefix, name)
+ b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ qualifier, oPrefix, ioBindNum, io2Prefix, prefix, name,
+ io2Prefix, prefix, name)
+ b.printf("%s%s = wuffs_base__io_%s__set("+
+ "\n&%s%s,\n&%s%s%s,\n&%s%s%s,\n&%s%s%s,\n&%s%s%s,\n",
+ prefix, name, cTyp,
+ uPrefix, name,
+ iopPrefix, prefix, name,
+ io0Prefix, prefix, name,
+ io1Prefix, prefix, name,
+ io2Prefix, prefix, name)
if err := g.writeExpr(b, n.Arg1(), 0); err != nil {
return err
}
b.writes(");\n")
} else {
- return fmt.Errorf("TODO: implement io_limit (or remove it from the parser)")
+ b.printf("%suint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ qualifier, oPrefix, ioBindNum, io2Prefix, prefix, name, io2Prefix, prefix, name)
+ b.printf("wuffs_base__io_%s__limit(&%s%s%s, %s%s%s,\n",
+ cTyp,
+ io2Prefix, prefix, name,
+ iopPrefix, prefix, name)
+ if err := g.writeExpr(b, n.Arg1(), 0); err != nil {
+ return err
+ }
+ b.writes(");\n")
}
}
@@ -289,18 +302,24 @@
prefix = aPrefix
}
name := e.Ident().Str(g.tm)
- b.printf("%s%s = %s%d_%s%s;\n",
- prefix, name, oPrefix, ioBindNum, prefix, name)
- if e.Operator() == 0 {
+
+ if n.Keyword() == t.IDIOBind {
+ b.printf("%s%s = %s%d_%s%s;\n",
+ prefix, name,
+ oPrefix, ioBindNum, prefix, name)
b.printf("%s%s%s = %s%d_%s%s%s;\n",
- iopPrefix, prefix, name, oPrefix, ioBindNum, iopPrefix, prefix, name)
+ iopPrefix, prefix, name,
+ oPrefix, ioBindNum, iopPrefix, prefix, name)
b.printf("%s%s%s = %s%d_%s%s%s;\n",
- io0Prefix, prefix, name, oPrefix, ioBindNum, io0Prefix, prefix, name)
+ io0Prefix, prefix, name,
+ oPrefix, ioBindNum, io0Prefix, prefix, name)
b.printf("%s%s%s = %s%d_%s%s%s;\n",
- io1Prefix, prefix, name, oPrefix, ioBindNum, io1Prefix, prefix, name)
- b.printf("%s%s%s = %s%d_%s%s%s;\n",
- io2Prefix, prefix, name, oPrefix, ioBindNum, io2Prefix, prefix, name)
+ io1Prefix, prefix, name,
+ oPrefix, ioBindNum, io1Prefix, prefix, name)
}
+ b.printf("%s%s%s = %s%d_%s%s%s;\n",
+ io2Prefix, prefix, name,
+ oPrefix, ioBindNum, io2Prefix, prefix, name)
}
b.writes("}\n")
return nil
diff --git a/internal/cgen/var.go b/internal/cgen/var.go
index 6bdd391..f59e651 100644
--- a/internal/cgen/var.go
+++ b/internal/cgen/var.go
@@ -42,25 +42,30 @@
}
for _, o := range g.currFunk.astFunc.Body() {
err := o.Walk(func(p *a.Node) error {
- // Look for p matching "args.name.etc(etc)".
- if p.Kind() != a.KExpr {
- return nil
- }
- recv, meth, args := p.AsExpr().IsMethodCall()
- if recv == nil {
- return nil
- }
- if recv.IsArgsDotFoo() == name {
- return errNeedDerivedVar
- }
- // Some built-in methods will also need a derived var for their
- // arguments.
- //
- // TODO: use a comprehensive list of such methods.
- switch meth {
- case t.IDLimitedSwizzleU32InterleavedFromReader,
- t.IDSwizzleInterleavedFromReader:
- if recv.MType().Eq(typeExprPixelSwizzler) && argsContainsArgsDotFoo(args, name) {
+ switch p.Kind() {
+ case a.KExpr:
+ // Look for p matching "args.name.etc(etc)".
+ recv, meth, args := p.AsExpr().IsMethodCall()
+ if recv == nil {
+ return nil
+ }
+ if recv.IsArgsDotFoo() == name {
+ return errNeedDerivedVar
+ }
+ // Some built-in methods will also need a derived var for their
+ // arguments.
+ //
+ // TODO: use a comprehensive list of such methods.
+ switch meth {
+ case t.IDLimitedSwizzleU32InterleavedFromReader,
+ t.IDSwizzleInterleavedFromReader:
+ if recv.MType().Eq(typeExprPixelSwizzler) && argsContainsArgsDotFoo(args, name) {
+ return errNeedDerivedVar
+ }
+ }
+
+ case a.KIOBind:
+ if p.AsIOBind().IO().IsArgsDotFoo() == name {
return errNeedDerivedVar
}
}
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index b7ac21c..e61e476 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -9307,6 +9307,15 @@
// --------
+static inline void //
+wuffs_base__io_reader__limit(const uint8_t** ptr_io2_r,
+ const uint8_t* iop_r,
+ uint64_t limit) {
+ if (((uint64_t)(*ptr_io2_r - iop_r)) > limit) {
+ *ptr_io2_r = iop_r + limit;
+ }
+}
+
static inline uint32_t //
wuffs_base__io_reader__limited_copy_u32_to_slice(const uint8_t** ptr_iop_r,
const uint8_t* io2_r,
@@ -9404,6 +9413,15 @@
return (uint64_t)(n);
}
+static inline void //
+wuffs_base__io_writer__limit(uint8_t** ptr_io2_w,
+ uint8_t* iop_w,
+ uint64_t limit) {
+ if (((uint64_t)(*ptr_io2_w - iop_w)) > limit) {
+ *ptr_io2_w = iop_w + limit;
+ }
+}
+
static inline uint32_t //
wuffs_base__io_writer__limited_copy_u32_from_history(uint8_t** ptr_iop_w,
uint8_t* io1_w,
@@ -29993,13 +30011,30 @@
self->private_impl.active_coroutine = 0;
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_frame[0];
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
if (self->private_impl.f_call_sequence < 4) {
+ 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_frame_config(self, NULL, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status.repr) {
goto suspend;
}
@@ -30008,6 +30043,16 @@
status = wuffs_base__make_status(wuffs_base__note__end_of_data);
goto ok;
}
+ while (true) {
+ {
+ const uint8_t *o_0_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)));
+ io2_a_src = o_0_io2_a_src;
+ }
+ goto label__0__break;
+ }
+ label__0__break:;
self->private_impl.f_call_sequence = 255;
goto ok;
@@ -30023,6 +30068,10 @@
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;
}
diff --git a/std/png/decode_png.wuffs b/std/png/decode_png.wuffs
index 208b878..f99be8e 100644
--- a/std/png/decode_png.wuffs
+++ b/std/png/decode_png.wuffs
@@ -231,6 +231,12 @@
return base."@end of data"
}
+ while true {
+ io_limit (io: args.src, limit: this.chunk_length as base.u64) {
+ }
+ break
+ } endwhile
+
this.call_sequence = 0xFF
}