std/xz: use io_forget_history
diff --git a/internal/cgen/cgen.go b/internal/cgen/cgen.go
index 7c4a775..cc3ed64 100644
--- a/internal/cgen/cgen.go
+++ b/internal/cgen/cgen.go
@@ -50,7 +50,7 @@
aPrefix = "a_" // Function argument.
fPrefix = "f_" // Struct field.
iPrefix = "i_" // Iterate variable.
- oPrefix = "o_" // Temporary io_bind variable.
+ oPrefix = "o_" // Temporary IOManip variable.
pPrefix = "p_" // Coroutine suspension point (program counter).
sPrefix = "s_" // Coroutine stack (saved local variables).
tPrefix = "t_" // Temporary local variable.
@@ -67,10 +67,12 @@
// The other two prefixes, giving names like io1_etc and io2_etc, are auxiliary
// pointers: lower and upper inclusive bounds. As an iop_etc pointer advances,
// it cannot advance past io2_etc. In the rarer case that an iop_etc pointer
-// retreats, undoing a read or write, it cannot retreat past io1_etc.
+// retreats, undoing a read or write, it cannot retreat past io1_etc. The
+// io0_etc pointer is used to calculate the history_length and is the base that
+// marks are relative to.
//
// The iop_etc pointer can change over the lifetime of a function. The ioN_etc
-// pointers, for numeric N, cannot.
+// pointers, for numeric N, cannot (except by IOManip blocks).
//
// At the start of a function, these pointers are initialized from an
// io_buffer's fields (ptr, ri, wi, len). For an io_reader:
diff --git a/internal/cgen/statement.go b/internal/cgen/statement.go
index 795b884..184189b 100644
--- a/internal/cgen/statement.go
+++ b/internal/cgen/statement.go
@@ -347,6 +347,46 @@
}
b.writes(");\n")
+ } else if keyword == t.IDIOForgetHistory {
+ if !isWriter {
+ return fmt.Errorf("unsupported io_forget_history for an io_reader")
+ }
+ 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("%s%s%s = %s%s%s;\n",
+ io0Prefix, prefix, name, iopPrefix, prefix, name)
+ b.printf("%s%s%s = %s%s%s;\n",
+ io1Prefix, prefix, name, iopPrefix, prefix, name)
+ b.printf("wuffs_base__io_buffer %s%d_%s%s;\n",
+ oPrefix, ioBindNum, prefix, name)
+ b.printf("if (%s%s) {\n",
+ prefix, name)
+ if isWriter {
+ b.printf("memcpy(&%s%d_%s%s, %s%s, sizeof(*%s%s));\n",
+ oPrefix, ioBindNum, prefix, name,
+ prefix, name,
+ prefix, name)
+ b.printf("size_t wi%d = %s%s->meta.wi;\n",
+ ioBindNum, prefix, name)
+ b.printf("%s%s->data.ptr += wi%d;\n",
+ prefix, name, ioBindNum)
+ b.printf("%s%s->data.len -= wi%d;\n",
+ prefix, name, ioBindNum)
+ b.printf("%s%s->meta.ri = 0;\n",
+ prefix, name)
+ b.printf("%s%s->meta.wi = 0;\n",
+ prefix, name)
+ b.printf("%s%s->meta.pos = wuffs_base__u64__sat_add(%s%s->meta.pos, wi%d);\n",
+ prefix, name, prefix, name, ioBindNum)
+ } else {
+ // TODO.
+ }
+ b.printf("}\n")
+
} else {
if !isWriter {
b.printf("const bool %s%d_closed_%s%s = %s%s->meta.closed;\n",
@@ -399,13 +439,36 @@
io2Prefix, prefix, name,
oPrefix, ioBindNum, io2Prefix, prefix, name)
+ } else if keyword == t.IDIOForgetHistory {
+ b.printf("if (%s%s) {\n",
+ prefix, name)
+ if isWriter {
+ b.printf("memcpy(%s%s, &%s%d_%s%s, sizeof(*%s%s));\n",
+ prefix, name,
+ oPrefix, ioBindNum, prefix, name,
+ prefix, name)
+ b.printf("%s%s->meta.wi = ((size_t)(%s%s%s - %s%s->data.ptr));\n",
+ prefix, name, iopPrefix, prefix, name, prefix, name)
+ b.printf("%s%s%s = %s%d_%s%s%s;\n",
+ 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)
+ } else {
+ // TODO.
+ }
+ b.printf("}\n")
+
} else {
b.printf("%s%s%s = %s%d_%s%s%s;\n",
io2Prefix, prefix, name,
oPrefix, ioBindNum, io2Prefix, prefix, name)
b.printf("if (%s%s) {\n", prefix, name)
- b.printf("%s%s->meta.closed = %s%d_closed_%s%s;\n",
- prefix, name, oPrefix, ioBindNum, prefix, name)
+ if !isWriter {
+ b.printf("%s%s->meta.closed = %s%d_closed_%s%s;\n",
+ prefix, name, oPrefix, ioBindNum, prefix, name)
+ }
b.printf("%s%s->%s = ((size_t)(%s%s%s - %s%s->data.ptr));\n",
prefix, name, end,
io2Prefix, prefix, name,
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4fd2387..596a5c7 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -67290,19 +67290,41 @@
}
} else {
{
+ uint8_t* o_0_io0_a_dst = io0_a_dst;
+ uint8_t* o_0_io1_a_dst = io1_a_dst;
+ io0_a_dst = iop_a_dst;
+ io1_a_dst = iop_a_dst;
+ wuffs_base__io_buffer o_0_a_dst;
if (a_dst) {
+ memcpy(&o_0_a_dst, a_dst, sizeof(*a_dst));
+ size_t wi0 = a_dst->meta.wi;
+ a_dst->data.ptr += wi0;
+ a_dst->data.len -= wi0;
+ a_dst->meta.ri = 0;
+ a_dst->meta.wi = 0;
+ a_dst->meta.pos = wuffs_base__u64__sat_add(a_dst->meta.pos, wi0);
+ }
+ {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ wuffs_base__status t_5 = wuffs_lzma__decoder__transform_io(&self->private_data.f_lzma, a_dst, a_src, a_workbuf);
+ v_status = t_5;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ }
+ if (a_dst) {
+ memcpy(a_dst, &o_0_a_dst, sizeof(*a_dst));
a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- wuffs_base__status t_5 = wuffs_lzma__decoder__transform_io(&self->private_data.f_lzma, a_dst, a_src, a_workbuf);
- v_status = t_5;
- if (a_dst) {
- iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
- }
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ io0_a_dst = o_0_io0_a_dst;
+ io1_a_dst = o_0_io1_a_dst;
}
}
wuffs_xz__decoder__apply_non_final_filters(self, wuffs_private_impl__io__since(v_dmark, ((uint64_t)(iop_a_dst - io0_a_dst)), io0_a_dst));
diff --git a/std/xz/decode_xz.wuffs b/std/xz/decode_xz.wuffs
index 50aea4a..f4b1b8e 100644
--- a/std/xz/decode_xz.wuffs
+++ b/std/xz/decode_xz.wuffs
@@ -179,7 +179,12 @@
if this.num_non_final_filters == 0 {
status =? this.lzma.transform_io?(dst: args.dst, src: args.src, workbuf: args.workbuf)
} else {
- status =? this.lzma.transform_io?(dst: args.dst, src: args.src, workbuf: args.workbuf)
+ // The non-final filters will modify the args.dst contents so
+ // that its history isn't what this.lzma considers its
+ // (unfiltered) history.
+ io_forget_history (io: args.dst) {
+ status =? this.lzma.transform_io?(dst: args.dst, src: args.src, workbuf: args.workbuf)
+ }
this.apply_non_final_filters!(dst_slice: args.dst.since(mark: dmark))
}
compressed_size ~mod+= args.src.count_since(mark: smark)
diff --git a/test/c/std/xz.c b/test/c/std/xz.c
index e5d96a1..bbe67a8 100644
--- a/test/c/std/xz.c
+++ b/test/c/std/xz.c
@@ -131,6 +131,39 @@
}
const char* //
+wuffs_xz_decode_with_history(wuffs_base__io_buffer* dst,
+ wuffs_base__io_buffer* src,
+ uint32_t wuffs_initialize_flags,
+ uint64_t wlimit,
+ uint64_t rlimit) {
+ if (wlimit != UINT64_MAX) {
+ return "wuffs_xz_decode_with_history assumes wlimit == UINT64_MAX";
+ }
+
+ wuffs_xz__decoder dec;
+ CHECK_STATUS("initialize",
+ wuffs_xz__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION,
+ wuffs_initialize_flags));
+
+ while (true) {
+ wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
+
+ // Compared to wuffs_xz_decode, wuffs_xz_decode_with_history passes dst
+ // directly, not limited_dst (which has no history).
+ wuffs_base__status status = wuffs_xz__decoder__transform_io(
+ &dec, dst, &limited_src, g_work_slice_u8);
+
+ src->meta.ri += limited_src.meta.ri;
+
+ if (((rlimit < UINT64_MAX) &&
+ (status.repr == wuffs_base__suspension__short_read))) {
+ continue;
+ }
+ return status.repr;
+ }
+}
+
+const char* //
test_wuffs_xz_decode_enwik5() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_xz_decode, &g_xz_enwik5_gt, UINT64_MAX,
@@ -138,13 +171,20 @@
}
const char* //
-test_wuffs_xz_decode_one_byte_reads() {
+test_wuffs_xz_decode_one_byte_reads_sans_history() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_xz_decode, &g_xz_romeo_delta1_gt, UINT64_MAX,
1);
}
const char* //
+test_wuffs_xz_decode_one_byte_reads_with_history() {
+ CHECK_FOCUS(__func__);
+ return do_test_io_buffers(wuffs_xz_decode_with_history, &g_xz_romeo_delta1_gt,
+ UINT64_MAX, 1);
+}
+
+const char* //
test_wuffs_xz_decode_romeo() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_xz_decode, &g_xz_romeo_gt, UINT64_MAX,
@@ -201,7 +241,8 @@
test_wuffs_xz_decode_enwik5,
test_wuffs_xz_decode_interface,
- test_wuffs_xz_decode_one_byte_reads,
+ test_wuffs_xz_decode_one_byte_reads_sans_history,
+ test_wuffs_xz_decode_one_byte_reads_with_history,
test_wuffs_xz_decode_romeo,
#ifdef WUFFS_MIMIC