summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh MacDonald <josh.macdonald@gmail.com>2015-12-27 22:12:34 -0800
committerJosh MacDonald <josh.macdonald@gmail.com>2015-12-27 22:12:34 -0800
commitec9905aa755eafb64f08fc59ca7e67ea57498264 (patch)
tree304cae17d7d856c3ef465f7fad18398347272970
parentdbbc4c4a59bb805a828bd61640ec8ba88fe92871 (diff)
parentcf662894ba5b3847f06fd44dfb91f4733d9196f4 (diff)
Merge frmo origin
-rw-r--r--xdelta3/Makefile.am3
-rw-r--r--xdelta3/go/src/regtest.go8
-rw-r--r--xdelta3/go/src/xdelta/run.go3
-rw-r--r--xdelta3/go/src/xdelta/tgroup.go4
-rwxr-xr-xxdelta3/run_release.sh2
-rw-r--r--xdelta3/testing/regtest.cc173
-rw-r--r--xdelta3/testing/test.h4
-rw-r--r--xdelta3/xdelta3-blkcache.h22
-rw-r--r--xdelta3/xdelta3-decode.h16
-rw-r--r--xdelta3/xdelta3-djw.h14
-rw-r--r--xdelta3/xdelta3-internal.h6
-rw-r--r--xdelta3/xdelta3-main.h9
-rw-r--r--xdelta3/xdelta3-merge.h21
-rw-r--r--xdelta3/xdelta3-second.h9
-rw-r--r--xdelta3/xdelta3-test.h2
-rw-r--r--xdelta3/xdelta3.c272
-rw-r--r--xdelta3/xdelta3.h4
17 files changed, 318 insertions, 254 deletions
diff --git a/xdelta3/Makefile.am b/xdelta3/Makefile.am
index 11f75b0..f437764 100644
--- a/xdelta3/Makefile.am
+++ b/xdelta3/Makefile.am
@@ -61,6 +61,9 @@ if DEBUG_SYMBOLS
61 common_CFLAGS += -g 61 common_CFLAGS += -g
62endif 62endif
63 63
64#common_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
65#common_CFLAGS += -O2
66
64# For additional debugging, add -DXD3_DEBUG=1, 2, 3, ... 67# For additional debugging, add -DXD3_DEBUG=1, 2, 3, ...
65xdelta3_CFLAGS = $(C_WFLAGS) $(common_CFLAGS) -DXD3_DEBUG=0 68xdelta3_CFLAGS = $(C_WFLAGS) $(common_CFLAGS) -DXD3_DEBUG=0
66xdelta3_LDADD = -lm 69xdelta3_LDADD = -lm
diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go
index bcf0de9..a7cab33 100644
--- a/xdelta3/go/src/regtest.go
+++ b/xdelta3/go/src/regtest.go
@@ -13,8 +13,8 @@ import (
13 13
14const ( 14const (
15 xdataset = "/volume/home/jmacd/src/testdata" 15 xdataset = "/volume/home/jmacd/src/testdata"
16 xcompare = "/volume/home/jmacd/src/xdelta3-devel/xdelta3/xdelta3" 16 xcompare = "/volume/home/jmacd/src/xdelta-devel/xdelta3/xdelta3"
17 xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/xdelta3" 17 xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/xdelta3"
18 seed = 1422253499919909358 18 seed = 1422253499919909358
19) 19)
20 20
@@ -35,12 +35,10 @@ func (c Config) smokeTest(t *xdelta.TestGroup, p xdelta.Program) {
35 35
36 enc, err := t.Exec("encode", p, true, []string{"-e"}) 36 enc, err := t.Exec("encode", p, true, []string{"-e"})
37 if err != nil { 37 if err != nil {
38 fmt.Println(err)
39 t.Panic(err) 38 t.Panic(err)
40 } 39 }
41 dec, err := t.Exec("decode", p, true, []string{"-d"}) 40 dec, err := t.Exec("decode", p, true, []string{"-d"})
42 if err != nil { 41 if err != nil {
43 fmt.Println(err)
44 t.Panic(err) 42 t.Panic(err)
45 } 43 }
46 44
@@ -234,7 +232,7 @@ func (cfg Config) offsetTest(t *xdelta.TestGroup, p xdelta.Program, offset, leng
234 232
235 // The decoder output ("read", above) is compared with the 233 // The decoder output ("read", above) is compared with the
236 // test-provided output ("write", below). The following 234 // test-provided output ("write", below). The following
237 // generates the input and output twice. 235 // generates two identical inputs.
238 t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin) 236 t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin)
239 t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write) 237 t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write)
240 t.Wait(enc, dec) 238 t.Wait(enc, dec)
diff --git a/xdelta3/go/src/xdelta/run.go b/xdelta3/go/src/xdelta/run.go
index 6523a1c..448fabe 100644
--- a/xdelta3/go/src/xdelta/run.go
+++ b/xdelta3/go/src/xdelta/run.go
@@ -55,7 +55,8 @@ func (r *Runner) RunTest(name string, f func (t *TestGroup)) {
55 c := make(chan interface{}) 55 c := make(chan interface{})
56 go func() { 56 go func() {
57 defer func() { 57 defer func() {
58 c <- recover() 58 rec := recover()
59 c <- rec
59 }() 60 }()
60 fmt.Println("Testing", name, "...") 61 fmt.Println("Testing", name, "...")
61 f(t) 62 f(t)
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go
index b1b04ec..602b1e1 100644
--- a/xdelta3/go/src/xdelta/tgroup.go
+++ b/xdelta3/go/src/xdelta/tgroup.go
@@ -58,7 +58,9 @@ func (g *Goroutine) OK() {
58 58
59func (g *Goroutine) Panic(err error) { 59func (g *Goroutine) Panic(err error) {
60 g.finish(err) 60 g.finish(err)
61 runtime.Goexit() 61 if g != g.TestGroup.main {
62 runtime.Goexit()
63 }
62} 64}
63 65
64func (t *TestGroup) Main() *Goroutine { return t.main } 66func (t *TestGroup) Main() *Goroutine { return t.main }
diff --git a/xdelta3/run_release.sh b/xdelta3/run_release.sh
index f38c44d..eb08afc 100755
--- a/xdelta3/run_release.sh
+++ b/xdelta3/run_release.sh
@@ -123,6 +123,7 @@ function buildit {
123 local FULLD="${SRCDIR}/${D}" 123 local FULLD="${SRCDIR}/${D}"
124 local CFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" 124 local CFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include"
125 local CXXFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" 125 local CXXFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include"
126 local CPPFLAGS="-I${SRCDIR}/build/lib-${LIBBM}/include"
126 local LDFLAGS="${march} -L${SRCDIR}/build/lib-${LIBBM}/lib" 127 local LDFLAGS="${march} -L${SRCDIR}/build/lib-${LIBBM}/lib"
127 128
128 mkdir -p ${D} 129 mkdir -p ${D}
@@ -179,6 +180,7 @@ EOF
179 --enable-debug-symbols \ 180 --enable-debug-symbols \
180 "CFLAGS=${CFLAGS}" \ 181 "CFLAGS=${CFLAGS}" \
181 "CXXFLAGS=${CXXFLAGS}" \ 182 "CXXFLAGS=${CXXFLAGS}" \
183 "CPPFLAGS=${CPPFLAGS}" \
182 "LDFLAGS=${LDFLAGS}" \ 184 "LDFLAGS=${LDFLAGS}" \
183 "CC=${USECC}" \ 185 "CC=${USECC}" \
184 "CXX=${USECXX}" 186 "CXX=${USECXX}"
diff --git a/xdelta3/testing/regtest.cc b/xdelta3/testing/regtest.cc
index bee7477..e83af4b 100644
--- a/xdelta3/testing/regtest.cc
+++ b/xdelta3/testing/regtest.cc
@@ -92,7 +92,7 @@ public:
92 bool done = false; 92 bool done = false;
93 bool done_after_input = false; 93 bool done_after_input = false;
94 94
95 IF_DEBUG1 (XPR(NTR "source %"Q"[%"Q"] target %"Q" winsize %lu\n", 95 IF_DEBUG1 (XPR(NTR "source %"Q"u[%"Q"u] target %"Q"u winsize %"Z"u\n",
96 source_file.Size(), options.block_size, 96 source_file.Size(), options.block_size,
97 target_file.Size(), 97 target_file.Size(),
98 Constants::WINDOW_SIZE)); 98 Constants::WINDOW_SIZE));
@@ -153,7 +153,7 @@ public:
153 xd3_source *src = (encoding ? &encode_source : &decode_source); 153 xd3_source *src = (encoding ? &encode_source : &decode_source);
154 Block *block = (encoding ? &encode_source_block : &decode_source_block); 154 Block *block = (encoding ? &encode_source_block : &decode_source_block);
155 if (encoding) { 155 if (encoding) {
156 IF_DEBUG1(XPR(NTR "[srcblock] %"Q"u last srcpos %"Q"u " 156 IF_DEBUG2(XPR(NTR "[srcblock] %"Q"u last srcpos %"Q"u "
157 "encodepos %"Q"u\n", 157 "encodepos %"Q"u\n",
158 encode_source.getblkno, 158 encode_source.getblkno,
159 encode_stream.match_last_srcpos, 159 encode_stream.match_last_srcpos,
@@ -790,32 +790,34 @@ void TestSmallStride() {
790 usize_t size = Constants::BLOCK_SIZE * 4; 790 usize_t size = Constants::BLOCK_SIZE * 4;
791 spec0.GenerateFixedSize(size); 791 spec0.GenerateFixedSize(size);
792 792
793 /* TODO Need to study the actual causes of missed adds for tests 793 // Note: Not very good performance due to hash collisions, note 3x
794 * less than 30 bytes. */ 794 // multiplier below.
795 const int s = 30; 795 for (int s = 15; s < 101; s++) {
796 usize_t adds = 0; 796 usize_t changes = 0;
797 ChangeList cl; 797 ChangeList cl;
798 for (usize_t j = s; j < size; j += s, ++adds) 798 for (usize_t j = s; j < size; j += s, ++changes)
799 { 799 {
800 cl.push_back(Change(Change::MODIFY, 1, j)); 800 cl.push_back(Change(Change::MODIFY, 1, j));
801 } 801 }
802 802
803 FileSpec spec1(&rand); 803 FileSpec spec1(&rand);
804 spec0.ModifyTo(ChangeListMutator(cl), &spec1); 804 spec0.ModifyTo(ChangeListMutator(cl), &spec1);
805 805
806 Options options; 806 Options options;
807 options.encode_srcwin_maxsz = size; 807 options.encode_srcwin_maxsz = size;
808 options.iopt_size = 128; 808 options.iopt_size = 128;
809 options.smatch_cfg = XD3_SMATCH_SLOW; 809 options.smatch_cfg = XD3_SMATCH_SLOW;
810 options.size_known = false; 810 options.size_known = false;
811 811
812 Block block; 812 Block block;
813 InMemoryEncodeDecode(spec0, spec1, &block, options); 813 InMemoryEncodeDecode(spec0, spec1, &block, options);
814 Delta delta(block); 814 Delta delta(block);
815 815
816 // Allow an additional two byte of add per window 816 IF_DEBUG1(DP(RINT "[stride=%d] changes=%u adds=%"Q"u\n",
817 usize_t allowance = 2 * size / Constants::WINDOW_SIZE; 817 s, changes, delta.AddedBytes()));
818 CHECK_GE(adds + allowance, delta.AddedBytes()); 818 double allowance = Constants::BLOCK_SIZE < 8192 || s < 30 ? 3.0 : 1.1;
819 CHECK_GE(allowance * changes, (double)delta.AddedBytes());
820 }
819} 821}
820 822
821void TestCopyWindow() { 823void TestCopyWindow() {
@@ -927,85 +929,73 @@ void TestCopyFromEnd() {
927} 929}
928 930
929void TestHalfBlockCopy() { 931void TestHalfBlockCopy() {
930 MTRandom rand; 932 // Create a half-block copy, 7.5 blocks apart, in a pair of files:
931 FileSpec spec0(&rand); 933 // 0 1 ... 6 7
932 FileSpec spec1(&rand); 934 // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbb_]
933 935 // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_]
934 spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 4); 936 // where stage=
935 937 // 0: the final block is full
936 // Create a half-block copy, 2.5 blocks apart, from the second half 938 // a. (source)spec1->(target)spec0 copies block C: reads 8 source
937 // of the source version to the first half of the target version. 939 // blocks during target block 0.
938 // 0 1 2 3 940 // b. (source)spec0->(target)spec1 does not copy block C b/c attempt
939 // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbbb] 941 // to read past EOF empties block 0 from (virtual) block cache
940 // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] 942 // 1: the final block is less than full.
941 ChangeList cl1; 943 // a. (same) copies block C
942 cl1.push_back(Change(Change::MODIFY, 944 // b. (same) copies block C, unlike 0a, no attempt to read past EOF
943 Constants::BLOCK_SIZE / 2, // size 945 //
944 0)); 946 // "virtual" above refers to XD3_TOOFARBACK, since there is no caching
945 cl1.push_back(Change(Change::COPYOVER, 947 // in the API, there is simply a promise not to request blocks that are
946 Constants::BLOCK_SIZE / 2, // size 948 // beyond source->max_winsize from the last known source file position.
947 Constants::BLOCK_SIZE * 3, // offset 949 for (int stage = 0; stage < 2; stage++)
948 Constants::BLOCK_SIZE / 2));
949 cl1.push_back(Change(Change::MODIFY,
950 Constants::BLOCK_SIZE * 3,
951 Constants::BLOCK_SIZE));
952 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
953
954 const int onecopy_adds =
955 4 * Constants::BLOCK_SIZE - Constants::BLOCK_SIZE / 2;
956 const int nocopy_adds = 4 * Constants::BLOCK_SIZE;
957
958 // Note the case b=4 is contrived: the caller should use a single block
959 // containing the entire source, if possible.
960 for (int b = 1; b <= 4; b++)
961 { 950 {
951 IF_DEBUG1 (DP(RINT "half_block_copy stage %d\n", stage));
952
953 MTRandom rand;
954 FileSpec spec0(&rand);
955 FileSpec spec1(&rand);
956
957 spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 8 - stage);
958
959 ChangeList cl1;
960 cl1.push_back(Change(Change::MODIFY,
961 Constants::BLOCK_SIZE / 2, // size
962 0));
963 cl1.push_back(Change(Change::COPYOVER,
964 Constants::BLOCK_SIZE / 2, // size
965 Constants::BLOCK_SIZE * 7, // offset
966 Constants::BLOCK_SIZE / 2));
967 cl1.push_back(Change(Change::MODIFY,
968 Constants::BLOCK_SIZE * 7,
969 Constants::BLOCK_SIZE - stage));
970 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
971
962 Options options; 972 Options options;
963 options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * b; 973 options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 8;
964 974
965 Block block0; 975 Block block0;
966 Block block1; 976 Block block1;
967 InMemoryEncodeDecode(spec0, spec1, &block0, options); 977 InMemoryEncodeDecode(spec0, spec1, &block0, options);
968 InMemoryEncodeDecode(spec1, spec0, &block1, options); 978 InMemoryEncodeDecode(spec1, spec0, &block1, options);
979
969 Delta delta0(block0); 980 Delta delta0(block0);
970 Delta delta1(block1); 981 Delta delta1(block1);
971 982
972 // The first block never copies from the last source block, by 983 const int yes =
973 // design, because if the last source block is available when 984 Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2;
974 // the first target block is ready, the caller is expected to 985 const int no =
975 // use a single block. 986 Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2;
976 CHECK_EQ(nocopy_adds, delta0.AddedBytes()); 987
977 if (Constants::BLOCK_SIZE < 8192 || b > 2) 988 if (stage == 0)
978 { 989 {
979 // For small-block inputs, the entire file is read into one 990 CHECK_EQ(yes, delta0.AddedBytes());
980 // block (the min source window size is 16kB). 991 CHECK_EQ(no, delta1.AddedBytes());
981 // 992 }
982 // For large blocks, at least 3 blocks of source window are
983 // needed.
984 CHECK_EQ(onecopy_adds, delta1.AddedBytes());
985 }
986 else 993 else
987 { 994 {
988 // When there are fewer than 3 source blocks. 995 CHECK_EQ(yes, delta0.AddedBytes());
989 CHECK_EQ(nocopy_adds, delta1.AddedBytes()); 996 CHECK_EQ(yes, delta1.AddedBytes());
990 } 997 }
991 } 998 }
992
993 Options options;
994 options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 4;
995 options.block_size = Constants::BLOCK_SIZE * 4;
996
997 // Test the whole-buffer case.
998 Block block0;
999 Block block1;
1000 InMemoryEncodeDecode(spec0, spec1, &block0, options);
1001 InMemoryEncodeDecode(spec1, spec0, &block1, options);
1002 Delta delta0(block0);
1003 Delta delta1(block1);
1004 // This <= >= are only for blocksize = 512, which has irregular readsize.
1005 CHECK_LE(onecopy_adds, delta0.AddedBytes());
1006 CHECK_GE(onecopy_adds + 1, delta0.AddedBytes());
1007
1008 CHECK_EQ(onecopy_adds, delta1.AddedBytes());
1009} 999}
1010 1000
1011void FourWayMergeTest(const FileSpec &spec0, 1001void FourWayMergeTest(const FileSpec &spec0,
@@ -1310,3 +1300,4 @@ int main(int argc, char **argv)
1310 1300
1311 return 0; 1301 return 0;
1312} 1302}
1303
diff --git a/xdelta3/testing/test.h b/xdelta3/testing/test.h
index 30d13a3..7de24fb 100644
--- a/xdelta3/testing/test.h
+++ b/xdelta3/testing/test.h
@@ -22,8 +22,8 @@ extern "C" {
22 __typeof__(x) _y(y); \ 22 __typeof__(x) _y(y); \
23 if (!(_x OP _y)) { \ 23 if (!(_x OP _y)) { \
24 cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \ 24 cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \
25 cerr << __FILE__ << ":" << __LINE__ << " Expected: " << _x << endl; \ 25 cerr << __FILE__ << ":" << __LINE__ << " {0} " << _x << endl; \
26 cerr << __FILE__ << ":" << __LINE__ << " Actual: " << _y << endl; \ 26 cerr << __FILE__ << ":" << __LINE__ << " {1} " << _y << endl; \
27 abort(); \ 27 abort(); \
28 } } while (false) 28 } } while (false)
29#undef CHECK 29#undef CHECK
diff --git a/xdelta3/xdelta3-blkcache.h b/xdelta3/xdelta3-blkcache.h
index 8de5d13..20a2a4a 100644
--- a/xdelta3/xdelta3-blkcache.h
+++ b/xdelta3/xdelta3-blkcache.h
@@ -183,6 +183,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
183 if (!sfile->size_known && source->onblk < blksize) 183 if (!sfile->size_known && source->onblk < blksize)
184 { 184 {
185 source_size = source->onblk; 185 source_size = source->onblk;
186 source->onlastblk = source_size;
186 sfile->size_known = 1; 187 sfile->size_known = 1;
187 } 188 }
188 189
@@ -194,8 +195,10 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
194 /* Modify block 0, change blocksize. */ 195 /* Modify block 0, change blocksize. */
195 blksize = option_srcwinsz / MAX_LRU_SIZE; 196 blksize = option_srcwinsz / MAX_LRU_SIZE;
196 source->blksize = blksize; 197 source->blksize = blksize;
197 source->onblk = blksize; /* xd3 sets onblk */ 198 source->onblk = blksize;
198 /* Note: source->max_winsize is unchanged. */ 199 source->onlastblk = blksize;
200 source->max_blkno = MAX_LRU_SIZE - 1;
201
199 lru[0].size = blksize; 202 lru[0].size = blksize;
200 lru_size = MAX_LRU_SIZE; 203 lru_size = MAX_LRU_SIZE;
201 204
@@ -309,9 +312,13 @@ main_getblk_lru (xd3_source *source, xoff_t blkno,
309 main_blklru_list_remove (blru); 312 main_blklru_list_remove (blru);
310 main_blklru_list_push_back (& lru_list, blru); 313 main_blklru_list_push_back (& lru_list, blru);
311 (*blrup) = blru; 314 (*blrup) = blru;
315 IF_DEBUG1 (DP(RINT "[getblk_lru] HIT blkno = %"Z"u lru_size=%d\n",
316 blkno, lru_size));
312 return 0; 317 return 0;
313 } 318 }
314 } 319 }
320 IF_DEBUG1 (DP(RINT "[getblk_lru] MISS blkno = %"Z"u lru_size=%d\n",
321 blkno, lru_size));
315 } 322 }
316 323
317 if (do_src_fifo) 324 if (do_src_fifo)
@@ -467,7 +474,6 @@ main_getblk_func (xd3_stream *stream,
467 main_file *sfile = (main_file*) source->ioh; 474 main_file *sfile = (main_file*) source->ioh;
468 main_blklru *blru; 475 main_blklru *blru;
469 int is_new; 476 int is_new;
470 int did_seek = 0;
471 size_t nread = 0; 477 size_t nread = 0;
472 478
473 if (allow_fake_source) 479 if (allow_fake_source)
@@ -504,20 +510,10 @@ main_getblk_func (xd3_stream *stream,
504 { 510 {
505 return ret; 511 return ret;
506 } 512 }
507
508 /* Indicates that another call to main_getblk_lru() may be
509 * needed */
510 did_seek = 1;
511 } 513 }
512 514
513 XD3_ASSERT (sfile->source_position == pos); 515 XD3_ASSERT (sfile->source_position == pos);
514 516
515 if (did_seek &&
516 (ret = main_getblk_lru (source, blkno, & blru, & is_new)))
517 {
518 return ret;
519 }
520
521 if ((ret = main_read_primary_input (sfile, 517 if ((ret = main_read_primary_input (sfile,
522 (uint8_t*) blru->blk, 518 (uint8_t*) blru->blk,
523 source->blksize, 519 source->blksize,
diff --git a/xdelta3/xdelta3-decode.h b/xdelta3/xdelta3-decode.h
index abe8c83..0cb8857 100644
--- a/xdelta3/xdelta3-decode.h
+++ b/xdelta3/xdelta3-decode.h
@@ -162,6 +162,9 @@ xd3_decode_allocate (xd3_stream *stream,
162 uint8_t **buf_ptr, 162 uint8_t **buf_ptr,
163 usize_t *buf_alloc) 163 usize_t *buf_alloc)
164{ 164{
165 IF_DEBUG2 (DP(RINT "[xd3_decode_allocate] size %u alloc %u\n",
166 size, *buf_alloc));
167
165 if (*buf_ptr != NULL && *buf_alloc < size) 168 if (*buf_ptr != NULL && *buf_alloc < size)
166 { 169 {
167 xd3_free (stream, *buf_ptr); 170 xd3_free (stream, *buf_ptr);
@@ -204,6 +207,8 @@ xd3_decode_section (xd3_stream *stream,
204 /* No allocation/copy needed */ 207 /* No allocation/copy needed */
205 section->buf = stream->next_in; 208 section->buf = stream->next_in;
206 sect_take = section->size; 209 sect_take = section->size;
210 IF_DEBUG1 (DP(RINT "[xd3_decode_section] zerocopy %u @ %u avail %u\n",
211 sect_take, section->pos, stream->avail_in));
207 } 212 }
208 else 213 else
209 { 214 {
@@ -227,6 +232,10 @@ xd3_decode_section (xd3_stream *stream,
227 section->buf = section->copied1; 232 section->buf = section->copied1;
228 } 233 }
229 234
235 IF_DEBUG2 (DP(RINT "[xd3_decode_section] take %u @ %u [need %u] avail %u\n",
236 sect_take, section->pos, sect_need, stream->avail_in));
237 XD3_ASSERT (section->pos + sect_take <= section->alloc1);
238
230 memcpy (section->copied1 + section->pos, 239 memcpy (section->copied1 + section->pos,
231 stream->next_in, 240 stream->next_in,
232 sect_take); 241 sect_take);
@@ -241,6 +250,7 @@ xd3_decode_section (xd3_stream *stream,
241 250
242 if (section->pos < section->size) 251 if (section->pos < section->size)
243 { 252 {
253 IF_DEBUG1 (DP(RINT "[xd3_decode_section] further input required %u\n", section->size - section->pos));
244 stream->msg = "further input required"; 254 stream->msg = "further input required";
245 return XD3_INPUT; 255 return XD3_INPUT;
246 } 256 }
@@ -1156,9 +1166,9 @@ xd3_decode_input (xd3_stream *stream)
1156 &src->cpyoff_blocks, 1166 &src->cpyoff_blocks,
1157 &src->cpyoff_blkoff); 1167 &src->cpyoff_blkoff);
1158 1168
1159 IF_DEBUG1(DP(RINT 1169 IF_DEBUG2(DP(RINT
1160 "decode cpyoff %"Q" " 1170 "[decode_cpyoff] %"Q"u "
1161 "cpyblkno %"Q" " 1171 "cpyblkno %"Q"u "
1162 "cpyblkoff %u " 1172 "cpyblkoff %u "
1163 "blksize %u\n", 1173 "blksize %u\n",
1164 stream->dec_cpyoff, 1174 stream->dec_cpyoff,
diff --git a/xdelta3/xdelta3-djw.h b/xdelta3/xdelta3-djw.h
index e6be032..414702a 100644
--- a/xdelta3/xdelta3-djw.h
+++ b/xdelta3/xdelta3-djw.h
@@ -1456,7 +1456,7 @@ djw_decode_symbol (xd3_stream *stream,
1456 if (*input == input_end) 1456 if (*input == input_end)
1457 { 1457 {
1458 stream->msg = "secondary decoder end of input"; 1458 stream->msg = "secondary decoder end of input";
1459 return XD3_INTERNAL; 1459 return XD3_INVALID_INPUT;
1460 } 1460 }
1461 1461
1462 bstate->cur_byte = *(*input)++; 1462 bstate->cur_byte = *(*input)++;
@@ -1479,7 +1479,7 @@ djw_decode_symbol (xd3_stream *stream,
1479 1479
1480 corrupt: 1480 corrupt:
1481 stream->msg = "secondary decoder invalid code"; 1481 stream->msg = "secondary decoder invalid code";
1482 return XD3_INTERNAL; 1482 return XD3_INVALID_INPUT;
1483} 1483}
1484 1484
1485static int 1485static int
@@ -1606,7 +1606,7 @@ djw_decode_1_2 (xd3_stream *stream,
1606 if (rep != 0) 1606 if (rep != 0)
1607 { 1607 {
1608 stream->msg = "secondary decoder invalid repeat code"; 1608 stream->msg = "secondary decoder invalid repeat code";
1609 return XD3_INTERNAL; 1609 return XD3_INVALID_INPUT;
1610 } 1610 }
1611 1611
1612 return 0; 1612 return 0;
@@ -1654,7 +1654,7 @@ xd3_decode_huff (xd3_stream *stream,
1654 if (output_bytes == 0) 1654 if (output_bytes == 0)
1655 { 1655 {
1656 stream->msg = "secondary decoder invalid input"; 1656 stream->msg = "secondary decoder invalid input";
1657 return XD3_INTERNAL; 1657 return XD3_INVALID_INPUT;
1658 } 1658 }
1659 1659
1660 /* Decode: number of groups */ 1660 /* Decode: number of groups */
@@ -1796,7 +1796,11 @@ xd3_decode_huff (xd3_stream *stream,
1796 gp_maxlen = maxlen[gp]; 1796 gp_maxlen = maxlen[gp];
1797 } 1797 }
1798 1798
1799 XD3_ASSERT (output_end - output > 0); 1799 if (output_end < output)
1800 {
1801 stream->msg = "secondary decoder invalid input";
1802 return XD3_INVALID_INPUT;
1803 }
1800 1804
1801 /* Decode next sector. */ 1805 /* Decode next sector. */
1802 n = xd3_min (sector_size, (usize_t) (output_end - output)); 1806 n = xd3_min (sector_size, (usize_t) (output_end - output));
diff --git a/xdelta3/xdelta3-internal.h b/xdelta3/xdelta3-internal.h
index 6482721..d54584d 100644
--- a/xdelta3/xdelta3-internal.h
+++ b/xdelta3/xdelta3-internal.h
@@ -335,6 +335,7 @@ xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num)
335 335
336#if SIZEOF_USIZE_T == 4 336#if SIZEOF_USIZE_T == 4
337#define USIZE_T_MAX UINT32_MAX 337#define USIZE_T_MAX UINT32_MAX
338#define USIZE_T_MAXBLKSZ 0x80000000U
338#define xd3_decode_size xd3_decode_uint32_t 339#define xd3_decode_size xd3_decode_uint32_t
339#define xd3_emit_size xd3_emit_uint32_t 340#define xd3_emit_size xd3_emit_uint32_t
340#define xd3_sizeof_size xd3_sizeof_uint32_t 341#define xd3_sizeof_size xd3_sizeof_uint32_t
@@ -342,9 +343,10 @@ xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num)
342#define xd3_large_cksum xd3_large32_cksum 343#define xd3_large_cksum xd3_large32_cksum
343#define xd3_large_cksum_update xd3_large32_cksum_update 344#define xd3_large_cksum_update xd3_large32_cksum_update
344#define xd3_hash_multiplier xd3_hash_multiplier32 345#define xd3_hash_multiplier xd3_hash_multiplier32
345#define XD3_MAXSRCWINSZ (1ULL << 31) 346#define XD3_MAXSRCWINSZ (1ULL << 31)
346#elif SIZEOF_USIZE_T == 8 347#elif SIZEOF_USIZE_T == 8
347#define USIZE_T_MAX UINT64_MAX 348#define USIZE_T_MAX UINT64_MAX
349#define USIZE_T_MAXBLKSZ 0x8000000000000000ULL
348#define xd3_decode_size xd3_decode_uint64_t 350#define xd3_decode_size xd3_decode_uint64_t
349#define xd3_emit_size xd3_emit_uint64_t 351#define xd3_emit_size xd3_emit_uint64_t
350#define xd3_sizeof_size xd3_sizeof_uint64_t 352#define xd3_sizeof_size xd3_sizeof_uint64_t
@@ -352,7 +354,7 @@ xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num)
352#define xd3_large_cksum xd3_large64_cksum 354#define xd3_large_cksum xd3_large64_cksum
353#define xd3_large_cksum_update xd3_large64_cksum_update 355#define xd3_large_cksum_update xd3_large64_cksum_update
354#define xd3_hash_multiplier xd3_hash_multiplier64 356#define xd3_hash_multiplier xd3_hash_multiplier64
355#define XD3_MAXSRCWINSZ (1ULL << 61) 357#define XD3_MAXSRCWINSZ (1ULL << 61)
356#endif /* SIZEOF_USIZE_T */ 358#endif /* SIZEOF_USIZE_T */
357 359
358#if SIZEOF_XOFF_T == 4 360#if SIZEOF_XOFF_T == 4
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h
index cfc952c..e43f6b3 100644
--- a/xdelta3/xdelta3-main.h
+++ b/xdelta3/xdelta3-main.h
@@ -870,6 +870,8 @@ main_file_open (main_file *xfile, const char* name, int mode)
870 return XD3_INVALID; 870 return XD3_INVALID;
871 } 871 }
872 872
873 IF_DEBUG1(DP(RINT "[main] open source %s\n", name));
874
873#if XD3_STDIO 875#if XD3_STDIO
874 xfile->file = fopen (name, XOPEN_STDIO); 876 xfile->file = fopen (name, XOPEN_STDIO);
875 877
@@ -1041,6 +1043,7 @@ main_file_read (main_file *ifile,
1041 const char *msg) 1043 const char *msg)
1042{ 1044{
1043 int ret = 0; 1045 int ret = 0;
1046 IF_DEBUG1(DP(RINT "[main] read %s up to %"Z"u\n", ifile->filename, size));
1044 1047
1045#if XD3_STDIO 1048#if XD3_STDIO
1046 size_t result; 1049 size_t result;
@@ -1081,6 +1084,8 @@ main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg)
1081{ 1084{
1082 int ret = 0; 1085 int ret = 0;
1083 1086
1087 IF_DEBUG1(DP(RINT "[main] write %u\n bytes", size));
1088
1084#if XD3_STDIO 1089#if XD3_STDIO
1085 usize_t result; 1090 usize_t result;
1086 1091
@@ -1150,6 +1155,8 @@ main_write_output (xd3_stream* stream, main_file *ofile)
1150{ 1155{
1151 int ret; 1156 int ret;
1152 1157
1158 IF_DEBUG1(DP(RINT "[main] write(%s) %u\n bytes", ofile->filename, stream->avail_out));
1159
1153 if (option_no_output) 1160 if (option_no_output)
1154 { 1161 {
1155 return 0; 1162 return 0;
@@ -3335,7 +3342,7 @@ main_input (xd3_cmd cmd,
3335 main_format_bcnt (stream.total_in, &trdb), 3342 main_format_bcnt (stream.total_in, &trdb),
3336 main_format_bcnt (stream.total_out, &twdb), 3343 main_format_bcnt (stream.total_out, &twdb),
3337 main_format_millis (millis, &tm), 3344 main_format_millis (millis, &tm),
3338 main_format_bcnt (sfile->source_position, &srcpos)); 3345 main_format_bcnt (stream.srcwin_cksum_pos, &srcpos));
3339 } 3346 }
3340 else 3347 else
3341 { 3348 {
diff --git a/xdelta3/xdelta3-merge.h b/xdelta3/xdelta3-merge.h
index 72bc892..a09f814 100644
--- a/xdelta3/xdelta3-merge.h
+++ b/xdelta3/xdelta3-merge.h
@@ -492,10 +492,15 @@ xd3_merge_source_copy (xd3_stream *stream,
492 } 492 }
493 else 493 else
494 { 494 {
495 // TODO: this is slow because of the recursion, which 495 // Note: A better implementation will construct the
496 // could reach a depth equal to the number of target 496 // mapping of output ranges, starting from the input
497 // copies, and this is compression-inefficient because 497 // range, applying deltas in forward order, using an
498 // it can produce duplicate adds. 498 // interval tree. This code uses recursion to construct
499 // each copied range, recursively (using binary search
500 // in xd3_merge_find_position).
501 //
502 // TODO: This code can cause stack overflow. Fix as
503 // described above.
499 xd3_winst tinst; 504 xd3_winst tinst;
500 tinst.type = XD3_CPY; 505 tinst.type = XD3_CPY;
501 tinst.mode = iinst.mode; 506 tinst.mode = iinst.mode;
@@ -555,12 +560,14 @@ int xd3_merge_inputs (xd3_stream *stream,
555 ret = xd3_merge_add (stream, input, iinst); 560 ret = xd3_merge_add (stream, input, iinst);
556 break; 561 break;
557 default: 562 default:
558 /* TODO: VCD_TARGET support is completely untested all 563 if (iinst->mode == 0)
559 * throughout. */
560 if (iinst->mode == 0 || iinst->mode == VCD_TARGET)
561 { 564 {
562 ret = xd3_merge_target_copy (stream, iinst); 565 ret = xd3_merge_target_copy (stream, iinst);
563 } 566 }
567 else if (iinst->mode == VCD_TARGET)
568 {
569 ret = XD3_INVALID_INPUT;
570 }
564 else 571 else
565 { 572 {
566 ret = xd3_merge_source_copy (stream, source, iinst); 573 ret = xd3_merge_source_copy (stream, source, iinst);
diff --git a/xdelta3/xdelta3-second.h b/xdelta3/xdelta3-second.h
index 309c947..899902e 100644
--- a/xdelta3/xdelta3-second.h
+++ b/xdelta3/xdelta3-second.h
@@ -298,9 +298,12 @@ xd3_encode_secondary (xd3_stream *stream,
298 298
299 if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS) || cfg->inefficient) 299 if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS) || cfg->inefficient)
300 { 300 {
301 IF_DEBUG1(DP(RINT "secondary saved %u bytes: %u -> %u (%0.2f%%)\n", 301 if (comp_size < orig_size)
302 orig_size - comp_size, orig_size, comp_size, 302 {
303 100.0 * (double) comp_size / (double) orig_size)); 303 IF_DEBUG1(DP(RINT "[encode_secondary] saved %u bytes: %u -> %u (%0.2f%%)\n",
304 orig_size - comp_size, orig_size, comp_size,
305 100.0 * (double) comp_size / (double) orig_size));
306 }
304 307
305 xd3_free_output (stream, *head); 308 xd3_free_output (stream, *head);
306 309
diff --git a/xdelta3/xdelta3-test.h b/xdelta3/xdelta3-test.h
index ddbfd65..335de28 100644
--- a/xdelta3/xdelta3-test.h
+++ b/xdelta3/xdelta3-test.h
@@ -3009,9 +3009,9 @@ int xd3_selftest (void)
3009#endif 3009#endif
3010 3010
3011 DO_TEST (recode_command, 0, 0); 3011 DO_TEST (recode_command, 0, 0);
3012 IF_LZMA (DO_TEST (secondary_lzma_default, 0, 0));
3012#endif 3013#endif
3013 3014
3014 IF_LZMA (DO_TEST (secondary_lzma_default, 0, 0));
3015 IF_LZMA (DO_TEST (secondary_lzma, 0, 1)); 3015 IF_LZMA (DO_TEST (secondary_lzma, 0, 1));
3016 IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS)); 3016 IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS));
3017 IF_FGK (DO_TEST (secondary_fgk, 0, 1)); 3017 IF_FGK (DO_TEST (secondary_fgk, 0, 1));
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c
index d95d97d..9253d68 100644
--- a/xdelta3/xdelta3.c
+++ b/xdelta3/xdelta3.c
@@ -519,7 +519,7 @@ static void xd3_verify_large_state (xd3_stream *stream,
519 usize_t x_cksum); 519 usize_t x_cksum);
520static void xd3_verify_small_state (xd3_stream *stream, 520static void xd3_verify_small_state (xd3_stream *stream,
521 const uint8_t *inp, 521 const uint8_t *inp,
522 uint32_t x_cksum); 522 uint32_t x_cksum);
523 523
524#endif /* XD3_DEBUG */ 524#endif /* XD3_DEBUG */
525#endif /* XD3_ENCODER */ 525#endif /* XD3_ENCODER */
@@ -1067,7 +1067,17 @@ xd3_round_blksize (usize_t sz, usize_t blksz)
1067 1067
1068 XD3_ASSERT (xd3_check_pow2 (blksz, NULL) == 0); 1068 XD3_ASSERT (xd3_check_pow2 (blksz, NULL) == 0);
1069 1069
1070 return mod ? (sz + (blksz - mod)) : sz; 1070 if (mod == 0)
1071 {
1072 return sz;
1073 }
1074
1075 if (sz > USIZE_T_MAXBLKSZ)
1076 {
1077 return USIZE_T_MAXBLKSZ;
1078 }
1079
1080 return sz + (blksz - mod);
1071} 1081}
1072 1082
1073/*********************************************************************** 1083/***********************************************************************
@@ -1848,7 +1858,7 @@ xd3_config_stream(xd3_stream *stream,
1848inline 1858inline
1849xoff_t xd3_source_eof(const xd3_source *src) 1859xoff_t xd3_source_eof(const xd3_source *src)
1850{ 1860{
1851 xoff_t r = (src->blksize * src->max_blkno) + src->onlastblk; 1861 xoff_t r = (src->max_blkno << src->shiftby) + (xoff_t)src->onlastblk;
1852 return r; 1862 return r;
1853} 1863}
1854 1864
@@ -1862,7 +1872,7 @@ usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno)
1862} 1872}
1863 1873
1864/* This function interfaces with the client getblk function, checks 1874/* This function interfaces with the client getblk function, checks
1865 * its results, updates frontier_blkno, max_blkno, onlastblk, eof_known. */ 1875 * its results, updates max_blkno, onlastblk, eof_known. */
1866static int 1876static int
1867xd3_getblk (xd3_stream *stream, xoff_t blkno) 1877xd3_getblk (xd3_stream *stream, xoff_t blkno)
1868{ 1878{
@@ -1875,6 +1885,7 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno)
1875 1885
1876 if (stream->getblk == NULL) 1886 if (stream->getblk == NULL)
1877 { 1887 {
1888 IF_DEBUG2 (DP(RINT "[getblk] XD3_GETSRCBLK %"Q"u\n", blkno));
1878 stream->msg = "getblk source input"; 1889 stream->msg = "getblk source input";
1879 return XD3_GETSRCBLK; 1890 return XD3_GETSRCBLK;
1880 } 1891 }
@@ -1882,48 +1893,34 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno)
1882 ret = stream->getblk (stream, source, blkno); 1893 ret = stream->getblk (stream, source, blkno);
1883 if (ret != 0) 1894 if (ret != 0)
1884 { 1895 {
1885 IF_DEBUG1 (DP(RINT "[getblk] app error blkno %"Q": %s\n", 1896 IF_DEBUG2 (DP(RINT "[getblk] app error blkno %"Q"u: %s\n",
1886 blkno, xd3_strerror (ret))); 1897 blkno, xd3_strerror (ret)));
1887 return ret; 1898 return ret;
1888 } 1899 }
1889 IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q" onblk " 1900
1890 "%u blksize %u\n", blkno, source->onblk, source->blksize)); 1901 IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q"u onblk "
1902 "%u blksize %u max_blkno %"Q"u\n", blkno, source->onblk,
1903 source->blksize, source->max_blkno));
1891 } 1904 }
1892 1905
1893 if (blkno >= source->frontier_blkno) 1906 if (blkno > source->max_blkno)
1894 { 1907 {
1895 if (blkno > source->max_blkno) 1908 source->max_blkno = blkno;
1896 {
1897 source->max_blkno = blkno;
1898 source->onlastblk = source->onblk;
1899 }
1900 1909
1901 if (source->onblk == source->blksize) 1910 if (source->onblk == source->blksize)
1902 { 1911 {
1903 source->frontier_blkno = blkno + 1; 1912 IF_DEBUG1 (DP(RINT "[getblk] full source blkno %"Q"u: "
1904 1913 "source length unknown %"Q"u\n",
1905 IF_DEBUG2 (DP(RINT "[getblk] full source blkno %"Q": "
1906 "source length unknown %"Q"\n",
1907 blkno, 1914 blkno,
1908 xd3_source_eof (source))); 1915 xd3_source_eof (source)));
1909 } 1916 }
1910 else 1917 else if (!source->eof_known)
1911 { 1918 {
1912 source->frontier_blkno = blkno; 1919 IF_DEBUG1 (DP(RINT "[getblk] eof block has %d bytes; "
1913 1920 "source length known %"Q"u\n",
1914 if (xd3_bytes_on_srcblk (source, blkno) != 0) 1921 xd3_bytes_on_srcblk (source, blkno),
1915 { 1922 xd3_source_eof (source)));
1916 source->frontier_blkno += 1; 1923 source->eof_known = 1;
1917 }
1918
1919 if (!source->eof_known)
1920 {
1921 IF_DEBUG2 (DP(RINT "[getblk] eof block has %d bytes; "
1922 "source length known %"Q"\n",
1923 xd3_bytes_on_srcblk (source, blkno),
1924 xd3_source_eof (source)));
1925 source->eof_known = 1;
1926 }
1927 } 1924 }
1928 } 1925 }
1929 1926
@@ -1932,13 +1929,8 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno)
1932 if (blkno == source->max_blkno) 1929 if (blkno == source->max_blkno)
1933 { 1930 {
1934 /* In case the application sets the source as 1 block w/ a 1931 /* In case the application sets the source as 1 block w/ a
1935 preset buffer. */ 1932 * preset buffer. */
1936 source->onlastblk = source->onblk; 1933 source->onlastblk = source->onblk;
1937
1938 if (source->onblk == source->blksize)
1939 {
1940 source->frontier_blkno = blkno + 1;
1941 }
1942 } 1934 }
1943 return 0; 1935 return 0;
1944} 1936}
@@ -1975,7 +1967,6 @@ xd3_set_source (xd3_stream *stream,
1975 IF_DEBUG1 (DP(RINT "raising src_maxsize to %u\n", src->blksize)); 1967 IF_DEBUG1 (DP(RINT "raising src_maxsize to %u\n", src->blksize));
1976 } 1968 }
1977 src->max_winsize = xd3_max (src->max_winsize, XD3_ALLOCSIZE); 1969 src->max_winsize = xd3_max (src->max_winsize, XD3_ALLOCSIZE);
1978
1979 return 0; 1970 return 0;
1980} 1971}
1981 1972
@@ -1989,11 +1980,13 @@ xd3_set_source_and_size (xd3_stream *stream,
1989 stream->src->eof_known = 1; 1980 stream->src->eof_known = 1;
1990 IF_DEBUG2 (DP(RINT "[set source] size known %"Q"\n", 1981 IF_DEBUG2 (DP(RINT "[set source] size known %"Q"\n",
1991 source_size)); 1982 source_size));
1992
1993 xd3_blksize_div(source_size, 1983 xd3_blksize_div(source_size,
1994 stream->src, 1984 stream->src,
1995 &stream->src->max_blkno, 1985 &stream->src->max_blkno,
1996 &stream->src->onlastblk); 1986 &stream->src->onlastblk);
1987
1988 IF_DEBUG1 (DP(RINT "[set source] size known %"Q"u max_blkno %"Q"u\n",
1989 source_size, stream->src->max_blkno));
1997 } 1990 }
1998 return ret; 1991 return ret;
1999} 1992}
@@ -2047,8 +2040,8 @@ xd3_close_stream (xd3_stream *stream)
2047 break; 2040 break;
2048 default: 2041 default:
2049 /* If decoding, should be ready for the next window. */ 2042 /* If decoding, should be ready for the next window. */
2050 stream->msg = "EOF in decode"; 2043 stream->msg = "eof in decode";
2051 return XD3_INTERNAL; 2044 return XD3_INVALID_INPUT;
2052 } 2045 }
2053 } 2046 }
2054 2047
@@ -2207,8 +2200,6 @@ xd3_iopt_finish_encoding (xd3_stream *stream, xd3_rinst *inst)
2207 } 2200 }
2208 case XD3_RUN: 2201 case XD3_RUN:
2209 { 2202 {
2210 XD3_ASSERT (inst->size >= MIN_MATCH);
2211
2212 if ((ret = xd3_emit_byte (stream, & DATA_TAIL (stream), inst->xtra))) { return ret; } 2203 if ((ret = xd3_emit_byte (stream, & DATA_TAIL (stream), inst->xtra))) { return ret; }
2213 2204
2214 stream->n_run += 1; 2205 stream->n_run += 1;
@@ -3194,6 +3185,7 @@ xd3_encode_input (xd3_stream *stream)
3194 * or else it can get stuck in a match-backward 3185 * or else it can get stuck in a match-backward
3195 * (getsrcblk) then match-forward (getsrcblk), 3186 * (getsrcblk) then match-forward (getsrcblk),
3196 * find insufficient match length, then repeat 3187 * find insufficient match length, then repeat
3188
3197 * exactly the same search. 3189 * exactly the same search.
3198 */ 3190 */
3199 stream->input_position += stream->match_fwd; 3191 stream->input_position += stream->match_fwd;
@@ -3219,7 +3211,7 @@ xd3_encode_input (xd3_stream *stream)
3219 3211
3220 case ENC_INSTR: 3212 case ENC_INSTR:
3221 /* Note: Jump here to encode VCDIFF deltas w/o using this 3213 /* Note: Jump here to encode VCDIFF deltas w/o using this
3222 * string-matching code. Merging code code enters here. */ 3214 * string-matching code. Merging code enters here. */
3223 3215
3224 /* Flush the instrution buffer, then possibly add one more 3216 /* Flush the instrution buffer, then possibly add one more
3225 * instruction, then emit the header. */ 3217 * instruction, then emit the header. */
@@ -3674,7 +3666,7 @@ xd3_srcwin_setup (xd3_stream *stream)
3674 /* Otherwise, we have to make a guess. More copies may still be 3666 /* Otherwise, we have to make a guess. More copies may still be
3675 * issued, but we have to decide the source window base and length 3667 * issued, but we have to decide the source window base and length
3676 * now. 3668 * now.
3677 * TODO: This >> 2 is arbitrary--try other values. */ 3669 * TODO: This may not working well in practice, more testing needed. */
3678 src->srcbase = stream->match_minaddr; 3670 src->srcbase = stream->match_minaddr;
3679 src->srclen = xd3_max ((usize_t) length, 3671 src->srclen = xd3_max ((usize_t) length,
3680 stream->avail_in + (stream->avail_in >> 2)); 3672 stream->avail_in + (stream->avail_in >> 2));
@@ -3707,9 +3699,8 @@ xd3_srcwin_setup (xd3_stream *stream)
3707static int 3699static int
3708xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) 3700xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
3709{ 3701{
3710 xd3_source *src = stream->src; 3702 xd3_source *const src = stream->src;
3711 usize_t greedy_or_not; 3703 usize_t greedy_or_not;
3712 xoff_t frontier_pos;
3713 3704
3714 stream->match_maxback = 0; 3705 stream->match_maxback = 0;
3715 stream->match_maxfwd = 0; 3706 stream->match_maxfwd = 0;
@@ -3733,18 +3724,24 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
3733 /* Implement src->max_winsize, which prevents the encoder from seeking 3724 /* Implement src->max_winsize, which prevents the encoder from seeking
3734 * back further than the LRU cache maintaining FIFO discipline, (to 3725 * back further than the LRU cache maintaining FIFO discipline, (to
3735 * avoid seeking). */ 3726 * avoid seeking). */
3736 frontier_pos = stream->src->frontier_blkno * stream->src->blksize; 3727 if (srcpos < stream->srcwin_cksum_pos &&
3737 IF_DEBUG2(DP(RINT "[match_setup] frontier_pos %"Q", srcpos %"Q", " 3728 stream->srcwin_cksum_pos - srcpos > src->max_winsize)
3738 "src->max_winsize %"Q"\n", 3729 {
3739 frontier_pos, srcpos, stream->src->max_winsize)); 3730 IF_DEBUG2(DP(RINT "[match_setup] rejected due to src->max_winsize "
3740 if (srcpos < frontier_pos && 3731 "distance eof=%"Q"u srcpos=%"Q"u max_winsz=%"Q"u\n",
3741 frontier_pos - srcpos > stream->src->max_winsize) { 3732 xd3_source_eof (src),
3742 IF_DEBUG1(DP(RINT "[match_setup] rejected due to src->max_winsize " 3733 srcpos, src->max_winsize));
3743 "distance eof=%"Q" srcpos=%"Q" maxsz=%"Q"\n", 3734 goto bad;
3744 xd3_source_eof (stream->src), 3735 }
3745 srcpos, stream->src->max_winsize)); 3736
3746 goto bad; 3737 /* There are cases where the above test does not reject a match that
3747 } 3738 * will experience XD3_TOOFARBACK at the first xd3_getblk call
3739 * because the input may have advanced up to one block beyond the
3740 * actual EOF. */
3741 IF_DEBUG2(DP(RINT "[match_setup] %"Q"u srcpos %"Q"u, "
3742 "src->max_winsize %"Q"u\n",
3743 stream->total_in + stream->input_position,
3744 srcpos, src->max_winsize));
3748 3745
3749 /* Going backwards, the 1.5-pass algorithm allows some 3746 /* Going backwards, the 1.5-pass algorithm allows some
3750 * already-matched input may be covered by a longer source match. 3747 * already-matched input may be covered by a longer source match.
@@ -3788,9 +3785,9 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
3788 stream->match_maxback = (usize_t) srcpos; 3785 stream->match_maxback = (usize_t) srcpos;
3789 } 3786 }
3790 3787
3791 if (stream->src->eof_known) 3788 if (src->eof_known)
3792 { 3789 {
3793 xoff_t srcavail = xd3_source_eof (stream->src) - srcpos; 3790 xoff_t srcavail = xd3_source_eof (src) - srcpos;
3794 3791
3795 if (srcavail < stream->match_maxfwd) 3792 if (srcavail < stream->match_maxfwd)
3796 { 3793 {
@@ -3834,8 +3831,8 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
3834 stream->match_maxfwd = srcavail; 3831 stream->match_maxfwd = srcavail;
3835 } 3832 }
3836 3833
3837 IF_DEBUG1(DP(RINT 3834 IF_DEBUG2(DP(RINT
3838 "[match_setup] srcpos %"Q" (tgtpos %"Q") " 3835 "[match_setup] srcpos %"Q"u (tgtpos %"Q"u) "
3839 "restricted maxback %u maxfwd %u\n", 3836 "restricted maxback %u maxfwd %u\n",
3840 srcpos, 3837 srcpos,
3841 stream->total_in + stream->input_position, 3838 stream->total_in + stream->input_position,
@@ -3852,6 +3849,7 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
3852 3849
3853 bad: 3850 bad:
3854 stream->match_state = MATCH_SEARCHING; 3851 stream->match_state = MATCH_SEARCHING;
3852 stream->match_last_srcpos = srcpos;
3855 return 1; 3853 return 1;
3856} 3854}
3857 3855
@@ -3903,7 +3901,7 @@ static int
3903xd3_source_extend_match (xd3_stream *stream) 3901xd3_source_extend_match (xd3_stream *stream)
3904{ 3902{
3905 int ret; 3903 int ret;
3906 xd3_source *src = stream->src; 3904 xd3_source *const src = stream->src;
3907 xoff_t matchoff; /* matchoff is the current right/left-boundary of 3905 xoff_t matchoff; /* matchoff is the current right/left-boundary of
3908 the source match being tested. */ 3906 the source match being tested. */
3909 usize_t streamoff; /* streamoff is the current right/left-boundary 3907 usize_t streamoff; /* streamoff is the current right/left-boundary
@@ -3923,7 +3921,7 @@ xd3_source_extend_match (xd3_stream *stream)
3923 if (stream->match_state == MATCH_BACKWARD) 3921 if (stream->match_state == MATCH_BACKWARD)
3924 { 3922 {
3925 /* Note: this code is practically duplicated below, substituting 3923 /* Note: this code is practically duplicated below, substituting
3926 * match_fwd/match_back and direction. TODO: Consolidate? */ 3924 * match_fwd/match_back and direction. */
3927 matchoff = stream->match_srcpos - stream->match_back; 3925 matchoff = stream->match_srcpos - stream->match_back;
3928 streamoff = stream->input_position - stream->match_back; 3926 streamoff = stream->input_position - stream->match_back;
3929 xd3_blksize_div (matchoff, src, &tryblk, &tryoff); 3927 xd3_blksize_div (matchoff, src, &tryblk, &tryoff);
@@ -3940,10 +3938,22 @@ xd3_source_extend_match (xd3_stream *stream)
3940 3938
3941 if ((ret = xd3_getblk (stream, tryblk))) 3939 if ((ret = xd3_getblk (stream, tryblk)))
3942 { 3940 {
3943 /* if search went too far back, continue forward. */
3944 if (ret == XD3_TOOFARBACK) 3941 if (ret == XD3_TOOFARBACK)
3945 { 3942 {
3946 break; 3943 IF_DEBUG2(DP(RINT "[maxback] %"Q"u TOOFARBACK: %u INP %"Q"u CKSUM %"Q"u\n",
3944 tryblk, stream->match_back,
3945 stream->total_in + stream->input_position,
3946 stream->srcwin_cksum_pos));
3947
3948 /* the starting position is too far back. */
3949 if (stream->match_back == 0)
3950 {
3951 XD3_ASSERT(stream->match_fwd == 0);
3952 goto donefwd;
3953 }
3954
3955 /* search went too far back, continue forward. */
3956 goto doneback;
3947 } 3957 }
3948 3958
3949 /* could be a XD3_GETSRCBLK failure. */ 3959 /* could be a XD3_GETSRCBLK failure. */
@@ -3989,7 +3999,14 @@ xd3_source_extend_match (xd3_stream *stream)
3989 3999
3990 if ((ret = xd3_getblk (stream, tryblk))) 4000 if ((ret = xd3_getblk (stream, tryblk)))
3991 { 4001 {
3992 XD3_ASSERT (ret != XD3_TOOFARBACK); 4002 if (ret == XD3_TOOFARBACK)
4003 {
4004 IF_DEBUG2(DP(RINT "[maxfwd] %"Q"u TOOFARBACK: %u INP %"Q"u CKSUM %"Q"u\n",
4005 tryblk, stream->match_fwd,
4006 stream->total_in + stream->input_position,
4007 stream->srcwin_cksum_pos));
4008 goto donefwd;
4009 }
3993 4010
3994 /* could be a XD3_GETSRCBLK failure. */ 4011 /* could be a XD3_GETSRCBLK failure. */
3995 return ret; 4012 return ret;
@@ -4020,8 +4037,14 @@ xd3_source_extend_match (xd3_stream *stream)
4020 } 4037 }
4021 } 4038 }
4022 4039
4040 donefwd:
4023 stream->match_state = MATCH_SEARCHING; 4041 stream->match_state = MATCH_SEARCHING;
4024 4042
4043 IF_DEBUG2(DP(RINT "[extend match] input %"Q"u srcpos %"Q"u len %u\n",
4044 stream->input_position + stream->total_in,
4045 stream->match_srcpos,
4046 stream->match_fwd));
4047
4025 /* If the match ends short of the last instruction end, we probably 4048 /* If the match ends short of the last instruction end, we probably
4026 * don't want it. There is the possibility that a copy ends short 4049 * don't want it. There is the possibility that a copy ends short
4027 * of the last copy but also goes further back, in which case we 4050 * of the last copy but also goes further back, in which case we
@@ -4073,8 +4096,9 @@ xd3_source_extend_match (xd3_stream *stream)
4073 4096
4074 IF_DEBUG2 ({ 4097 IF_DEBUG2 ({
4075 static int x = 0; 4098 static int x = 0;
4076 DP(RINT "[source match:%d] <inp %"Q" %"Q"> <src %"Q" %"Q"> (%s) [ %u bytes ]\n", 4099 DP(RINT "[source match:%d] length %u <inp %"Q"u %"Q"u> <src %"Q"u %"Q"u> (%s) [ %u bytes ]\n",
4077 x++, 4100 x++,
4101 match_length,
4078 stream->total_in + target_position, 4102 stream->total_in + target_position,
4079 stream->total_in + target_position + match_length, 4103 stream->total_in + target_position + match_length,
4080 match_position, 4104 match_position,
@@ -4315,17 +4339,18 @@ xd3_verify_run_state (xd3_stream *stream,
4315 * stream->input_position reaches the value returned as 4339 * stream->input_position reaches the value returned as
4316 * *next_move_point. NB: this is one of the most expensive functions 4340 * *next_move_point. NB: this is one of the most expensive functions
4317 * in this code and also the most critical for good compression. 4341 * in this code and also the most critical for good compression.
4318 * TODO: optimize the inner loop
4319 */ 4342 */
4320static int 4343static int
4321xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) 4344xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4322{ 4345{
4323 xoff_t logical_input_cksum_pos; 4346 /* the source file is indexed until this point */
4324 xoff_t source_size; 4347 xoff_t target_cksum_pos;
4348 /* the absolute target file input position */
4349 xoff_t absolute_input_pos;
4325 4350
4326 if (stream->src->eof_known) 4351 if (stream->src->eof_known)
4327 { 4352 {
4328 source_size = xd3_source_eof (stream->src); 4353 xoff_t source_size = xd3_source_eof (stream->src);
4329 XD3_ASSERT(stream->srcwin_cksum_pos <= source_size); 4354 XD3_ASSERT(stream->srcwin_cksum_pos <= source_size);
4330 4355
4331 if (stream->srcwin_cksum_pos == source_size) 4356 if (stream->srcwin_cksum_pos == source_size)
@@ -4335,19 +4360,31 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4335 } 4360 }
4336 } 4361 }
4337 4362
4338 /* Begin by advancing at twice the input rate, up to half the 4363 absolute_input_pos = stream->total_in + stream->input_position;
4339 * maximum window size. */
4340 logical_input_cksum_pos = xd3_min((stream->total_in + stream->input_position) * 2,
4341 (stream->total_in + stream->input_position) +
4342 (stream->src->max_winsize / 2));
4343 4364
4344 /* If srcwin_cksum_pos is already greater, wait until the difference 4365 /* Immediately read the entire window.
4345 * is met. */ 4366 *
4346 if (stream->srcwin_cksum_pos > logical_input_cksum_pos) 4367 * Note: this reverses a long held policy, at this point in the
4368 * code, of advancing relatively slowly as the input is read, which
4369 * results in better compression for very-similar inputs, but worse
4370 * compression where data is deleted near the beginning of the file.
4371 *
4372 * The new policy is simpler, somewhat slower and can benefit, or
4373 * slightly worsen, compression performance. */
4374 if (absolute_input_pos < stream->src->max_winsize / 2)
4347 { 4375 {
4348 *next_move_point = stream->input_position + 4376 target_cksum_pos = stream->src->max_winsize;
4349 (usize_t)(stream->srcwin_cksum_pos - logical_input_cksum_pos); 4377 }
4350 return 0; 4378 else
4379 {
4380 /* TODO: The addition of 2 blocks here is arbitrary. Do a
4381 * better job of stream alignment based on observed source copy
4382 * addresses, and when both input sizes are known, the
4383 * difference in size. */
4384 target_cksum_pos = absolute_input_pos +
4385 stream->src->max_winsize / 2 +
4386 stream->src->blksize * 2;
4387 target_cksum_pos &= ~stream->src->maskby;
4351 } 4388 }
4352 4389
4353 /* A long match may have extended past srcwin_cksum_pos. Don't 4390 /* A long match may have extended past srcwin_cksum_pos. Don't
@@ -4357,27 +4394,12 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4357 stream->srcwin_cksum_pos = stream->maxsrcaddr; 4394 stream->srcwin_cksum_pos = stream->maxsrcaddr;
4358 } 4395 }
4359 4396
4360 if (logical_input_cksum_pos < stream->srcwin_cksum_pos) 4397 if (target_cksum_pos < stream->srcwin_cksum_pos)
4361 { 4398 {
4362 logical_input_cksum_pos = stream->srcwin_cksum_pos; 4399 target_cksum_pos = stream->srcwin_cksum_pos;
4363 } 4400 }
4364 4401
4365 /* Advance at least one source block. With the command-line 4402 while (stream->srcwin_cksum_pos < target_cksum_pos &&
4366 * defaults this means:
4367 *
4368 * if (src->size <= src->max_winsize), index the entire source at once
4369 * using the position of the first non-match. This is good for
4370 * small inputs, especially when the content may have moved anywhere
4371 * in the file (e.g., tar files).
4372 *
4373 * if (src->size > src->max_winsize), index at least one block ahead
4374 * of the logical position. This is good for different reasons:
4375 * when a long match spanning several source blocks is encountered,
4376 * this avoids computing checksums for those blocks.
4377 */
4378 logical_input_cksum_pos += stream->src->blksize;
4379
4380 while (stream->srcwin_cksum_pos < logical_input_cksum_pos &&
4381 (!stream->src->eof_known || 4403 (!stream->src->eof_known ||
4382 stream->srcwin_cksum_pos < xd3_source_eof (stream->src))) 4404 stream->srcwin_cksum_pos < xd3_source_eof (stream->src)))
4383 { 4405 {
@@ -4399,17 +4421,19 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4399 { 4421 {
4400 ret = XD3_INTERNAL; 4422 ret = XD3_INTERNAL;
4401 } 4423 }
4424
4402 IF_DEBUG1 (DP(RINT 4425 IF_DEBUG1 (DP(RINT
4403 "[srcwin_move_point] async getblk return for %"Q"\n", 4426 "[srcwin_move_point] async getblk return for %"Q"u: %s\n",
4404 blkno)); 4427 blkno, xd3_strerror (ret)));
4405 return ret; 4428 return ret;
4406 } 4429 }
4407 4430
4408 IF_DEBUG1 (DP(RINT 4431 IF_DEBUG1 (DP(RINT
4409 "[srcwin_move_point] T=%"Q"{%"Q"} S=%"Q" EOF=%"Q" %s\n", 4432 "[srcwin_move_point] block %"Q"u T=%"Q"u S=%"Q"u L=%"Q"u EOF=%"Q"u %s\n",
4433 blkno,
4410 stream->total_in + stream->input_position, 4434 stream->total_in + stream->input_position,
4411 logical_input_cksum_pos,
4412 stream->srcwin_cksum_pos, 4435 stream->srcwin_cksum_pos,
4436 target_cksum_pos,
4413 xd3_source_eof (stream->src), 4437 xd3_source_eof (stream->src),
4414 stream->src->eof_known ? "known" : "unknown")); 4438 stream->src->eof_known ? "known" : "unknown"));
4415 4439
@@ -4418,7 +4442,7 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4418 if (blkpos < (ssize_t) stream->smatcher.large_look) 4442 if (blkpos < (ssize_t) stream->smatcher.large_look)
4419 { 4443 {
4420 stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; 4444 stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize;
4421 IF_DEBUG1 (DP(RINT "[srcwin_move_point] continue (end-of-block)\n")); 4445 IF_DEBUG2 (DP(RINT "[srcwin_move_point] continue (end-of-block): %"Q"u\n", blkpos));
4422 continue; 4446 continue;
4423 } 4447 }
4424 4448
@@ -4468,8 +4492,7 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4468 4492
4469 if (stream->src->eof_known) 4493 if (stream->src->eof_known)
4470 { 4494 {
4471 source_size = xd3_source_eof (stream->src); 4495 xoff_t source_size = xd3_source_eof (stream->src);
4472
4473 if (stream->srcwin_cksum_pos >= source_size) 4496 if (stream->srcwin_cksum_pos >= source_size)
4474 { 4497 {
4475 /* This invariant is needed for xd3_source_cksum_offset() */ 4498 /* This invariant is needed for xd3_source_cksum_offset() */
@@ -4482,9 +4505,22 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4482 } 4505 }
4483 4506
4484 /* How long until this function should be called again. */ 4507 /* How long until this function should be called again. */
4485 XD3_ASSERT(stream->srcwin_cksum_pos >= logical_input_cksum_pos); 4508 XD3_ASSERT(stream->srcwin_cksum_pos >= target_cksum_pos);
4486 *next_move_point = stream->input_position + 1 + 4509
4487 (usize_t)(stream->srcwin_cksum_pos - logical_input_cksum_pos); 4510 *next_move_point = stream->input_position +
4511 stream->src->blksize -
4512 ((stream->srcwin_cksum_pos - target_cksum_pos) & stream->src->maskby);
4513
4514 IF_DEBUG2 (DP(RINT
4515 "[srcwin_move_point] finished T=%"Q"u "
4516 "S=%"Q"u L=%"Q"u EOF=%"Q"u %s again in %u\n",
4517 stream->total_in + stream->input_position,
4518 stream->srcwin_cksum_pos,
4519 target_cksum_pos,
4520 xd3_source_eof (stream->src),
4521 stream->src->eof_known ? "known" : "unknown",
4522 *next_move_point - stream->input_position));
4523
4488 return 0; 4524 return 0;
4489} 4525}
4490 4526
@@ -4543,6 +4579,8 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream)
4543 usize_t match_offset = 0; 4579 usize_t match_offset = 0;
4544 usize_t next_move_point; 4580 usize_t next_move_point;
4545 4581
4582 IF_DEBUG2(DP(RINT "[string_match] initial entry %u\n", stream->input_position));
4583
4546 /* If there will be no compression due to settings or short input, 4584 /* If there will be no compression due to settings or short input,
4547 * skip it entirely. */ 4585 * skip it entirely. */
4548 if (! (DO_SMALL || DO_LARGE || DO_RUN) || 4586 if (! (DO_SMALL || DO_LARGE || DO_RUN) ||
@@ -4554,6 +4592,8 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream)
4554 * needs to be reset. */ 4592 * needs to be reset. */
4555 restartloop: 4593 restartloop:
4556 4594
4595 IF_DEBUG2(DP(RINT "[string_match] restartloop %u\n", stream->input_position));
4596
4557 /* If there is not enough input remaining for any kind of match, 4597 /* If there is not enough input remaining for any kind of match,
4558 skip it. */ 4598 skip it. */
4559 if (stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; } 4599 if (stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; }
@@ -4597,7 +4637,9 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream)
4597 { 4637 {
4598 /* Source window: next_move_point is the point that 4638 /* Source window: next_move_point is the point that
4599 * stream->input_position must reach before computing more 4639 * stream->input_position must reach before computing more
4600 * source checksum. */ 4640 * source checksum. Note: this is called unconditionally
4641 * the first time after reentry, subsequent calls will be
4642 * avoided if next_move_point is > input_position */
4601 if ((ret = xd3_srcwin_move_point (stream, & next_move_point))) 4643 if ((ret = xd3_srcwin_move_point (stream, & next_move_point)))
4602 { 4644 {
4603 return ret; 4645 return ret;
diff --git a/xdelta3/xdelta3.h b/xdelta3/xdelta3.h
index 63b76b0..f00f887 100644
--- a/xdelta3/xdelta3.h
+++ b/xdelta3/xdelta3.h
@@ -833,10 +833,6 @@ struct _xd3_source
833 xoff_t max_blkno; /* Maximum block, if eof is known, 833 xoff_t max_blkno; /* Maximum block, if eof is known,
834 * otherwise, equals frontier_blkno 834 * otherwise, equals frontier_blkno
835 * (initially 0). */ 835 * (initially 0). */
836 xoff_t frontier_blkno; /* If eof is unknown, the next
837 * source position to be read.
838 * Otherwise, equal to
839 * max_blkno. */
840 usize_t onlastblk; /* Number of bytes on max_blkno */ 836 usize_t onlastblk; /* Number of bytes on max_blkno */
841 int eof_known; /* Set to true when the first 837 int eof_known; /* Set to true when the first
842 * partial block is read. */ 838 * partial block is read. */