summaryrefslogtreecommitdiff
path: root/xdelta3
diff options
context:
space:
mode:
authorjosh.macdonald <jmacd@users.noreply.github.com>2010-02-07 03:00:42 +0000
committerjosh.macdonald <jmacd@users.noreply.github.com>2010-02-07 03:00:42 +0000
commit3dbebbe46096e17c0298f1cbe315d10b35b4f9ee (patch)
treec2ae665c490d2a4e4cd4365721f4cf807fa1e44b /xdelta3
parente7a0eda2519593950a1a0dff77e42d4da9189c3e (diff)
Implement srcwin_maxsz in xd3_source_match_setup(), which prevents
the encoder from seeking backwards further than this parameter. This was supposed to be implemented long ago, but was especially problematic in the recent release, which implements source-from-FIFO.
Diffstat (limited to 'xdelta3')
-rwxr-xr-xxdelta3/testing/Makefile5
-rw-r--r--xdelta3/testing/file.h28
-rw-r--r--xdelta3/testing/modify.h107
-rw-r--r--xdelta3/testing/regtest.cc128
-rw-r--r--xdelta3/testing/segment.h10
-rw-r--r--xdelta3/xdelta3-main.h111
-rw-r--r--xdelta3/xdelta3.c164
-rw-r--r--xdelta3/xdelta3.h20
8 files changed, 346 insertions, 227 deletions
diff --git a/xdelta3/testing/Makefile b/xdelta3/testing/Makefile
index 2cfeee3..c1621f2 100755
--- a/xdelta3/testing/Makefile
+++ b/xdelta3/testing/Makefile
@@ -1,11 +1,10 @@
1CFLAGS = -O2 -Wall -Wconversion -Wsign-compare -Wextra -Wno-unused-parameter -I.. \ 1CFLAGS = -g -Wall -Wconversion -Wsign-compare -Wextra \
2 -Wno-unused-parameter -I.. \
2 -DGENERIC_ENCODE_TABLES=1 \ 3 -DGENERIC_ENCODE_TABLES=1 \
3 -DSECONDARY_DJW=1 \ 4 -DSECONDARY_DJW=1 \
4 -DSECONDARY_FGK=1 \ 5 -DSECONDARY_FGK=1 \
5 -DXD3_USE_LARGEFILE64=1 6 -DXD3_USE_LARGEFILE64=1
6 7
7#CFLAGS = -O2 -Wall -I.. -DXD3_DEBUG=1 -DNDEBUG=1
8
9DEPS = ../*.h ../*.c *.cc *.h 8DEPS = ../*.h ../*.c *.cc *.h
10 9
11TARGETS = xdelta3-regtest xdelta3-regtest2 10TARGETS = xdelta3-regtest xdelta3-regtest2
diff --git a/xdelta3/testing/file.h b/xdelta3/testing/file.h
index 9bfbf4c..b46717f 100644
--- a/xdelta3/testing/file.h
+++ b/xdelta3/testing/file.h
@@ -7,7 +7,7 @@ class Block {
7public: 7public:
8 Block() 8 Block()
9 : data_(NULL), 9 : data_(NULL),
10 data_size_(0), 10 data_size_(0),
11 size_(0) { } 11 size_(0) { }
12 12
13 ~Block() { 13 ~Block() {
@@ -15,7 +15,7 @@ public:
15 delete [] data_; 15 delete [] data_;
16 } 16 }
17 } 17 }
18 18
19 size_t Size() const { 19 size_t Size() const {
20 return size_; 20 return size_;
21 } 21 }
@@ -27,7 +27,7 @@ public:
27 27
28 uint8_t* Data() const { 28 uint8_t* Data() const {
29 if (data_ == NULL) { 29 if (data_ == NULL) {
30 CHECK_EQ(0, size_); 30 CHECK_EQ(0, size_);
31 data_size_ = 1; 31 data_size_ = 1;
32 data_ = new uint8_t[1]; 32 data_ = new uint8_t[1];
33 } 33 }
@@ -42,9 +42,9 @@ public:
42 data_ = new uint8_t[Constants::BLOCK_SIZE]; 42 data_ = new uint8_t[Constants::BLOCK_SIZE];
43 data_size_ = Constants::BLOCK_SIZE; 43 data_size_ = Constants::BLOCK_SIZE;
44 } 44 }
45 45
46 if (size_ + size > data_size_) { 46 if (size_ + size > data_size_) {
47 uint8_t *tmp = data_; 47 uint8_t *tmp = data_;
48 while (size_ + size > data_size_) { 48 while (size_ + size > data_size_) {
49 data_size_ *= 2; 49 data_size_ *= 2;
50 } 50 }
@@ -109,7 +109,7 @@ class FileSpec {
109 // Generates a file with a known size 109 // Generates a file with a known size
110 void GenerateFixedSize(xoff_t size) { 110 void GenerateFixedSize(xoff_t size) {
111 Reset(); 111 Reset();
112 112
113 for (xoff_t p = 0; p < size; ) { 113 for (xoff_t p = 0; p < size; ) {
114 xoff_t t = min(Constants::BLOCK_SIZE, size - p); 114 xoff_t t = min(Constants::BLOCK_SIZE, size - p);
115 table_.insert(make_pair(p, Segment(t, rand_))); 115 table_.insert(make_pair(p, Segment(t, rand_)));
@@ -172,7 +172,8 @@ class FileSpec {
172 iter != table_.end(); 172 iter != table_.end();
173 ++iter) { 173 ++iter) {
174 const Segment &seg = iter->second; 174 const Segment &seg = iter->second;
175 cerr << "Segment at " << iter->first << " (" << seg.ToString() << ")" << endl; 175 cerr << "Segment at " << iter->first
176 << " (" << seg.ToString() << ")" << endl;
176 } 177 }
177 } 178 }
178 179
@@ -210,7 +211,7 @@ class FileSpec {
210 const Segment &seg = pos->second; 211 const Segment &seg = pos->second;
211 212
212 // The position of this segment may start before this block starts, 213 // The position of this segment may start before this block starts,
213 // and then the position of the data may be offset from the seeding 214 // and then the position of the data may be offset from the seeding
214 // position. 215 // position.
215 size_t seg_offset = offset - pos->first; 216 size_t seg_offset = offset - pos->first;
216 size_t advance = min(seg.Size() - seg_offset, 217 size_t advance = min(seg.Size() - seg_offset,
@@ -330,10 +331,12 @@ public:
330 iter.Get(&sblock); 331 iter.Get(&sblock);
331 tblock.SetSize(sblock.Size()); 332 tblock.SetSize(sblock.Size());
332 usize_t tread; 333 usize_t tread;
333 CHECK_EQ(0, main_file_read(&t, tblock.Data(), tblock.Size(), &tread, "read failed")); 334 CHECK_EQ(0, main_file_read(&t,
335 tblock.Data(),
336 tblock.Size(), &tread, "read failed"));
334 CHECK_EQ(0, CmpDifferentBlockBytes(tblock, sblock)); 337 CHECK_EQ(0, CmpDifferentBlockBytes(tblock, sblock));
335 } 338 }
336 339
337 CHECK_EQ(0, main_file_close(&t)); 340 CHECK_EQ(0, main_file_close(&t));
338 main_file_cleanup(&t); 341 main_file_cleanup(&t);
339 return true; 342 return true;
@@ -345,7 +348,6 @@ protected:
345 348
346class TmpFile : public ExtFile { 349class TmpFile : public ExtFile {
347public: 350public:
348 // TODO this is a little unportable!
349 TmpFile() { 351 TmpFile() {
350 main_file_init(&file_); 352 main_file_init(&file_);
351 CHECK_EQ(0, main_file_open(&file_, Name(), XO_WRITE)); 353 CHECK_EQ(0, main_file_open(&file_, Name(), XO_WRITE));
@@ -356,8 +358,8 @@ public:
356 } 358 }
357 359
358 void Append(const Block *block) { 360 void Append(const Block *block) {
359 CHECK_EQ(0, main_file_write(&file_, 361 CHECK_EQ(0, main_file_write(&file_,
360 block->Data(), block->Size(), 362 block->Data(), block->Size(),
361 "tmpfile write failed")); 363 "tmpfile write failed"));
362 } 364 }
363 365
diff --git a/xdelta3/testing/modify.h b/xdelta3/testing/modify.h
index 7f27992..4a6edd3 100644
--- a/xdelta3/testing/modify.h
+++ b/xdelta3/testing/modify.h
@@ -2,20 +2,23 @@
2class Mutator { 2class Mutator {
3public: 3public:
4 virtual ~Mutator() { } 4 virtual ~Mutator() { }
5 virtual void Mutate(SegmentMap *table, 5 virtual void Mutate(SegmentMap *table,
6 const SegmentMap *source_table, 6 const SegmentMap *source_table,
7 MTRandom *rand) const = 0; 7 MTRandom *rand) const = 0;
8}; 8};
9 9
10class Change { 10class Change {
11public: 11public:
12 enum Kind { 12 enum Kind {
13 MODIFY = 1, 13 MODIFY = 1, // Mutate a certain range w/ random or supplied data
14 ADD = 2, 14 ADD = 2, // Insert random or supplied data
15 DELETE = 3, 15 DELETE = 3, // Delete a specified range of data
16 MOVE = 4, 16 COPY = 4, // Copy from one region, inserting elsewhere
17 COPY = 5, 17 MOVE = 5, // Copy then delete copied-from range
18 OVERWRITE = 6, 18 OVERWRITE = 6, // Copy then delete copied-to range
19
20 // ADD, DELETE, and COPY change the file size
21 // MODIFY, MOVE, OVERWRITE preserve the file size
19 }; 22 };
20 23
21 // Constructor for modify, add, delete. 24 // Constructor for modify, add, delete.
@@ -24,7 +27,7 @@ public:
24 size(size), 27 size(size),
25 addr1(addr1), 28 addr1(addr1),
26 addr2(0), 29 addr2(0),
27 insert(NULL) { 30 insert(NULL) {
28 CHECK(kind != MOVE && kind != COPY && kind != OVERWRITE); 31 CHECK(kind != MOVE && kind != COPY && kind != OVERWRITE);
29 } 32 }
30 33
@@ -34,17 +37,17 @@ public:
34 size(size), 37 size(size),
35 addr1(addr1), 38 addr1(addr1),
36 addr2(0), 39 addr2(0),
37 insert(insert) { 40 insert(insert) {
38 CHECK(kind != MOVE && kind != COPY && kind != OVERWRITE); 41 CHECK(kind != MOVE && kind != COPY && kind != OVERWRITE);
39 } 42 }
40 43
41 // Constructor for move 44 // Constructor for move, copy, overwrite
42 Change(Kind kind, xoff_t size, xoff_t addr1, xoff_t addr2) 45 Change(Kind kind, xoff_t size, xoff_t addr1, xoff_t addr2)
43 : kind(kind), 46 : kind(kind),
44 size(size), 47 size(size),
45 addr1(addr1), 48 addr1(addr1),
46 addr2(addr2), 49 addr2(addr2),
47 insert(NULL) { 50 insert(NULL) {
48 CHECK(kind == MOVE || kind == COPY || kind == OVERWRITE); 51 CHECK(kind == MOVE || kind == COPY || kind == OVERWRITE);
49 } 52 }
50 53
@@ -72,8 +75,9 @@ public:
72 // The speed of processing gigabytes of data is so slow compared with 75 // The speed of processing gigabytes of data is so slow compared with
73 // these table-copy operations, no attempt to make this fast. 76 // these table-copy operations, no attempt to make this fast.
74 SegmentMap tmp; 77 SegmentMap tmp;
75 78
76 for (ConstChangeListIterator iter(cl_.begin()); iter != cl_.end(); ++iter) { 79 for (ConstChangeListIterator iter(cl_.begin());
80 iter != cl_.end(); ++iter) {
77 const Change &ch = *iter; 81 const Change &ch = *iter;
78 tmp.clear(); 82 tmp.clear();
79 Mutate(ch, &tmp, source_table, rand); 83 Mutate(ch, &tmp, source_table, rand);
@@ -81,8 +85,8 @@ public:
81 source_table = table; 85 source_table = table;
82 } 86 }
83 } 87 }
84 88
85 static void Mutate(const Change &ch, 89 static void Mutate(const Change &ch,
86 SegmentMap *table, 90 SegmentMap *table,
87 const SegmentMap *source_table, 91 const SegmentMap *source_table,
88 MTRandom *rand) { 92 MTRandom *rand) {
@@ -108,7 +112,7 @@ public:
108 } 112 }
109 } 113 }
110 114
111 static void ModifyChange(const Change &ch, 115 static void ModifyChange(const Change &ch,
112 SegmentMap *table, 116 SegmentMap *table,
113 const SegmentMap *source_table, 117 const SegmentMap *source_table,
114 MTRandom *rand) { 118 MTRandom *rand) {
@@ -117,7 +121,7 @@ public:
117 xoff_t i_start = 0; 121 xoff_t i_start = 0;
118 xoff_t i_end = 0; 122 xoff_t i_end = 0;
119 123
120 for (ConstSegmentMapIterator iter(source_table->begin()); 124 for (ConstSegmentMapIterator iter(source_table->begin());
121 iter != source_table->end(); 125 iter != source_table->end();
122 ++iter) { 126 ++iter) {
123 const Segment &seg = iter->second; 127 const Segment &seg = iter->second;
@@ -130,8 +134,8 @@ public:
130 } 134 }
131 135
132 if (i_start < m_start) { 136 if (i_start < m_start) {
133 table->insert(table->end(), 137 table->insert(table->end(),
134 make_pair(i_start, 138 make_pair(i_start,
135 seg.Subseg(0, m_start - i_start))); 139 seg.Subseg(0, m_start - i_start)));
136 } 140 }
137 141
@@ -148,8 +152,8 @@ public:
148 } 152 }
149 153
150 if (i_end > m_end) { 154 if (i_end > m_end) {
151 table->insert(table->end(), 155 table->insert(table->end(),
152 make_pair(m_end, 156 make_pair(m_end,
153 seg.Subseg(m_end - i_start, i_end - m_end))); 157 seg.Subseg(m_end - i_start, i_end - m_end)));
154 } 158 }
155 } 159 }
@@ -159,7 +163,7 @@ public:
159 CHECK_LE(m_end, i_end); 163 CHECK_LE(m_end, i_end);
160 } 164 }
161 165
162 static void AddChange(const Change &ch, 166 static void AddChange(const Change &ch,
163 SegmentMap *table, 167 SegmentMap *table,
164 const SegmentMap *source_table, 168 const SegmentMap *source_table,
165 MTRandom *rand) { 169 MTRandom *rand) {
@@ -167,7 +171,7 @@ public:
167 xoff_t i_start = 0; 171 xoff_t i_start = 0;
168 xoff_t i_end = 0; 172 xoff_t i_end = 0;
169 173
170 for (ConstSegmentMapIterator iter(source_table->begin()); 174 for (ConstSegmentMapIterator iter(source_table->begin());
171 iter != source_table->end(); 175 iter != source_table->end();
172 ++iter) { 176 ++iter) {
173 const Segment &seg = iter->second; 177 const Segment &seg = iter->second;
@@ -185,8 +189,8 @@ public:
185 } 189 }
186 190
187 if (i_start < m_start) { 191 if (i_start < m_start) {
188 table->insert(table->end(), 192 table->insert(table->end(),
189 make_pair(i_start, 193 make_pair(i_start,
190 seg.Subseg(0, m_start - i_start))); 194 seg.Subseg(0, m_start - i_start)));
191 } 195 }
192 196
@@ -198,9 +202,10 @@ public:
198 } 202 }
199 203
200 if (m_start < i_end) { 204 if (m_start < i_end) {
201 table->insert(table->end(), 205 table->insert(table->end(),
202 make_pair(m_start + ch.size, 206 make_pair(m_start + ch.size,
203 seg.Subseg(m_start - i_start, i_end - m_start))); 207 seg.Subseg(m_start - i_start,
208 i_end - m_start)));
204 } 209 }
205 } 210 }
206 211
@@ -213,7 +218,7 @@ public:
213 } 218 }
214 } 219 }
215 220
216 static void DeleteChange(const Change &ch, 221 static void DeleteChange(const Change &ch,
217 SegmentMap *table, 222 SegmentMap *table,
218 const SegmentMap *source_table, 223 const SegmentMap *source_table,
219 MTRandom *rand) { 224 MTRandom *rand) {
@@ -222,7 +227,7 @@ public:
222 xoff_t i_start = 0; 227 xoff_t i_start = 0;
223 xoff_t i_end = 0; 228 xoff_t i_end = 0;
224 229
225 for (ConstSegmentMapIterator iter(source_table->begin()); 230 for (ConstSegmentMapIterator iter(source_table->begin());
226 iter != source_table->end(); 231 iter != source_table->end();
227 ++iter) { 232 ++iter) {
228 const Segment &seg = iter->second; 233 const Segment &seg = iter->second;
@@ -240,14 +245,14 @@ public:
240 } 245 }
241 246
242 if (i_start < m_start) { 247 if (i_start < m_start) {
243 table->insert(table->end(), 248 table->insert(table->end(),
244 make_pair(i_start, 249 make_pair(i_start,
245 seg.Subseg(0, m_start - i_start))); 250 seg.Subseg(0, m_start - i_start)));
246 } 251 }
247 252
248 if (i_end > m_end) { 253 if (i_end > m_end) {
249 table->insert(table->end(), 254 table->insert(table->end(),
250 make_pair(m_end - ch.size, 255 make_pair(m_end - ch.size,
251 seg.Subseg(m_end - i_start, i_end - m_end))); 256 seg.Subseg(m_end - i_start, i_end - m_end)));
252 } 257 }
253 } 258 }
@@ -256,19 +261,21 @@ public:
256 CHECK_LE(m_end, i_end); 261 CHECK_LE(m_end, i_end);
257 } 262 }
258 263
259 static void MoveChange(const Change &ch, 264 // A move is a copy followed by delete of the copied-from range.
265 static void MoveChange(const Change &ch,
260 SegmentMap *table, 266 SegmentMap *table,
261 const SegmentMap *source_table, 267 const SegmentMap *source_table,
262 MTRandom *rand) { 268 MTRandom *rand) {
263 SegmentMap tmp; 269 SegmentMap tmp;
264 CHECK_NE(ch.addr1, ch.addr2); 270 CHECK_NE(ch.addr1, ch.addr2);
265 CopyChange(ch, &tmp, source_table, rand); 271 CopyChange(ch, &tmp, source_table, rand);
266 Change d(Change::DELETE, ch.size, 272 Change d(Change::DELETE, ch.size,
267 ch.addr1 < ch.addr2 ? ch.addr1 : ch.addr1 + ch.size); 273 ch.addr1 < ch.addr2 ? ch.addr1 : ch.addr1 + ch.size);
268 DeleteChange(d, table, &tmp, rand); 274 DeleteChange(d, table, &tmp, rand);
269 } 275 }
270 276
271 static void OverwriteChange(const Change &ch, 277 // An overwrite is a copy followed by a delete of the copied-to range.
278 static void OverwriteChange(const Change &ch,
272 SegmentMap *table, 279 SegmentMap *table,
273 const SegmentMap *source_table, 280 const SegmentMap *source_table,
274 MTRandom *rand) { 281 MTRandom *rand) {
@@ -279,7 +286,7 @@ public:
279 DeleteChange(d, table, &tmp, rand); 286 DeleteChange(d, table, &tmp, rand);
280 } 287 }
281 288
282 static void CopyChange(const Change &ch, 289 static void CopyChange(const Change &ch,
283 SegmentMap *table, 290 SegmentMap *table,
284 const SegmentMap *source_table, 291 const SegmentMap *source_table,
285 MTRandom *ignore) { 292 MTRandom *ignore) {
@@ -289,7 +296,7 @@ public:
289 xoff_t i_end = 0; 296 xoff_t i_end = 0;
290 297
291 // Like AddChange() with AppendCopy instead of a random segment. 298 // Like AddChange() with AppendCopy instead of a random segment.
292 for (ConstSegmentMapIterator iter(source_table->begin()); 299 for (ConstSegmentMapIterator iter(source_table->begin());
293 iter != source_table->end(); 300 iter != source_table->end();
294 ++iter) { 301 ++iter) {
295 const Segment &seg = iter->second; 302 const Segment &seg = iter->second;
@@ -307,16 +314,16 @@ public:
307 } 314 }
308 315
309 if (i_start < m_start) { 316 if (i_start < m_start) {
310 table->insert(table->end(), 317 table->insert(table->end(),
311 make_pair(i_start, 318 make_pair(i_start,
312 seg.Subseg(0, m_start - i_start))); 319 seg.Subseg(0, m_start - i_start)));
313 } 320 }
314 321
315 AppendCopy(table, source_table, c_start, m_start, ch.size); 322 AppendCopy(table, source_table, c_start, m_start, ch.size);
316 323
317 if (m_start < i_end) { 324 if (m_start < i_end) {
318 table->insert(table->end(), 325 table->insert(table->end(),
319 make_pair(m_start + ch.size, 326 make_pair(m_start + ch.size,
320 seg.Subseg(m_start - i_start, i_end - m_start))); 327 seg.Subseg(m_start - i_start, i_end - m_start)));
321 } 328 }
322 } 329 }
@@ -331,7 +338,7 @@ public:
331 338
332 static void AppendCopy(SegmentMap *table, 339 static void AppendCopy(SegmentMap *table,
333 const SegmentMap *source_table, 340 const SegmentMap *source_table,
334 xoff_t copy_offset, 341 xoff_t copy_offset,
335 xoff_t append_offset, 342 xoff_t append_offset,
336 xoff_t length) { 343 xoff_t length) {
337 ConstSegmentMapIterator pos(source_table->upper_bound(copy_offset)); 344 ConstSegmentMapIterator pos(source_table->upper_bound(copy_offset));
@@ -340,10 +347,10 @@ public:
340 347
341 while (got < length) { 348 while (got < length) {
342 size_t seg_offset = copy_offset - pos->first; 349 size_t seg_offset = copy_offset - pos->first;
343 size_t advance = min(pos->second.Size() - seg_offset, 350 size_t advance = min(pos->second.Size() - seg_offset,
344 (size_t)(length - got)); 351 (size_t)(length - got));
345 352
346 table->insert(table->end(), 353 table->insert(table->end(),
347 make_pair(append_offset, 354 make_pair(append_offset,
348 pos->second.Subseg(seg_offset, 355 pos->second.Subseg(seg_offset,
349 advance))); 356 advance)));
@@ -354,7 +361,7 @@ public:
354 ++pos; 361 ++pos;
355 } 362 }
356 } 363 }
357 364
358 ChangeList* Changes() { 365 ChangeList* Changes() {
359 return &cl_; 366 return &cl_;
360 } 367 }
@@ -369,8 +376,8 @@ private:
369 376
370class Modify1stByte : public Mutator { 377class Modify1stByte : public Mutator {
371public: 378public:
372 void Mutate(SegmentMap *table, 379 void Mutate(SegmentMap *table,
373 const SegmentMap *source_table, 380 const SegmentMap *source_table,
374 MTRandom *rand) const { 381 MTRandom *rand) const {
375 ChangeListMutator::Mutate(Change(Change::MODIFY, 1, 0), 382 ChangeListMutator::Mutate(Change(Change::MODIFY, 1, 0),
376 table, source_table, rand); 383 table, source_table, rand);
diff --git a/xdelta3/testing/regtest.cc b/xdelta3/testing/regtest.cc
index 4ac458b..f0b7a42 100644
--- a/xdelta3/testing/regtest.cc
+++ b/xdelta3/testing/regtest.cc
@@ -8,15 +8,20 @@ class Regtest {
8public: 8public:
9 typedef typename Constants::Sizes Sizes; 9 typedef typename Constants::Sizes Sizes;
10 10
11 struct Options {
12 size_t encode_srcwin_maxsz;
13 };
14
11#include "segment.h" 15#include "segment.h"
12#include "modify.h" 16#include "modify.h"
13#include "file.h" 17#include "file.h"
14#include "cmp.h" 18#include "cmp.h"
15#include "delta.h" 19#include "delta.h"
16 20
17void InMemoryEncodeDecode(const FileSpec &source_file, 21void InMemoryEncodeDecode(const FileSpec &source_file,
18 const FileSpec &target_file, 22 const FileSpec &target_file,
19 Block *coded_data) { 23 Block *coded_data,
24 const Options &options = Options()) {
20 xd3_stream encode_stream; 25 xd3_stream encode_stream;
21 xd3_config encode_config; 26 xd3_config encode_config;
22 xd3_source encode_source; 27 xd3_source encode_source;
@@ -41,8 +46,9 @@ void InMemoryEncodeDecode(const FileSpec &source_file,
41 xd3_init_config(&decode_config, XD3_ADLER32); 46 xd3_init_config(&decode_config, XD3_ADLER32);
42 47
43 encode_config.winsize = Constants::WINDOW_SIZE; 48 encode_config.winsize = Constants::WINDOW_SIZE;
49 encode_config.srcwin_maxsz = options.encode_srcwin_maxsz;
44 50
45 // TODO! the smatcher setup isn't working, 51 // TODO! the smatcher setup isn't working,
46// if (options.large_cksum_step) { 52// if (options.large_cksum_step) {
47// encode_config.smatch_cfg = XD3_SMATCH_SOFT; 53// encode_config.smatch_cfg = XD3_SMATCH_SOFT;
48// encode_config.smatcher_soft.large_step = options.large_cksum_step; 54// encode_config.smatcher_soft.large_step = options.large_cksum_step;
@@ -81,7 +87,8 @@ void InMemoryEncodeDecode(const FileSpec &source_file,
81 87
82 IF_DEBUG2(DP(RINT "target in %s: %llu..%llu %"Q"u(%"Q"u) verified %"Q"u\n", 88 IF_DEBUG2(DP(RINT "target in %s: %llu..%llu %"Q"u(%"Q"u) verified %"Q"u\n",
83 encoding ? "encoding" : "decoding", 89 encoding ? "encoding" : "decoding",
84 target_iterator.Offset(), target_iterator.Offset() + target_block.Size(), 90 target_iterator.Offset(),
91 target_iterator.Offset() + target_block.Size(),
85 target_iterator.Blkno(), blks, verified_bytes)); 92 target_iterator.Blkno(), blks, verified_bytes));
86 93
87 if (blks == 0 || target_iterator.Blkno() == (blks - 1)) { 94 if (blks == 0 || target_iterator.Blkno() == (blks - 1)) {
@@ -102,7 +109,7 @@ void InMemoryEncodeDecode(const FileSpec &source_file,
102 msg = decode_stream.msg; 109 msg = decode_stream.msg;
103 } 110 }
104 111
105 IF_DEBUG2(DP(RINT "%s = %s %s\n", encoding ? "E " : " D", 112 IF_DEBUG1(DP(RINT "%s = %s %s\n", encoding ? "E " : " D",
106 xd3_strerror(ret), 113 xd3_strerror(ret),
107 msg == NULL ? "" : msg)); 114 msg == NULL ? "" : msg));
108 115
@@ -111,12 +118,12 @@ void InMemoryEncodeDecode(const FileSpec &source_file,
111 if (encoding) { 118 if (encoding) {
112 if (coded_data != NULL) { 119 if (coded_data != NULL) {
113 // Optional encoded-output to the caller 120 // Optional encoded-output to the caller
114 coded_data->Append(encode_stream.next_out, 121 coded_data->Append(encode_stream.next_out,
115 encode_stream.avail_out); 122 encode_stream.avail_out);
116 } 123 }
117 // Feed this data to the decoder. 124 // Feed this data to the decoder.
118 xd3_avail_input(&decode_stream, 125 xd3_avail_input(&decode_stream,
119 encode_stream.next_out, 126 encode_stream.next_out,
120 encode_stream.avail_out); 127 encode_stream.avail_out);
121 xd3_consume_output(&encode_stream); 128 xd3_consume_output(&encode_stream);
122 encoding = false; 129 encoding = false;
@@ -131,12 +138,13 @@ void InMemoryEncodeDecode(const FileSpec &source_file,
131 xd3_source *src = (encoding ? &encode_source : &decode_source); 138 xd3_source *src = (encoding ? &encode_source : &decode_source);
132 Block *block = (encoding ? &encode_source_block : &decode_source_block); 139 Block *block = (encoding ? &encode_source_block : &decode_source_block);
133 if (encoding) { 140 if (encoding) {
134 IF_DEBUG2(DP(RINT "block %"Q"u last srcpos %"Q"u encodepos %u\n", 141 IF_DEBUG1(DP(RINT "[srcblock] %"Q"u last srcpos %"Q"u "
142 "encodepos %"Q"u\n",
135 encode_source.getblkno, 143 encode_source.getblkno,
136 encode_stream.match_last_srcpos, 144 encode_stream.match_last_srcpos,
137 encode_stream.input_position)); 145 encode_stream.input_position + encode_stream.total_in));
138 } 146 }
139 147
140 source_iterator.SetBlock(src->getblkno); 148 source_iterator.SetBlock(src->getblkno);
141 source_iterator.Get(block); 149 source_iterator.Get(block);
142 src->curblkno = src->getblkno; 150 src->curblkno = src->getblkno;
@@ -171,8 +179,8 @@ void InMemoryEncodeDecode(const FileSpec &source_file,
171 } 179 }
172 encoding = false; 180 encoding = false;
173 } else { 181 } else {
174 CHECK_EQ(0, CmpDifferentBlockBytesAtOffset(decoded_block, 182 CHECK_EQ(0, CmpDifferentBlockBytesAtOffset(decoded_block,
175 target_file, 183 target_file,
176 verified_bytes)); 184 verified_bytes));
177 verified_bytes += decoded_block.Size(); 185 verified_bytes += decoded_block.Size();
178 decoded_block.Reset(); 186 decoded_block.Reset();
@@ -210,7 +218,7 @@ void TestRandomNumbers() {
210 usum += rand.Rand32(); 218 usum += rand.Rand32();
211 esum += rand.ExpRand32(1024); 219 esum += rand.ExpRand32(1024);
212 } 220 }
213 221
214 double allowed_error = 0.01; 222 double allowed_error = 0.01;
215 223
216 uint32_t umean = usum / rounds; 224 uint32_t umean = usum / rounds;
@@ -331,10 +339,11 @@ void TestModifyMutator() {
331 339
332 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { 340 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) {
333 ChangeList cl1; 341 ChangeList cl1;
334 cl1.push_back(Change(Change::MODIFY, test_cases[i].size, test_cases[i].addr)); 342 cl1.push_back(Change(Change::MODIFY, test_cases[i].size,
343 test_cases[i].addr));
335 spec0.ModifyTo(ChangeListMutator(cl1), &spec1); 344 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
336 CHECK_EQ(spec0.Size(), spec1.Size()); 345 CHECK_EQ(spec0.Size(), spec1.Size());
337 346
338 size_t diff = CmpDifferentBytes(spec0, spec1); 347 size_t diff = CmpDifferentBytes(spec0, spec1);
339 CHECK_LE(diff, test_cases[i].size); 348 CHECK_LE(diff, test_cases[i].size);
340 349
@@ -407,7 +416,8 @@ void TestDeleteMutator() {
407 416
408 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { 417 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) {
409 ChangeList cl1; 418 ChangeList cl1;
410 cl1.push_back(Change(Change::DELETE, test_cases[i].size, test_cases[i].addr)); 419 cl1.push_back(Change(Change::DELETE, test_cases[i].size,
420 test_cases[i].addr));
411 spec0.ModifyTo(ChangeListMutator(cl1), &spec1); 421 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
412 CHECK_EQ(spec0.Size() - test_cases[i].size, spec1.Size()); 422 CHECK_EQ(spec0.Size() - test_cases[i].size, spec1.Size());
413 423
@@ -435,12 +445,13 @@ void TestCopyMutator() {
435 // copies, it does not enter checksums. So these tests copy data from 445 // copies, it does not enter checksums. So these tests copy data from
436 // later to earlier so that checksumming will start. 446 // later to earlier so that checksumming will start.
437 { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2, 0 }, 447 { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2, 0 },
438 { Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE, Constants::BLOCK_SIZE, }, 448 { Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE,
449 Constants::BLOCK_SIZE, },
439 }; 450 };
440 451
441 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { 452 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) {
442 ChangeList cl1; 453 ChangeList cl1;
443 cl1.push_back(Change(Change::COPY, test_cases[i].size, 454 cl1.push_back(Change(Change::COPY, test_cases[i].size,
444 test_cases[i].from, test_cases[i].to)); 455 test_cases[i].from, test_cases[i].to));
445 spec0.ModifyTo(ChangeListMutator(cl1), &spec1); 456 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
446 CHECK_EQ(spec0.Size() + test_cases[i].size, spec1.Size()); 457 CHECK_EQ(spec0.Size() + test_cases[i].size, spec1.Size());
@@ -468,17 +479,21 @@ void TestMoveMutator() {
468 // This is easier to test than Copy but has the same trouble as Delete. 479 // This is easier to test than Copy but has the same trouble as Delete.
469 { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2, 0 }, 480 { Constants::BLOCK_SIZE / 2, Constants::BLOCK_SIZE / 2, 0 },
470 { Constants::BLOCK_SIZE / 2, 0, Constants::BLOCK_SIZE / 2 }, 481 { Constants::BLOCK_SIZE / 2, 0, Constants::BLOCK_SIZE / 2 },
471 { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE }, 482 { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE, 2 *
472 { Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE, Constants::BLOCK_SIZE }, 483 Constants::BLOCK_SIZE },
473 { Constants::BLOCK_SIZE * 3 / 2, Constants::BLOCK_SIZE, Constants::BLOCK_SIZE * 3 / 2 }, 484 { Constants::BLOCK_SIZE, 2 * Constants::BLOCK_SIZE,
485 Constants::BLOCK_SIZE },
486 { Constants::BLOCK_SIZE * 3 / 2, Constants::BLOCK_SIZE,
487 Constants::BLOCK_SIZE * 3 / 2 },
474 488
475 // This is a no-op 489 // This is a no-op
476 { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE * 2, 3 * Constants::BLOCK_SIZE }, 490 { Constants::BLOCK_SIZE, Constants::BLOCK_SIZE * 2,
491 3 * Constants::BLOCK_SIZE },
477 }; 492 };
478 493
479 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { 494 for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) {
480 ChangeList cl1; 495 ChangeList cl1;
481 cl1.push_back(Change(Change::MOVE, test_cases[i].size, 496 cl1.push_back(Change(Change::MOVE, test_cases[i].size,
482 test_cases[i].from, test_cases[i].to)); 497 test_cases[i].from, test_cases[i].to));
483 spec0.ModifyTo(ChangeListMutator(cl1), &spec1); 498 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
484 CHECK_EQ(spec0.Size(), spec1.Size()); 499 CHECK_EQ(spec0.Size(), spec1.Size());
@@ -506,10 +521,11 @@ void TestOverwriteMutator() {
506 Block b0, b1; 521 Block b0, b1;
507 BlockIterator(spec0).Get(&b0); 522 BlockIterator(spec0).Get(&b0);
508 BlockIterator(spec1).Get(&b1); 523 BlockIterator(spec1).Get(&b1);
509 524
510 CHECK(memcmp(b0.Data(), b1.Data() + 20, 10) == 0); 525 CHECK(memcmp(b0.Data(), b1.Data() + 20, 10) == 0);
511 CHECK(memcmp(b0.Data(), b1.Data(), 20) == 0); 526 CHECK(memcmp(b0.Data(), b1.Data(), 20) == 0);
512 CHECK(memcmp(b0.Data() + 30, b1.Data() + 30, Constants::BLOCK_SIZE - 30) == 0); 527 CHECK(memcmp(b0.Data() + 30, b1.Data() + 30,
528 Constants::BLOCK_SIZE - 30) == 0);
513 529
514 cl1.clear(); 530 cl1.clear();
515 cl1.push_back(Change(Change::OVERWRITE, 10, 20, (xoff_t)0)); 531 cl1.push_back(Change(Change::OVERWRITE, 10, 20, (xoff_t)0));
@@ -518,9 +534,10 @@ void TestOverwriteMutator() {
518 534
519 BlockIterator(spec0).Get(&b0); 535 BlockIterator(spec0).Get(&b0);
520 BlockIterator(spec1).Get(&b1); 536 BlockIterator(spec1).Get(&b1);
521 537
522 CHECK(memcmp(b0.Data() + 20, b1.Data(), 10) == 0); 538 CHECK(memcmp(b0.Data() + 20, b1.Data(), 10) == 0);
523 CHECK(memcmp(b0.Data() + 10, b1.Data() + 10, Constants::BLOCK_SIZE - 10) == 0); 539 CHECK(memcmp(b0.Data() + 10, b1.Data() + 10,
540 Constants::BLOCK_SIZE - 10) == 0);
524} 541}
525 542
526// Note: this test is written to expose a problem, but the problem was 543// Note: this test is written to expose a problem, but the problem was
@@ -534,7 +551,7 @@ void TestNonBlockingProgress() {
534 spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 3); 551 spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 3);
535 552
536 // This is a lazy target match 553 // This is a lazy target match
537 Change ct(Change::OVERWRITE, 22, 554 Change ct(Change::OVERWRITE, 22,
538 Constants::BLOCK_SIZE + 50, 555 Constants::BLOCK_SIZE + 50,
539 Constants::BLOCK_SIZE + 20); 556 Constants::BLOCK_SIZE + 20);
540 557
@@ -598,6 +615,44 @@ void TestBlockInMemory() {
598 CHECK_EQ(spec1.Blocks(Constants::WINDOW_SIZE), delta.Windows()); 615 CHECK_EQ(spec1.Blocks(Constants::WINDOW_SIZE), delta.Windows());
599} 616}
600 617
618void TestFifoCopyDiscipline() {
619 MTRandom rand;
620 FileSpec spec0(&rand);
621 FileSpec spec1(&rand);
622
623 spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 4);
624
625 // Create a half-block copy, 2.5 blocks apart. With 64-byte blocks,
626 // the file in spec0 copies @ 384 from spec1 @ 64.
627 ChangeList cl1;
628 cl1.push_back(Change(Change::MODIFY,
629 Constants::BLOCK_SIZE / 2,
630 0));
631 cl1.push_back(Change(Change::OVERWRITE,
632 Constants::BLOCK_SIZE / 2,
633 Constants::BLOCK_SIZE * 3,
634 Constants::BLOCK_SIZE / 2));
635 cl1.push_back(Change(Change::MODIFY,
636 Constants::BLOCK_SIZE * 3,
637 Constants::BLOCK_SIZE));
638 spec0.ModifyTo(ChangeListMutator(cl1), &spec1);
639
640 Options options1;
641 options1.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 4;
642 Block block1;
643 InMemoryEncodeDecode(spec1, spec0, &block1, options1);
644 Delta delta1(block1);
645 CHECK_EQ(4 * Constants::BLOCK_SIZE -
646 Constants::BLOCK_SIZE / 2, delta1.AddedBytes());
647
648 Options options2;
649 options2.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 3;
650 Block block2;
651 InMemoryEncodeDecode(spec1, spec0, &block2, options2);
652 Delta delta2(block2);
653 CHECK_EQ(4 * Constants::BLOCK_SIZE, delta2.AddedBytes());
654}
655
601void FourWayMergeTest(const FileSpec &spec0, 656void FourWayMergeTest(const FileSpec &spec0,
602 const FileSpec &spec1, 657 const FileSpec &spec1,
603 const FileSpec &spec2, 658 const FileSpec &spec2,
@@ -631,7 +686,7 @@ void FourWayMergeTest(const FileSpec &spec0,
631 mcmd.push_back(NULL); 686 mcmd.push_back(NULL);
632 687
633 //DP(RINT "Running one merge: %s\n", CommandToString(mcmd).c_str()); 688 //DP(RINT "Running one merge: %s\n", CommandToString(mcmd).c_str());
634 CHECK_EQ(0, xd3_main_cmdline(mcmd.size() - 1, 689 CHECK_EQ(0, xd3_main_cmdline(mcmd.size() - 1,
635 const_cast<char**>(&mcmd[0]))); 690 const_cast<char**>(&mcmd[0])));
636 691
637 ExtFile recon; 692 ExtFile recon;
@@ -645,7 +700,7 @@ void FourWayMergeTest(const FileSpec &spec0,
645 tcmd.push_back(NULL); 700 tcmd.push_back(NULL);
646 701
647 //DP(RINT "Running one recon! %s\n", CommandToString(tcmd).c_str()); 702 //DP(RINT "Running one recon! %s\n", CommandToString(tcmd).c_str());
648 CHECK_EQ(0, xd3_main_cmdline(tcmd.size() - 1, 703 CHECK_EQ(0, xd3_main_cmdline(tcmd.size() - 1,
649 const_cast<char**>(&tcmd[0]))); 704 const_cast<char**>(&tcmd[0])));
650 //DP(RINT "Should equal! %s\n", f2.Name()); 705 //DP(RINT "Should equal! %s\n", f2.Name());
651 706
@@ -675,7 +730,7 @@ void TestMergeCommand1() {
675 if (change1 == 0) { 730 if (change1 == 0) {
676 continue; 731 continue;
677 } 732 }
678 733
679 DP(RINT "S0 = %lu\n", size0); 734 DP(RINT "S0 = %lu\n", size0);
680 DP(RINT "C1 = %lu\n", change1); 735 DP(RINT "C1 = %lu\n", change1);
681 736
@@ -685,7 +740,7 @@ void TestMergeCommand1() {
685 spec0.GenerateFixedSize(size0); 740 spec0.GenerateFixedSize(size0);
686 741
687 ChangeList cl1, cl2, cl3; 742 ChangeList cl1, cl2, cl3;
688 743
689 size_t change3 = change1; 744 size_t change3 = change1;
690 size_t change3_pos; 745 size_t change3_pos;
691 746
@@ -735,7 +790,7 @@ void TestMergeCommand2() {
735 SizeIterator<size_t, Sizes> si3(&rand, 10); 790 SizeIterator<size_t, Sizes> si3(&rand, 10);
736 for (; !si3.Done(); si3.Next()) { 791 for (; !si3.Done(); si3.Next()) {
737 size_t size3 = si3.Get(); 792 size_t size3 = si3.Get();
738 793
739 // We're only interested in three sizes, strictly decreasing. */ 794 // We're only interested in three sizes, strictly decreasing. */
740 if (size3 >= size2 || size2 >= size1 || size1 >= size0) { 795 if (size3 >= size2 || size2 >= size1 || size1 >= size0) {
741 continue; 796 continue;
@@ -749,7 +804,7 @@ void TestMergeCommand2() {
749 spec0.GenerateFixedSize(size0); 804 spec0.GenerateFixedSize(size0);
750 805
751 ChangeList cl1, cl2, cl3; 806 ChangeList cl1, cl2, cl3;
752 807
753 cl1.push_back(Change(Change::DELETE, size0 - size1, 0)); 808 cl1.push_back(Change(Change::DELETE, size0 - size1, 0));
754 cl2.push_back(Change(Change::DELETE, size0 - size2, 0)); 809 cl2.push_back(Change(Change::DELETE, size0 - size2, 0));
755 cl3.push_back(Change(Change::DELETE, size0 - size3, 0)); 810 cl3.push_back(Change(Change::DELETE, size0 - size3, 0));
@@ -790,6 +845,7 @@ void MainTest() {
790 TEST(TestEmptyInMemory); 845 TEST(TestEmptyInMemory);
791 TEST(TestBlockInMemory); 846 TEST(TestBlockInMemory);
792 TEST(TestNonBlockingProgress); 847 TEST(TestNonBlockingProgress);
848 TEST(TestFifoCopyDiscipline);
793 TEST(TestMergeCommand1); 849 TEST(TestMergeCommand1);
794 TEST(TestMergeCommand2); 850 TEST(TestMergeCommand2);
795} 851}
diff --git a/xdelta3/testing/segment.h b/xdelta3/testing/segment.h
index a743bfd..ea3dcee 100644
--- a/xdelta3/testing/segment.h
+++ b/xdelta3/testing/segment.h
@@ -6,7 +6,7 @@ class Segment {
6 : size_(size), 6 : size_(size),
7 seed_(rand->Rand32()), 7 seed_(rand->Rand32()),
8 seed_offset_(0), 8 seed_offset_(0),
9 data_(NULL) { 9 data_(NULL) {
10 CHECK_GT(size_, 0); 10 CHECK_GT(size_, 0);
11 } 11 }
12 12
@@ -14,7 +14,7 @@ class Segment {
14 : size_(size), 14 : size_(size),
15 seed_(seed), 15 seed_(seed),
16 seed_offset_(0), 16 seed_offset_(0),
17 data_(NULL) { 17 data_(NULL) {
18 CHECK_GT(size_, 0); 18 CHECK_GT(size_, 0);
19 } 19 }
20 20
@@ -22,12 +22,12 @@ class Segment {
22 : size_(size), 22 : size_(size),
23 seed_(0), 23 seed_(0),
24 seed_offset_(0), 24 seed_offset_(0),
25 data_(data) { 25 data_(data) {
26 CHECK_GT(size_, 0); 26 CHECK_GT(size_, 0);
27 } 27 }
28 28
29 size_t Size() const { 29 size_t Size() const {
30 return size_; 30 return size_;
31 } 31 }
32 32
33 Segment Subseg(size_t start, size_t size) const { 33 Segment Subseg(size_t start, size_t size) const {
@@ -66,7 +66,7 @@ class Segment {
66 } 66 }
67 } else { 67 } else {
68 char buf[256]; 68 char buf[256];
69 sprintf(buf, "size=%ld,seed=%ld,skip=%ld", size_, seed_, seed_offset_); 69 sprintf(buf, "size=%ld,seed=%ud,skip=%ld", size_, seed_, seed_offset_);
70 r.append(buf); 70 r.append(buf);
71 } 71 }
72 return r; 72 return r;
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h
index 167343a..7fa0901 100644
--- a/xdelta3/xdelta3-main.h
+++ b/xdelta3/xdelta3-main.h
@@ -1,6 +1,6 @@
1/* xdelta 3 - delta compression tools and library 1/* xdelta 3 - delta compression tools and library
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 * 2008, 2009 3 * 2008, 2009, 2010
4 * Joshua P. MacDonald 4 * Joshua P. MacDonald
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
@@ -323,7 +323,7 @@ static int option_recompress_outputs = 1;
323/* This is for comparing "printdelta" output without attention to 323/* This is for comparing "printdelta" output without attention to
324 * copy-instruction modes. */ 324 * copy-instruction modes. */
325#if VCDIFF_TOOLS 325#if VCDIFF_TOOLS
326static int option_print_cpymode = 1; /* Note: see reset_defaults(). */ 326static int option_print_cpymode = 1; /* Note: see reset_defaults(). */
327#endif 327#endif
328 328
329/* Static variables */ 329/* Static variables */
@@ -1111,7 +1111,7 @@ main_file_seek (main_file *xfile, xoff_t pos)
1111 1111
1112 if (ret) 1112 if (ret)
1113 { 1113 {
1114 XPR(NT "seek to %"Q"u failed: %s: %s\n", 1114 XPR(NT "seek to %"Q"u failed: %s: %s\n",
1115 pos, xfile->filename, xd3_mainerror (ret)); 1115 pos, xfile->filename, xd3_mainerror (ret));
1116 } 1116 }
1117 1117
@@ -1266,7 +1266,7 @@ xsnprintf_func (char *str, int n, const char *fmt, ...)
1266 return ret; 1266 return ret;
1267} 1267}
1268 1268
1269/* The following macros let VCDIFF print using main_file_write(), 1269/* The following macros let VCDIFF print using main_file_write(),
1270 * for example: 1270 * for example:
1271 * 1271 *
1272 * VC(UT "trying to be portable: %d\n", x)VE; 1272 * VC(UT "trying to be portable: %d\n", x)VE;
@@ -1315,23 +1315,24 @@ main_print_window (xd3_stream* stream, main_file *xfile)
1315 addr_bytes = stream->addr_sect.buf - addr_before; 1315 addr_bytes = stream->addr_sect.buf - addr_before;
1316 inst_bytes = stream->inst_sect.buf - inst_before; 1316 inst_bytes = stream->inst_sect.buf - inst_before;
1317 1317
1318 VC(UT " %06"Q"u %03u %s %6u", stream->dec_winstart + size, 1318 VC(UT " %06"Q"u %03u %s %6u", stream->dec_winstart + size,
1319 option_print_cpymode ? code : 0, 1319 option_print_cpymode ? code : 0,
1320 xd3_rtype_to_string ((xd3_rtype) stream->dec_current1.type, option_print_cpymode), 1320 xd3_rtype_to_string ((xd3_rtype) stream->dec_current1.type,
1321 option_print_cpymode),
1321 (usize_t) stream->dec_current1.size)VE; 1322 (usize_t) stream->dec_current1.size)VE;
1322 1323
1323 if (stream->dec_current1.type != XD3_NOOP) 1324 if (stream->dec_current1.type != XD3_NOOP)
1324 { 1325 {
1325 if (stream->dec_current1.type >= XD3_CPY) 1326 if (stream->dec_current1.type >= XD3_CPY)
1326 { 1327 {
1327 if (stream->dec_current1.addr >= stream->dec_cpylen) 1328 if (stream->dec_current1.addr >= stream->dec_cpylen)
1328 { 1329 {
1329 VC(UT " T@%-6u", 1330 VC(UT " T@%-6u",
1330 stream->dec_current1.addr - stream->dec_cpylen)VE; 1331 stream->dec_current1.addr - stream->dec_cpylen)VE;
1331 } 1332 }
1332 else 1333 else
1333 { 1334 {
1334 VC(UT " S@%-6"Q"u", 1335 VC(UT " S@%-6"Q"u",
1335 stream->dec_cpyoff + stream->dec_current1.addr)VE; 1336 stream->dec_cpyoff + stream->dec_current1.addr)VE;
1336 } 1337 }
1337 } 1338 }
@@ -1352,14 +1353,14 @@ main_print_window (xd3_stream* stream, main_file *xfile)
1352 1353
1353 if (stream->dec_current2.type >= XD3_CPY) 1354 if (stream->dec_current2.type >= XD3_CPY)
1354 { 1355 {
1355 if (stream->dec_current2.addr >= stream->dec_cpylen) 1356 if (stream->dec_current2.addr >= stream->dec_cpylen)
1356 { 1357 {
1357 VC(UT " T@%-6u", 1358 VC(UT " T@%-6u",
1358 stream->dec_current2.addr - stream->dec_cpylen)VE; 1359 stream->dec_current2.addr - stream->dec_cpylen)VE;
1359 } 1360 }
1360 else 1361 else
1361 { 1362 {
1362 VC(UT " S@%-6"Q"u", 1363 VC(UT " S@%-6"Q"u",
1363 stream->dec_cpyoff + stream->dec_current2.addr)VE; 1364 stream->dec_cpyoff + stream->dec_current2.addr)VE;
1364 } 1365 }
1365 } 1366 }
@@ -1432,7 +1433,8 @@ main_print_func (xd3_stream* stream, main_file *xfile)
1432 1433
1433 if (xfile->snprintf_buf == NULL) 1434 if (xfile->snprintf_buf == NULL)
1434 { 1435 {
1435 if ((xfile->snprintf_buf = (uint8_t*)main_malloc(SNPRINTF_BUFSIZE)) == NULL) 1436 if ((xfile->snprintf_buf =
1437 (uint8_t*)main_malloc(SNPRINTF_BUFSIZE)) == NULL)
1436 { 1438 {
1437 return ENOMEM; 1439 return ENOMEM;
1438 } 1440 }
@@ -1742,7 +1744,7 @@ main_merge_arguments (main_merge_list* merges)
1742 } 1744 }
1743 1745
1744 if ((ret = xd3_config_stream (& merge_input, NULL)) || 1746 if ((ret = xd3_config_stream (& merge_input, NULL)) ||
1745 (ret = xd3_whole_state_init (& merge_input))) 1747 (ret = xd3_whole_state_init (& merge_input)))
1746 { 1748 {
1747 XPR(NT XD3_LIB_ERRMSG (& merge_input, ret)); 1749 XPR(NT XD3_LIB_ERRMSG (& merge_input, ret));
1748 return ret; 1750 return ret;
@@ -1768,7 +1770,7 @@ main_merge_arguments (main_merge_list* merges)
1768 if (count++ == 0) 1770 if (count++ == 0)
1769 { 1771 {
1770 /* The first merge source is the next merge input. */ 1772 /* The first merge source is the next merge input. */
1771 xd3_swap_whole_state (& recode_stream->whole_target, 1773 xd3_swap_whole_state (& recode_stream->whole_target,
1772 & merge_input.whole_target); 1774 & merge_input.whole_target);
1773 } 1775 }
1774 else 1776 else
@@ -1822,7 +1824,7 @@ main_merge_arguments (main_merge_list* merges)
1822 goto error; 1824 goto error;
1823 } 1825 }
1824 1826
1825 xd3_swap_whole_state (& merge_stream->whole_target, 1827 xd3_swap_whole_state (& merge_stream->whole_target,
1826 & merge_input.whole_target); 1828 & merge_input.whole_target);
1827 ret = 0; 1829 ret = 0;
1828 error: 1830 error:
@@ -1861,7 +1863,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1861 /* merge_stream is set if there were arguments. this stream's input 1863 /* merge_stream is set if there were arguments. this stream's input
1862 * needs to be applied to the merge_stream source. */ 1864 * needs to be applied to the merge_stream source. */
1863 if ((merge_stream != NULL) && 1865 if ((merge_stream != NULL) &&
1864 (ret = xd3_merge_input_output (stream, 1866 (ret = xd3_merge_input_output (stream,
1865 & merge_stream->whole_target))) 1867 & merge_stream->whole_target)))
1866 { 1868 {
1867 XPR(NT XD3_LIB_ERRMSG (stream, ret)); 1869 XPR(NT XD3_LIB_ERRMSG (stream, ret));
@@ -1918,7 +1920,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1918 } 1920 }
1919 1921
1920 if (option_use_checksum && 1922 if (option_use_checksum &&
1921 (stream->dec_win_ind & VCD_ADLER32) != 0) 1923 (stream->dec_win_ind & VCD_ADLER32) != 0)
1922 { 1924 {
1923 recode_stream->flags |= XD3_ADLER32_RECODE; 1925 recode_stream->flags |= XD3_ADLER32_RECODE;
1924 recode_stream->recode_adler32 = stream->whole_target.wininfo[window_num].adler32; 1926 recode_stream->recode_adler32 = stream->whole_target.wininfo[window_num].adler32;
@@ -1931,7 +1933,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1931 main_free (main_bdata); 1933 main_free (main_bdata);
1932 main_bdata = NULL; 1934 main_bdata = NULL;
1933 main_bsize = 0; 1935 main_bsize = 0;
1934 if ((main_bdata = (uint8_t*) 1936 if ((main_bdata = (uint8_t*)
1935 main_malloc (window_size)) == NULL) 1937 main_malloc (window_size)) == NULL)
1936 { 1938 {
1937 return ENOMEM; 1939 return ENOMEM;
@@ -1959,7 +1961,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1959 1961
1960 case XD3_ADD: 1962 case XD3_ADD:
1961 /* Adds are implicit, put them into the input buffer. */ 1963 /* Adds are implicit, put them into the input buffer. */
1962 memcpy (main_bdata + window_pos, 1964 memcpy (main_bdata + window_pos,
1963 stream->whole_target.adds + inst->addr, take); 1965 stream->whole_target.adds + inst->addr, take);
1964 break; 1966 break;
1965 1967
@@ -1976,14 +1978,14 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1976 } 1978 }
1977 addr = inst->addr; 1979 addr = inst->addr;
1978 } 1980 }
1979 else 1981 else
1980 { 1982 {
1981 XD3_ASSERT (inst->addr >= window_start); 1983 XD3_ASSERT (inst->addr >= window_start);
1982 addr = inst->addr - window_start; 1984 addr = inst->addr - window_start;
1983 } 1985 }
1984 IF_DEBUG2 (DP(RINT "[merge copy] winpos %u take %u addr %"Q"u mode %u\n", 1986 IF_DEBUG2 (DP(RINT "[merge copy] winpos %u take %u addr %"Q"u mode %u\n",
1985 window_pos, take, addr, inst->mode)); 1987 window_pos, take, addr, inst->mode));
1986 if ((ret = xd3_found_match (recode_stream, window_pos, take, 1988 if ((ret = xd3_found_match (recode_stream, window_pos, take,
1987 addr, inst->mode != 0))) 1989 addr, inst->mode != 0)))
1988 { 1990 {
1989 return ret; 1991 return ret;
@@ -2381,9 +2383,9 @@ main_secondary_decompress_check (main_file *file,
2381 2383
2382 if (check_nread == try_read) 2384 if (check_nread == try_read)
2383 { 2385 {
2384 ret = main_file_read (file, 2386 ret = main_file_read (file,
2385 input_buf + try_read, 2387 input_buf + try_read,
2386 input_size - try_read, 2388 input_size - try_read,
2387 nread, 2389 nread,
2388 "input read failed"); 2390 "input read failed");
2389 } 2391 }
@@ -2732,7 +2734,7 @@ main_read_primary_input (main_file *file,
2732 { 2734 {
2733 /* Application header overrides magic number. */ 2735 /* Application header overrides magic number. */
2734 } 2736 }
2735 else 2737 else
2736 { 2738 {
2737 return main_secondary_decompress_check (file, buf, size, nread); 2739 return main_secondary_decompress_check (file, buf, size, nread);
2738 } 2740 }
@@ -2844,7 +2846,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2844 } 2846 }
2845 2847
2846 if (sfile->size_known && source_size < option_srcwinsz) 2848 if (sfile->size_known && source_size < option_srcwinsz)
2847 { 2849 {
2848 blksize = (source_size / MIN_LRU_SIZE); 2850 blksize = (source_size / MIN_LRU_SIZE);
2849 } 2851 }
2850 else 2852 else
@@ -2885,12 +2887,12 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2885 main_blklru_list_remove (& lru[0]); 2887 main_blklru_list_remove (& lru[0]);
2886 lru = NULL; 2888 lru = NULL;
2887 2889
2888 if (ret != 0) 2890 if (ret != 0)
2889 { 2891 {
2890 main_free (block0.blk); 2892 main_free (block0.blk);
2891 2893
2892 XPR(NT "error reading source %s: %s\n", 2894 XPR(NT "error reading source %s: %s\n",
2893 sfile->filename, 2895 sfile->filename,
2894 xd3_mainerror (ret)); 2896 xd3_mainerror (ret));
2895 2897
2896 return ret; 2898 return ret;
@@ -2931,7 +2933,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2931 lru[0].blkno = 0; 2933 lru[0].blkno = 0;
2932 lru[0].size = source->onblk; 2934 lru[0].size = source->onblk;
2933 2935
2934 if (! sfile->size_known) 2936 if (! sfile->size_known)
2935 { 2937 {
2936 do_not_lru = 1; 2938 do_not_lru = 1;
2937 } 2939 }
@@ -2949,14 +2951,14 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2949 ret = ENOMEM; 2951 ret = ENOMEM;
2950 return ret; 2952 return ret;
2951 } 2953 }
2952 2954
2953 if (do_not_lru == 0) 2955 if (do_not_lru == 0)
2954 { 2956 {
2955 main_blklru_list_push_back (& lru_free, & lru[i]); 2957 main_blklru_list_push_back (& lru_free, & lru[i]);
2956 } 2958 }
2957 } 2959 }
2958 2960
2959 if (sfile->size_known) 2961 if (sfile->size_known)
2960 { 2962 {
2961 ret = xd3_set_source_and_size (stream, source, source_size); 2963 ret = xd3_set_source_and_size (stream, source, source_size);
2962 } 2964 }
@@ -2984,7 +2986,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2984 2986
2985 if (sfile->size_known) 2987 if (sfile->size_known)
2986 { 2988 {
2987 sprintf (srcszbuf, "source size %s [%"Q"u]", 2989 sprintf (srcszbuf, "source size %s [%"Q"u]",
2988 main_format_bcnt (source_size, srccntbuf), 2990 main_format_bcnt (source_size, srccntbuf),
2989 source_size); 2991 source_size);
2990 } 2992 }
@@ -2994,7 +2996,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd,
2994 } 2996 }
2995 2997
2996 nbufs[0] = 0; 2998 nbufs[0] = 0;
2997 2999
2998 if (option_verbose > 1) 3000 if (option_verbose > 1)
2999 { 3001 {
3000 sprintf(nbufs, " #bufs %u", lru_size); 3002 sprintf(nbufs, " #bufs %u", lru_size);
@@ -3027,8 +3029,8 @@ main_get_winsize (main_file *ifile) {
3027 3029
3028 if (option_verbose > 1) 3030 if (option_verbose > 1)
3029 { 3031 {
3030 XPR(NT "input %s window size %s\n", 3032 XPR(NT "input %s window size %s\n",
3031 ifile->filename, 3033 ifile->filename,
3032 main_format_bcnt (size, iszbuf)); 3034 main_format_bcnt (size, iszbuf));
3033 } 3035 }
3034 3036
@@ -3080,12 +3082,12 @@ main_getblk_lru (xd3_source *source, xoff_t blkno, main_blklru** blrup, int *is_
3080 } 3082 }
3081 } 3083 }
3082 3084
3083 if (do_not_lru) 3085 if (do_not_lru)
3084 { 3086 {
3085 int idx = blkno % lru_size; 3087 int idx = blkno % lru_size;
3086 blru = & lru[idx]; 3088 blru = & lru[idx];
3087 } 3089 }
3088 else 3090 else
3089 { 3091 {
3090 if (! main_blklru_list_empty (& lru_free)) 3092 if (! main_blklru_list_empty (& lru_free))
3091 { 3093 {
@@ -3140,7 +3142,7 @@ main_getblk_func (xd3_stream *stream,
3140 return ret; 3142 return ret;
3141 } 3143 }
3142 3144
3143 if (!is_new) 3145 if (!is_new)
3144 { 3146 {
3145 source->curblkno = blkno; 3147 source->curblkno = blkno;
3146 source->onblk = blru->size; 3148 source->onblk = blru->size;
@@ -3180,18 +3182,19 @@ main_getblk_func (xd3_stream *stream,
3180 if (option_verbose) 3182 if (option_verbose)
3181 { 3183 {
3182 XPR(NT "source can't seek backwards; requested block offset " 3184 XPR(NT "source can't seek backwards; requested block offset "
3183 "%"Q"u source position is %"Q"u\n", 3185 "%"Q"u source position is %"Q"u\n",
3184 pos, sfile->source_position); 3186 pos, sfile->source_position);
3185 } 3187 }
3186 3188
3187 sfile->seek_failed = 1; 3189 sfile->seek_failed = 1;
3188 stream->msg = "non-seekable source: copy is too far back (try raising -B)"; 3190 stream->msg = "non-seekable source: "
3191 "copy is too far back (try raising -B)";
3189 return XD3_TOOFARBACK; 3192 return XD3_TOOFARBACK;
3190 } 3193 }
3191 3194
3192 if (option_verbose > 2 || (option_verbose > 1 && !sfile->seek_failed)) 3195 if (option_verbose > 2 || (option_verbose > 1 && !sfile->seek_failed))
3193 { 3196 {
3194 XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n", 3197 XPR(NT "non-seekable source skipping %"Q"u bytes @ %"Q"u\n",
3195 pos - sfile->source_position, 3198 pos - sfile->source_position,
3196 sfile->source_position); 3199 sfile->source_position);
3197 } 3200 }
@@ -3218,8 +3221,8 @@ main_getblk_func (xd3_stream *stream,
3218 3221
3219 if ((ret = main_read_primary_input (sfile, 3222 if ((ret = main_read_primary_input (sfile,
3220 (uint8_t*) blru->blk, 3223 (uint8_t*) blru->blk,
3221 source->blksize, 3224 source->blksize,
3222 & nread, 3225 & nread,
3223 1 /* source */))) 3226 1 /* source */)))
3224 { 3227 {
3225 return ret; 3228 return ret;
@@ -3235,7 +3238,7 @@ main_getblk_func (xd3_stream *stream,
3235 sfile->source_position += nread; 3238 sfile->source_position += nread;
3236 blru->size = nread; 3239 blru->size = nread;
3237 3240
3238 IF_DEBUG1 (DP(RINT "[getblk] skip blkno %"Q"u {%"Q"u} size %u\n", 3241 IF_DEBUG1 (DP(RINT "[getblk] skip blkno %"Q"u {%"Q"u} size %u\n",
3239 skip_blkno, blru->blkno, blru->size)); 3242 skip_blkno, blru->blkno, blru->size));
3240 3243
3241 XD3_ASSERT (sfile->source_position <= pos); 3244 XD3_ASSERT (sfile->source_position <= pos);
@@ -3250,9 +3253,9 @@ main_getblk_func (xd3_stream *stream,
3250 return ret; 3253 return ret;
3251 } 3254 }
3252 3255
3253 if ((ret = main_read_primary_input (sfile, 3256 if ((ret = main_read_primary_input (sfile,
3254 (uint8_t*) blru->blk, 3257 (uint8_t*) blru->blk,
3255 source->blksize, 3258 source->blksize,
3256 & nread, 3259 & nread,
3257 1 /* source */))) 3260 1 /* source */)))
3258 { 3261 {
@@ -3461,7 +3464,7 @@ main_input (xd3_cmd cmd,
3461 } 3464 }
3462 3465
3463#if VCDIFF_TOOLS 3466#if VCDIFF_TOOLS
3464 if ((cmd == CMD_MERGE || cmd == CMD_MERGE_ARG) && 3467 if ((cmd == CMD_MERGE || cmd == CMD_MERGE_ARG) &&
3465 (ret = xd3_whole_state_init (& stream))) 3468 (ret = xd3_whole_state_init (& stream)))
3466 { 3469 {
3467 XPR(NT XD3_LIB_ERRMSG (& stream, ret)); 3470 XPR(NT XD3_LIB_ERRMSG (& stream, ret));
@@ -3473,7 +3476,7 @@ main_input (xd3_cmd cmd,
3473 { 3476 {
3474 /* When not decoding, set source now. The decoder delays this 3477 /* When not decoding, set source now. The decoder delays this
3475 * step until XD3_GOTHEADER. */ 3478 * step until XD3_GOTHEADER. */
3476 if (sfile && sfile->filename != NULL) 3479 if (sfile && sfile->filename != NULL)
3477 { 3480 {
3478 if ((ret = main_set_source (& stream, cmd, sfile, & source))) 3481 if ((ret = main_set_source (& stream, cmd, sfile, & source)))
3479 { 3482 {
@@ -3483,7 +3486,7 @@ main_input (xd3_cmd cmd,
3483 XD3_ASSERT(stream.src != NULL); 3486 XD3_ASSERT(stream.src != NULL);
3484 } 3487 }
3485 } 3488 }
3486 3489
3487 if (cmd == CMD_PRINTHDR || 3490 if (cmd == CMD_PRINTHDR ||
3488 cmd == CMD_PRINTHDRS || 3491 cmd == CMD_PRINTHDRS ||
3489 cmd == CMD_PRINTDELTA || 3492 cmd == CMD_PRINTDELTA ||
@@ -3593,7 +3596,7 @@ main_input (xd3_cmd cmd,
3593 { 3596 {
3594 return EXIT_FAILURE; 3597 return EXIT_FAILURE;
3595 } 3598 }
3596 3599
3597 if ((ret = output_func (& stream, ofile)) && 3600 if ((ret = output_func (& stream, ofile)) &&
3598 (ret != PRINTHDR_SPECIAL)) 3601 (ret != PRINTHDR_SPECIAL))
3599 { 3602 {
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c
index 3a053ed..98c0e57 100644
--- a/xdelta3/xdelta3.c
+++ b/xdelta3/xdelta3.c
@@ -1,6 +1,6 @@
1/* xdelta 3 - delta compression tools and library 1/* xdelta 3 - delta compression tools and library
2 * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2 * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007,
3 * 2008, 2009. Joshua P. MacDonald 3 * 2008, 2009, 2010. Joshua P. MacDonald
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -540,7 +540,8 @@ static usize_t xd3_smatch (xd3_stream *stream,
540 usize_t scksum, 540 usize_t scksum,
541 usize_t *match_offset); 541 usize_t *match_offset);
542static int xd3_string_match_init (xd3_stream *stream); 542static int xd3_string_match_init (xd3_stream *stream);
543static uint32_t xd3_scksum (uint32_t *state, const uint8_t *seg, const usize_t ln); 543static uint32_t xd3_scksum (uint32_t *state, const uint8_t *seg,
544 const usize_t ln);
544static usize_t xd3_comprun (const uint8_t *seg, usize_t slook, uint8_t *run_cp); 545static usize_t xd3_comprun (const uint8_t *seg, usize_t slook, uint8_t *run_cp);
545static int xd3_srcwin_move_point (xd3_stream *stream, 546static int xd3_srcwin_move_point (xd3_stream *stream,
546 usize_t *next_move_point); 547 usize_t *next_move_point);
@@ -764,9 +765,9 @@ const xd3_sec_type fgk_sec_type =
764 (xd3_sec_stream* (*)(xd3_stream*)) fgk_alloc, 765 (xd3_sec_stream* (*)(xd3_stream*)) fgk_alloc,
765 (void (*)(xd3_stream*, xd3_sec_stream*)) fgk_destroy, 766 (void (*)(xd3_stream*, xd3_sec_stream*)) fgk_destroy,
766 (void (*)(xd3_sec_stream*)) fgk_init, 767 (void (*)(xd3_sec_stream*)) fgk_init,
767 (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*, 768 (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*,
768 uint8_t**, const uint8_t*)) xd3_decode_fgk, 769 uint8_t**, const uint8_t*)) xd3_decode_fgk,
769 IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*, 770 IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*,
770 xd3_output*, xd3_sec_cfg*)) xd3_encode_fgk) 771 xd3_output*, xd3_sec_cfg*)) xd3_encode_fgk)
771}; 772};
772#endif 773#endif
@@ -781,9 +782,9 @@ const xd3_sec_type djw_sec_type =
781 (xd3_sec_stream* (*)(xd3_stream*)) djw_alloc, 782 (xd3_sec_stream* (*)(xd3_stream*)) djw_alloc,
782 (void (*)(xd3_stream*, xd3_sec_stream*)) djw_destroy, 783 (void (*)(xd3_stream*, xd3_sec_stream*)) djw_destroy,
783 (void (*)(xd3_sec_stream*)) djw_init, 784 (void (*)(xd3_sec_stream*)) djw_init,
784 (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*, 785 (int (*)(xd3_stream*, xd3_sec_stream*, const uint8_t**, const uint8_t*,
785 uint8_t**, const uint8_t*)) xd3_decode_huff, 786 uint8_t**, const uint8_t*)) xd3_decode_huff,
786 IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*, 787 IF_ENCODER((int (*)(xd3_stream*, xd3_sec_stream*, xd3_output*,
787 xd3_output*, xd3_sec_cfg*)) xd3_encode_huff) 788 xd3_output*, xd3_sec_cfg*)) xd3_encode_huff)
788}; 789};
789#endif 790#endif
@@ -1251,7 +1252,7 @@ static usize_t __alternate_code_table_compressed_size;
1251/* This function generates a delta describing the code table for 1252/* This function generates a delta describing the code table for
1252 * encoding within a VCDIFF file. This function is NOT thread safe 1253 * encoding within a VCDIFF file. This function is NOT thread safe
1253 * because it is only intended that this function is used to generate 1254 * because it is only intended that this function is used to generate
1254 * statically-compiled strings. "comp_string" must be sized 1255 * statically-compiled strings. "comp_string" must be sized
1255 * CODE_TABLE_VCDIFF_SIZE. */ 1256 * CODE_TABLE_VCDIFF_SIZE. */
1256int xd3_compute_code_table_encoding (xd3_stream *in_stream, 1257int xd3_compute_code_table_encoding (xd3_stream *in_stream,
1257 const xd3_dinst *code_table, 1258 const xd3_dinst *code_table,
@@ -1451,7 +1452,7 @@ xd3_apply_table_encoding (xd3_stream *in_stream, const uint8_t *data, usize_t si
1451 1452
1452 xd3_compute_code_table_string (xd3_rfc3284_code_table (), dflt_string); 1453 xd3_compute_code_table_string (xd3_rfc3284_code_table (), dflt_string);
1453 1454
1454 if ((ret = xd3_decode_memory (data, size, 1455 if ((ret = xd3_decode_memory (data, size,
1455 dflt_string, CODE_TABLE_STRING_SIZE, 1456 dflt_string, CODE_TABLE_STRING_SIZE,
1456 code_string, &code_size, 1457 code_string, &code_size,
1457 CODE_TABLE_STRING_SIZE, 1458 CODE_TABLE_STRING_SIZE,
@@ -1623,9 +1624,9 @@ xd3_decode_bytes (xd3_stream *stream, uint8_t *buf, usize_t *pos, usize_t size)
1623 usize_t want; 1624 usize_t want;
1624 usize_t take; 1625 usize_t take;
1625 1626
1626 /* Note: The case where (*pos == size) happens when a zero-length appheader or code 1627 /* Note: The case where (*pos == size) happens when a zero-length
1627 * table is transmitted, but there is nothing in the standard against that. */ 1628 * appheader or code table is transmitted, but there is nothing in
1628 1629 * the standard against that. */
1629 while (*pos < size) 1630 while (*pos < size)
1630 { 1631 {
1631 if (stream->avail_in == 0) 1632 if (stream->avail_in == 0)
@@ -1918,7 +1919,10 @@ xd3_update_cache (xd3_addr_cache* acache, usize_t addr)
1918#if XD3_ENCODER 1919#if XD3_ENCODER
1919/* OPT: this gets called a lot, can it be optimized? */ 1920/* OPT: this gets called a lot, can it be optimized? */
1920static int 1921static int
1921xd3_encode_address (xd3_stream *stream, usize_t addr, usize_t here, uint8_t* mode) 1922xd3_encode_address (xd3_stream *stream,
1923 usize_t addr,
1924 usize_t here,
1925 uint8_t* mode)
1922{ 1926{
1923 usize_t d, bestd; 1927 usize_t d, bestd;
1924 usize_t i, bestm, ret; 1928 usize_t i, bestm, ret;
@@ -1948,7 +1952,7 @@ xd3_encode_address (xd3_stream *stream, usize_t addr, usize_t here, uint8_t* mod
1948 { 1952 {
1949 /* Note: If we used signed computation here, we'd could compte d 1953 /* Note: If we used signed computation here, we'd could compte d
1950 * and then check (d >= 0 && d < bestd). */ 1954 * and then check (d >= 0 && d < bestd). */
1951 if (addr >= acache->near_array[i]) 1955 if (addr >= acache->near_array[i])
1952 { 1956 {
1953 d = addr - acache->near_array[i]; 1957 d = addr - acache->near_array[i];
1954 1958
@@ -1962,18 +1966,26 @@ xd3_encode_address (xd3_stream *stream, usize_t addr, usize_t here, uint8_t* mod
1962 } 1966 }
1963 } 1967 }
1964 1968
1965 if (acache->s_same > 0 && acache->same_array[d = addr%(acache->s_same*256)] == addr) 1969 if (acache->s_same > 0 &&
1970 acache->same_array[d = addr%(acache->s_same*256)] == addr)
1966 { 1971 {
1967 bestd = d%256; 1972 bestd = d%256;
1968 bestm = acache->s_near + 2 + d/256; /* 2 + s_near offsets past the VCD_NEAR modes */ 1973 /* 2 + s_near offsets past the VCD_NEAR modes */
1974 bestm = acache->s_near + 2 + d/256;
1969 1975
1970 if ((ret = xd3_emit_byte (stream, & ADDR_TAIL (stream), bestd))) { return ret; } 1976 if ((ret = xd3_emit_byte (stream, & ADDR_TAIL (stream), bestd)))
1977 {
1978 return ret;
1979 }
1971 } 1980 }
1972 else 1981 else
1973 { 1982 {
1974 good: 1983 good:
1975 1984
1976 if ((ret = xd3_emit_size (stream, & ADDR_TAIL (stream), bestd))) { return ret; } 1985 if ((ret = xd3_emit_size (stream, & ADDR_TAIL (stream), bestd)))
1986 {
1987 return ret;
1988 }
1977 } 1989 }
1978 1990
1979 xd3_update_cache (acache, addr); 1991 xd3_update_cache (acache, addr);
@@ -2054,7 +2066,7 @@ xd3_alloc (xd3_stream *stream,
2054 if (a != NULL) 2066 if (a != NULL)
2055 { 2067 {
2056 IF_DEBUG (stream->alloc_cnt += 1); 2068 IF_DEBUG (stream->alloc_cnt += 1);
2057 IF_DEBUG2 (DP(RINT "[stream %p malloc] size %u ptr %p\n", 2069 IF_DEBUG2 (DP(RINT "[stream %p malloc] size %u ptr %p\n",
2058 stream, elts * size, a)); 2070 stream, elts * size, a));
2059 } 2071 }
2060 else 2072 else
@@ -2073,7 +2085,7 @@ xd3_free (xd3_stream *stream,
2073 { 2085 {
2074 IF_DEBUG (stream->free_cnt += 1); 2086 IF_DEBUG (stream->free_cnt += 1);
2075 XD3_ASSERT (stream->free_cnt <= stream->alloc_cnt); 2087 XD3_ASSERT (stream->free_cnt <= stream->alloc_cnt);
2076 IF_DEBUG2 (DP(RINT "[stream %p free] %p\n", 2088 IF_DEBUG2 (DP(RINT "[stream %p free] %p\n",
2077 stream, ptr)); 2089 stream, ptr));
2078 stream->free (stream->opaque, ptr); 2090 stream->free (stream->opaque, ptr);
2079 } 2091 }
@@ -2109,12 +2121,14 @@ xd3_alloc_output (xd3_stream *stream,
2109 } 2121 }
2110 else 2122 else
2111 { 2123 {
2112 if ((output = (xd3_output*) xd3_alloc (stream, 1, sizeof (xd3_output))) == NULL) 2124 if ((output = (xd3_output*) xd3_alloc (stream, 1,
2125 sizeof (xd3_output))) == NULL)
2113 { 2126 {
2114 return NULL; 2127 return NULL;
2115 } 2128 }
2116 2129
2117 if ((base = (uint8_t*) xd3_alloc (stream, XD3_ALLOCSIZE, sizeof (uint8_t))) == NULL) 2130 if ((base = (uint8_t*) xd3_alloc (stream, XD3_ALLOCSIZE,
2131 sizeof (uint8_t))) == NULL)
2118 { 2132 {
2119 xd3_free (stream, output); 2133 xd3_free (stream, output);
2120 return NULL; 2134 return NULL;
@@ -2448,7 +2462,7 @@ xd3_config_stream(xd3_stream *stream,
2448 2462
2449 switch (level) 2463 switch (level)
2450 { 2464 {
2451 case 1: 2465 case 1:
2452 IF_BUILD_FASTEST(*smatcher = __smatcher_fastest; 2466 IF_BUILD_FASTEST(*smatcher = __smatcher_fastest;
2453 break;) 2467 break;)
2454 case 2: 2468 case 2:
@@ -2478,7 +2492,7 @@ xd3_config_stream(xd3_stream *stream,
2478 return 0; 2492 return 0;
2479} 2493}
2480 2494
2481/***************************************************************** 2495/***********************************************************
2482 Getblk interface 2496 Getblk interface
2483 ***********************************************************/ 2497 ***********************************************************/
2484 2498
@@ -2492,7 +2506,7 @@ xoff_t xd3_source_eof(const xd3_source *src)
2492inline 2506inline
2493usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno) 2507usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno)
2494{ 2508{
2495 usize_t r = (blkno == src->max_blkno ? 2509 usize_t r = (blkno == src->max_blkno ?
2496 src->onlastblk : 2510 src->onlastblk :
2497 src->blksize); 2511 src->blksize);
2498 return r; 2512 return r;
@@ -2515,15 +2529,15 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno)
2515 stream->msg = "getblk source input"; 2529 stream->msg = "getblk source input";
2516 return XD3_GETSRCBLK; 2530 return XD3_GETSRCBLK;
2517 } 2531 }
2518 2532
2519 ret = stream->getblk (stream, source, blkno); 2533 ret = stream->getblk (stream, source, blkno);
2520 if (ret != 0) 2534 if (ret != 0)
2521 { 2535 {
2522 IF_DEBUG1 (DP(RINT "[getblk] app error: %s\n", xd3_strerror (ret))); 2536 IF_DEBUG1 (DP(RINT "[getblk] app error: %s\n", xd3_strerror (ret)));
2523 return ret; 2537 return ret;
2524 } 2538 }
2525 } 2539 }
2526 2540
2527 if (blkno >= source->frontier_blkno) 2541 if (blkno >= source->frontier_blkno)
2528 { 2542 {
2529 source->max_blkno = blkno; 2543 source->max_blkno = blkno;
@@ -2533,13 +2547,13 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno)
2533 { 2547 {
2534 source->frontier_blkno = blkno + 1; 2548 source->frontier_blkno = blkno + 1;
2535 2549
2536 IF_DEBUG2 (DP(RINT "[getblk] full source blkno %"Q"u: source length unknown %"Q"u\n", 2550 IF_DEBUG2 (DP(RINT "[getblk] full source blkno %"Q"u: source length unknown %"Q"u\n",
2537 blkno, 2551 blkno,
2538 xd3_source_eof (source))); 2552 xd3_source_eof (source)));
2539 } 2553 }
2540 else 2554 else
2541 { 2555 {
2542 if (!source->eof_known) 2556 if (!source->eof_known)
2543 { 2557 {
2544 IF_DEBUG2 (DP(RINT "[getblk] eof block has %d bytes; source length known %"Q"u\n", 2558 IF_DEBUG2 (DP(RINT "[getblk] eof block has %d bytes; source length known %"Q"u\n",
2545 xd3_bytes_on_srcblk (source, blkno), 2559 xd3_bytes_on_srcblk (source, blkno),
@@ -2552,7 +2566,7 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno)
2552 } 2566 }
2553 2567
2554 XD3_ASSERT (source->curblk != NULL); 2568 XD3_ASSERT (source->curblk != NULL);
2555 IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q"u onblk %u blksize %u\n", 2569 IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q"u onblk %u blksize %u\n",
2556 blkno, source->onblk, source->blksize)); 2570 blkno, source->onblk, source->blksize));
2557 2571
2558 if (blkno == source->max_blkno) 2572 if (blkno == source->max_blkno)
@@ -2609,7 +2623,7 @@ xd3_set_source_and_size (xd3_stream *stream, xd3_source *user_source, xoff_t sou
2609 source_size)); 2623 source_size));
2610 2624
2611 xd3_blksize_div(source_size, 2625 xd3_blksize_div(source_size,
2612 stream->src, 2626 stream->src,
2613 &stream->src->max_blkno, 2627 &stream->src->max_blkno,
2614 &stream->src->onlastblk); 2628 &stream->src->onlastblk);
2615 } 2629 }
@@ -2773,7 +2787,7 @@ xd3_iopt_finish_encoding (xd3_stream *stream, xd3_rinst *inst)
2773 } 2787 }
2774 else 2788 else
2775 { 2789 {
2776 stream->srcwin_decided_early = (!stream->src->eof_known || 2790 stream->srcwin_decided_early = (!stream->src->eof_known ||
2777 (stream->srcwin_cksum_pos < xd3_source_eof (stream->src))); 2791 (stream->srcwin_cksum_pos < xd3_source_eof (stream->src)));
2778 } 2792 }
2779 2793
@@ -2804,7 +2818,7 @@ xd3_iopt_finish_encoding (xd3_stream *stream, xd3_rinst *inst)
2804 /* Note: used to assert inst->size >= MIN_MATCH, but not true 2818 /* Note: used to assert inst->size >= MIN_MATCH, but not true
2805 * for merge operations & identical match heuristics. */ 2819 * for merge operations & identical match heuristics. */
2806 /* the "here" position is always offset by taroff */ 2820 /* the "here" position is always offset by taroff */
2807 if ((ret = xd3_encode_address (stream, addr, inst->pos + stream->taroff, 2821 if ((ret = xd3_encode_address (stream, addr, inst->pos + stream->taroff,
2808 & inst->type))) 2822 & inst->type)))
2809 { 2823 {
2810 return ret; 2824 return ret;
@@ -3609,7 +3623,8 @@ xd3_encode_init (xd3_stream *stream, int full_init)
3609 * identical or short inputs require no table allocation. */ 3623 * identical or short inputs require no table allocation. */
3610 if (large_comp) 3624 if (large_comp)
3611 { 3625 {
3612 usize_t hash_values = (stream->srcwin_maxsz / stream->smatcher.large_step); 3626 usize_t hash_values = (stream->srcwin_maxsz /
3627 stream->smatcher.large_step);
3613 3628
3614 xd3_size_hashtable (stream, 3629 xd3_size_hashtable (stream,
3615 hash_values, 3630 hash_values,
@@ -3780,7 +3795,7 @@ xd3_encode_input (xd3_stream *stream)
3780 return XD3_WINSTART; 3795 return XD3_WINSTART;
3781 3796
3782 case ENC_SEARCH: 3797 case ENC_SEARCH:
3783 IF_DEBUG2 (DP(RINT "[SEARCH] match_state %d avail_in %u %s\n", 3798 IF_DEBUG2 (DP(RINT "[SEARCH] match_state %d avail_in %u %s\n",
3784 stream->match_state, stream->avail_in, stream->src ? "source" : "no source")); 3799 stream->match_state, stream->avail_in, stream->src ? "source" : "no source"));
3785 3800
3786 /* Reentrant matching. */ 3801 /* Reentrant matching. */
@@ -3795,7 +3810,7 @@ xd3_encode_input (xd3_stream *stream)
3795 * that extends to the end of the previous window. The 3810 * that extends to the end of the previous window. The
3796 * match_srcpos field is initially zero and later set 3811 * match_srcpos field is initially zero and later set
3797 * during xd3_source_extend_match. */ 3812 * during xd3_source_extend_match. */
3798 3813
3799 if (stream->avail_in > 0) 3814 if (stream->avail_in > 0)
3800 { 3815 {
3801 /* This call can't fail because the source window is 3816 /* This call can't fail because the source window is
@@ -3824,7 +3839,7 @@ xd3_encode_input (xd3_stream *stream)
3824 * or else it can get stuck in a match-backward 3839 * or else it can get stuck in a match-backward
3825 * (getsrcblk) then match-forward (getsrcblk), 3840 * (getsrcblk) then match-forward (getsrcblk),
3826 * find insufficient match length, then repeat 3841 * find insufficient match length, then repeat
3827 * exactly the same search. 3842 * exactly the same search.
3828 */ 3843 */
3829 stream->input_position += stream->match_fwd; 3844 stream->input_position += stream->match_fwd;
3830 } 3845 }
@@ -3962,7 +3977,7 @@ xd3_process_stream (int is_encode,
3962 3977
3963 (*output_size) = 0; 3978 (*output_size) = 0;
3964 3979
3965 stream->flags |= XD3_FLUSH; 3980 stream->flags |= XD3_FLUSH;
3966 3981
3967 xd3_avail_input (stream, input + ipos, n); 3982 xd3_avail_input (stream, input + ipos, n);
3968 ipos += n; 3983 ipos += n;
@@ -4085,7 +4100,7 @@ xd3_process_memory (int is_encode,
4085 } 4100 }
4086 4101
4087 exit: 4102 exit:
4088 if (ret != 0) 4103 if (ret != 0)
4089 { 4104 {
4090 IF_DEBUG2 (DP(RINT "process_memory: %d: %s\n", ret, stream.msg)); 4105 IF_DEBUG2 (DP(RINT "process_memory: %d: %s\n", ret, stream.msg));
4091 } 4106 }
@@ -4303,7 +4318,8 @@ xd3_srcwin_setup (xd3_stream *stream)
4303 * issued, but we have to decide the source window base and length 4318 * issued, but we have to decide the source window base and length
4304 * now. */ 4319 * now. */
4305 src->srcbase = stream->match_minaddr; 4320 src->srcbase = stream->match_minaddr;
4306 src->srclen = max ((usize_t) length, stream->avail_in + (stream->avail_in >> 2)); 4321 src->srclen = max ((usize_t) length,
4322 stream->avail_in + (stream->avail_in >> 2));
4307 4323
4308 /* OPT: If we know the source size, it might be possible to reduce 4324 /* OPT: If we know the source size, it might be possible to reduce
4309 * srclen. */ 4325 * srclen. */
@@ -4346,6 +4362,17 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
4346 goto bad; 4362 goto bad;
4347 } 4363 }
4348 4364
4365 /* Implement srcwin_maxsz, which prevents the encoder from seeking
4366 * back further than the LRU cache maintaining FIFO discipline,
4367 * which causes terrible performance. */
4368 if (xd3_source_eof (stream->src) - srcpos > stream->srcwin_maxsz) {
4369 IF_DEBUG1(DP(RINT "[match_setup] rejected due to srcwin_maxsz "
4370 "distance eof=%"Q"u srcpos=%"Q"u maxsz=%u\n",
4371 xd3_source_eof (stream->src),
4372 srcpos, stream->srcwin_maxsz));
4373 goto bad;
4374 }
4375
4349 /* Going backwards, the 1.5-pass algorithm allows some 4376 /* Going backwards, the 1.5-pass algorithm allows some
4350 * already-matched input may be covered by a longer source match. 4377 * already-matched input may be covered by a longer source match.
4351 * The greedy algorithm does not allow this. */ 4378 * The greedy algorithm does not allow this. */
@@ -4396,8 +4423,11 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
4396 } 4423 }
4397 } 4424 }
4398 4425
4399 IF_DEBUG2(DP(RINT "[match_setup] srcpos %"Q"u unrestricted back %u fwd %u\n", 4426 IF_DEBUG1(DP(RINT
4427 "[match_setup] srcpos %"Q"u (tgtpos %"Q"u) "
4428 "unrestricted maxback %u maxfwd %u\n",
4400 srcpos, 4429 srcpos,
4430 stream->total_in + stream->input_position,
4401 stream->match_maxback, 4431 stream->match_maxback,
4402 stream->match_maxfwd)); 4432 stream->match_maxfwd));
4403 goto good; 4433 goto good;
@@ -4407,9 +4437,10 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
4407 XD3_ASSERT (src->srclen > 0); 4437 XD3_ASSERT (src->srclen > 0);
4408 4438
4409 /* Restricted case: fail if the srcpos lies outside the source window */ 4439 /* Restricted case: fail if the srcpos lies outside the source window */
4410 if ((srcpos < src->srcbase) || (srcpos > (src->srcbase + (xoff_t) src->srclen))) 4440 if ((srcpos < src->srcbase) ||
4441 (srcpos > (src->srcbase + (xoff_t) src->srclen)))
4411 { 4442 {
4412 IF_DEBUG2(DP(RINT "[match_setup] restricted source window failure\n")); 4443 IF_DEBUG1(DP(RINT "[match_setup] restricted source window failure\n"));
4413 goto bad; 4444 goto bad;
4414 } 4445 }
4415 else 4446 else
@@ -4428,8 +4459,11 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
4428 stream->match_maxfwd = srcavail; 4459 stream->match_maxfwd = srcavail;
4429 } 4460 }
4430 4461
4431 IF_DEBUG2(DP(RINT "[match_setup] srcpos %"Q"u restricted back %u fwd %u\n", 4462 IF_DEBUG1(DP(RINT
4463 "[match_setup] srcpos %"Q"u (tgtpos %"Q"u) "
4464 "restricted maxback %u maxfwd %u\n",
4432 srcpos, 4465 srcpos,
4466 stream->total_in + stream->input_position,
4433 stream->match_maxback, 4467 stream->match_maxback,
4434 stream->match_maxfwd)); 4468 stream->match_maxfwd));
4435 goto good; 4469 goto good;
@@ -4468,7 +4502,7 @@ xd3_forward_match(const uint8_t *s1c, const uint8_t *s2c, size_t n)
4468 s1[i++] == s2[j++] && 4502 s1[i++] == s2[j++] &&
4469 s1[i++] == s2[j++] && 4503 s1[i++] == s2[j++] &&
4470 s1[i++] == s2[j++] && 4504 s1[i++] == s2[j++] &&
4471 s1[i++] == s2[j++] && 4505 s1[i++] == s2[j++] &&
4472 s1[i++] == s2[j++]) { } 4506 s1[i++] == s2[j++]) { }
4473 4507
4474 i = (i - 1) * sizeof(int); 4508 i = (i - 1) * sizeof(int);
@@ -4519,7 +4553,7 @@ xd3_source_extend_match (xd3_stream *stream)
4519 usize_t tryrem; /* tryrem is the number of matchable bytes */ 4553 usize_t tryrem; /* tryrem is the number of matchable bytes */
4520 usize_t matched; 4554 usize_t matched;
4521 4555
4522 IF_DEBUG2(DP(RINT "[extend match] srcpos %"Q"u\n", 4556 IF_DEBUG2(DP(RINT "[extend match] srcpos %"Q"u\n",
4523 stream->match_srcpos)); 4557 stream->match_srcpos));
4524 4558
4525 XD3_ASSERT (src != NULL); 4559 XD3_ASSERT (src != NULL);
@@ -4556,7 +4590,7 @@ xd3_source_extend_match (xd3_stream *stream)
4556 } 4590 }
4557 4591
4558 tryrem = min (tryoff, stream->match_maxback - stream->match_back); 4592 tryrem = min (tryoff, stream->match_maxback - stream->match_back);
4559 4593
4560 IF_DEBUG2(DP(RINT "[maxback] maxback %u trysrc %"Q"u/%u tgt %u tryrem %u\n", 4594 IF_DEBUG2(DP(RINT "[maxback] maxback %u trysrc %"Q"u/%u tgt %u tryrem %u\n",
4561 stream->match_maxback, tryblk, tryoff, streamoff, tryrem)); 4595 stream->match_maxback, tryblk, tryoff, streamoff, tryrem));
4562 4596
@@ -4988,12 +5022,6 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
4988 */ 5022 */
4989 logical_input_cksum_pos += stream->src->blksize; 5023 logical_input_cksum_pos += stream->src->blksize;
4990 5024
4991 IF_DEBUG1 (DP(RINT "[srcwin_move_point] T=%"Q"u{%"Q"u} S=%"Q"u EOF=%"Q"u %s\n",
4992 stream->total_in + stream->input_position,
4993 logical_input_cksum_pos,
4994 stream->srcwin_cksum_pos,
4995 xd3_source_eof (stream->src),
4996 stream->src->eof_known ? "known" : "unknown"));
4997 while (stream->srcwin_cksum_pos < logical_input_cksum_pos && 5025 while (stream->srcwin_cksum_pos < logical_input_cksum_pos &&
4998 (!stream->src->eof_known || 5026 (!stream->src->eof_known ||
4999 stream->srcwin_cksum_pos < xd3_source_eof (stream->src))) 5027 stream->srcwin_cksum_pos < xd3_source_eof (stream->src)))
@@ -5016,14 +5044,26 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
5016 { 5044 {
5017 ret = XD3_INTERNAL; 5045 ret = XD3_INTERNAL;
5018 } 5046 }
5047 IF_DEBUG1 (DP(RINT
5048 "[srcwin_move_point] async getblk return for %"Q"u\n",
5049 blkno));
5019 return ret; 5050 return ret;
5020 } 5051 }
5021 5052
5053 IF_DEBUG1 (DP(RINT
5054 "[srcwin_move_point] T=%"Q"u{%"Q"u} S=%"Q"u EOF=%"Q"u %s\n",
5055 stream->total_in + stream->input_position,
5056 logical_input_cksum_pos,
5057 stream->srcwin_cksum_pos,
5058 xd3_source_eof (stream->src),
5059 stream->src->eof_known ? "known" : "unknown"));
5060
5022 blkpos = xd3_bytes_on_srcblk (stream->src, blkno); 5061 blkpos = xd3_bytes_on_srcblk (stream->src, blkno);
5023 5062
5024 if (blkpos < (ssize_t) stream->smatcher.large_look) 5063 if (blkpos < (ssize_t) stream->smatcher.large_look)
5025 { 5064 {
5026 stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; 5065 stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize;
5066 IF_DEBUG1 (DP(RINT "[srcwin_move_point] continue (end-of-block)\n"));
5027 continue; 5067 continue;
5028 } 5068 }
5029 5069
@@ -5058,15 +5098,25 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
5058 stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; 5098 stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize;
5059 } 5099 }
5060 5100
5101 IF_DEBUG1 (DP(RINT
5102 "[srcwin_move_point] exited loop T=%"Q"u{%"Q"u} S=%"Q"u EOF=%"Q"u %s\n",
5103 stream->total_in + stream->input_position,
5104 logical_input_cksum_pos,
5105 stream->srcwin_cksum_pos,
5106 xd3_source_eof (stream->src),
5107 stream->src->eof_known ? "known" : "unknown"));
5108
5061 if (stream->src->eof_known) 5109 if (stream->src->eof_known)
5062 { 5110 {
5063 source_size = xd3_source_eof (stream->src); 5111 source_size = xd3_source_eof (stream->src);
5064 5112
5065 if (stream->srcwin_cksum_pos >= source_size) 5113 if (stream->srcwin_cksum_pos >= source_size)
5066 { 5114 {
5067 /* This invariant is needed for xd3_source_cksum_offset() */ 5115 /* This invariant is needed for xd3_source_cksum_offset() */
5068 stream->srcwin_cksum_pos = source_size; 5116 stream->srcwin_cksum_pos = source_size;
5069 *next_move_point = USIZE_T_MAX; 5117 *next_move_point = USIZE_T_MAX;
5118 IF_DEBUG1 (DP(RINT
5119 "[srcwin_move_point] finished with source input\n"));
5070 return 0; 5120 return 0;
5071 } 5121 }
5072 } 5122 }
@@ -5260,7 +5310,7 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream)
5260 if (stream->large_table[linx] != 0) 5310 if (stream->large_table[linx] != 0)
5261 { 5311 {
5262 /* the match_setup will fail if the source window has 5312 /* the match_setup will fail if the source window has
5263 * been decided and the match lies outside it. 5313 * been decided and the match lies outside it.
5264 * OPT: Consider forcing a window at this point to 5314 * OPT: Consider forcing a window at this point to
5265 * permit a new source window. */ 5315 * permit a new source window. */
5266 xoff_t adj_offset = 5316 xoff_t adj_offset =
@@ -5357,7 +5407,7 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream)
5357 } 5407 }
5358 5408
5359 /* Compute next RUN, CKSUM */ 5409 /* Compute next RUN, CKSUM */
5360 if (DO_RUN) 5410 if (DO_RUN)
5361 { 5411 {
5362 NEXTRUN (inp[SLOOK]); 5412 NEXTRUN (inp[SLOOK]);
5363 } 5413 }
diff --git a/xdelta3/xdelta3.h b/xdelta3/xdelta3.h
index 5b99a72..f417dcf 100644
--- a/xdelta3/xdelta3.h
+++ b/xdelta3/xdelta3.h
@@ -1,5 +1,6 @@
1/* xdelta 3 - delta compression tools and library 1/* xdelta 3 - delta compression tools and library
2 * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007. Joshua P. MacDonald 2 * Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007,
3 * 2008, 2009, 2010. Joshua P. MacDonald
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -694,7 +695,8 @@ struct _xd3_config
694 buffer */ 695 buffer */
695 usize_t srcwin_maxsz; /* srcwin_size grows by a factor 696 usize_t srcwin_maxsz; /* srcwin_size grows by a factor
696 of 2 when no matches are 697 of 2 when no matches are
697 found */ 698 found. encoder will not seek
699 back further than this. */
698 700
699 xd3_getblk_func *getblk; /* The three callbacks. */ 701 xd3_getblk_func *getblk; /* The three callbacks. */
700 xd3_alloc_func *alloc; 702 xd3_alloc_func *alloc;
@@ -743,7 +745,7 @@ struct _xd3_source
743 xoff_t srcbase; /* offset of this source window 745 xoff_t srcbase; /* offset of this source window
744 in the source itself */ 746 in the source itself */
745 int shiftby; /* for power-of-two blocksizes */ 747 int shiftby; /* for power-of-two blocksizes */
746 int maskby; /* for power-of-two blocksizes */ 748 int maskby; /* for power-of-two blocksizes */
747 xoff_t cpyoff_blocks; /* offset of dec_cpyoff in blocks */ 749 xoff_t cpyoff_blocks; /* offset of dec_cpyoff in blocks */
748 usize_t cpyoff_blkoff; /* offset of copy window in 750 usize_t cpyoff_blkoff; /* offset of copy window in
749 blocks, remainder */ 751 blocks, remainder */
@@ -799,7 +801,7 @@ struct _xd3_stream
799 void* opaque; /* private data object passed to 801 void* opaque; /* private data object passed to
800 alloc, free, and getblk */ 802 alloc, free, and getblk */
801 int flags; /* various options */ 803 int flags; /* various options */
802 804
803 /* secondary compressor configuration */ 805 /* secondary compressor configuration */
804 xd3_sec_cfg sec_data; /* Secondary compressor config: data */ 806 xd3_sec_cfg sec_data; /* Secondary compressor config: data */
805 xd3_sec_cfg sec_inst; /* Secondary compressor config: inst */ 807 xd3_sec_cfg sec_inst; /* Secondary compressor config: inst */
@@ -1046,7 +1048,7 @@ int xd3_decode_memory (const uint8_t *input,
1046 * xd3_stream stream; 1048 * xd3_stream stream;
1047 * xd3_config config; 1049 * xd3_config config;
1048 * xd3_source src; 1050 * xd3_source src;
1049 * 1051 *
1050 * memset (& src, 0, sizeof (src)); 1052 * memset (& src, 0, sizeof (src));
1051 * memset (& stream, 0, sizeof (stream)); 1053 * memset (& stream, 0, sizeof (stream));
1052 * memset (& config, 0, sizeof (config)); 1054 * memset (& config, 0, sizeof (config));
@@ -1119,7 +1121,7 @@ int xd3_decode_stream (xd3_stream *stream,
1119 * assert(stream->current_window == 0); 1121 * assert(stream->current_window == 0);
1120 * stuff; 1122 * stuff;
1121 * } 1123 * }
1122 * // fallthrough 1124 * // fallthrough
1123 * case XD3_WINSTART: { 1125 * case XD3_WINSTART: {
1124 * something(stream->current_window); 1126 * something(stream->current_window);
1125 * goto again; 1127 * goto again;
@@ -1171,7 +1173,7 @@ void xd3_free_stream (xd3_stream *stream);
1171int xd3_set_source (xd3_stream *stream, 1173int xd3_set_source (xd3_stream *stream,
1172 xd3_source *source); 1174 xd3_source *source);
1173 1175
1174/* If the source size is known, call this instead of xd3_set_source(). 1176/* If the source size is known, call this instead of xd3_set_source().
1175 * to avoid having stream->getblk called (and/or to avoid XD3_GETSRCBLK). 1177 * to avoid having stream->getblk called (and/or to avoid XD3_GETSRCBLK).
1176 * 1178 *
1177 * Follow these steps: 1179 * Follow these steps:
@@ -1231,7 +1233,7 @@ void xd3_init_config (xd3_config *config,
1231 config->flags = flags; 1233 config->flags = flags;
1232} 1234}
1233 1235
1234/* This supplies some input to the stream. 1236/* This supplies some input to the stream.
1235 * 1237 *
1236 * For encoding, if the input is larger than the configured window 1238 * For encoding, if the input is larger than the configured window
1237 * size (xd3_config.winsize), the entire input will be consumed and 1239 * size (xd3_config.winsize), the entire input will be consumed and
@@ -1330,7 +1332,7 @@ void xd3_blksize_add (xoff_t *blkno,
1330 *blkoff += add; 1332 *blkoff += add;
1331 blkdiff = *blkoff >> source->shiftby; 1333 blkdiff = *blkoff >> source->shiftby;
1332 1334
1333 if (blkdiff) 1335 if (blkdiff)
1334 { 1336 {
1335 *blkno += blkdiff; 1337 *blkno += blkdiff;
1336 *blkoff &= source->maskby; 1338 *blkoff &= source->maskby;