summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjosh.macdonald <jmacd@users.noreply.github.com>2008-09-07 09:42:31 +0000
committerjosh.macdonald <jmacd@users.noreply.github.com>2008-09-07 09:42:31 +0000
commitb8630ef77dfe76039b3c54882750d694b81a13bd (patch)
treef11268362994adce782753592783a8e7ced1f318
parent16d481af9d05ece1a76c6f828ef4a64d1f039434 (diff)
Fixes two merge bugs:
1. The whole_state struct now keeps an array of window sizes so that during reconstruction it can use the same window size as the target delta. The code was previously using dec_tgtlen, which was the window size of the last target delta window. 2. xd3_merge_copy_source(), which applys a source-copy instruction during merge was not properly translating target-copy instructions in the target. The solution here is SLOW and INEFFICIENT, but it at least allows the tests to pass. A big TODO here is to improve the algorithm: it has a potentially O(N) recursion for each target-copy that it sees, and the naive approach also can produce duplicate adds.
-rw-r--r--xdelta3/xdelta3-main.h22
-rw-r--r--xdelta3/xdelta3-merge.h84
-rw-r--r--xdelta3/xdelta3.c1
-rw-r--r--xdelta3/xdelta3.h6
4 files changed, 97 insertions, 16 deletions
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h
index ae6fc19..46b2cfb 100644
--- a/xdelta3/xdelta3-main.h
+++ b/xdelta3/xdelta3-main.h
@@ -1265,7 +1265,7 @@ main_print_window (xd3_stream* stream, main_file *xfile)
1265 { 1265 {
1266 if (stream->dec_current1.addr >= stream->dec_cpylen) 1266 if (stream->dec_current1.addr >= stream->dec_cpylen)
1267 { 1267 {
1268 VC(UT " T@%-6"Q"u", 1268 VC(UT " T@%-6u",
1269 stream->dec_current1.addr - stream->dec_cpylen)VE; 1269 stream->dec_current1.addr - stream->dec_cpylen)VE;
1270 } 1270 }
1271 else 1271 else
@@ -1293,7 +1293,7 @@ main_print_window (xd3_stream* stream, main_file *xfile)
1293 { 1293 {
1294 if (stream->dec_current2.addr >= stream->dec_cpylen) 1294 if (stream->dec_current2.addr >= stream->dec_cpylen)
1295 { 1295 {
1296 VC(UT " T@%-6"Q"u", 1296 VC(UT " T@%-6u",
1297 stream->dec_current2.addr - stream->dec_cpylen)VE; 1297 stream->dec_current2.addr - stream->dec_cpylen)VE;
1298 } 1298 }
1299 else 1299 else
@@ -1794,6 +1794,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1794 usize_t inst_pos = 0; 1794 usize_t inst_pos = 0;
1795 xoff_t output_pos = 0; 1795 xoff_t output_pos = 0;
1796 xd3_source recode_source; 1796 xd3_source recode_source;
1797 usize_t window_num = 0;
1797 int at_least_once = 0; 1798 int at_least_once = 0;
1798 1799
1799 /* merge_stream is set if there were arguments. this stream's input 1800 /* merge_stream is set if there were arguments. this stream's input
@@ -1821,6 +1822,7 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1821 xoff_t window_srcmin = 0; 1822 xoff_t window_srcmin = 0;
1822 xoff_t window_srcmax = 0; 1823 xoff_t window_srcmax = 0;
1823 usize_t window_pos = 0; 1824 usize_t window_pos = 0;
1825 usize_t window_size;
1824 1826
1825 /* at_least_once ensures that we encode at least one window, 1827 /* at_least_once ensures that we encode at least one window,
1826 * which handles the 0-byte case. */ 1828 * which handles the 0-byte case. */
@@ -1834,25 +1836,31 @@ main_merge_output (xd3_stream *stream, main_file *ofile)
1834 return XD3_INVALID; 1836 return XD3_INVALID;
1835 } 1837 }
1836 1838
1837 if (main_bsize < stream->dec_tgtlen) 1839 /* Window sizes must match from the input to the output, so that
1840 * target copies are in-range (and so that checksums carry
1841 * over). */
1842 XD3_ASSERT (window_num < stream->whole_target.winsizeslen);
1843 window_size = stream->whole_target.winsizes[window_num++];
1844
1845 if (main_bsize < window_size)
1838 { 1846 {
1839 main_free (main_bdata); 1847 main_free (main_bdata);
1840 main_bdata = NULL; 1848 main_bdata = NULL;
1841 main_bsize = 0; 1849 main_bsize = 0;
1842 if ((main_bdata = (uint8_t*) 1850 if ((main_bdata = (uint8_t*)
1843 main_malloc (stream->dec_tgtlen)) == NULL) 1851 main_malloc (window_size)) == NULL)
1844 { 1852 {
1845 return ENOMEM; 1853 return ENOMEM;
1846 } 1854 }
1847 main_bsize = stream->dec_tgtlen; 1855 main_bsize = window_size;
1848 } 1856 }
1849 1857
1850 /* This encodes a single target window. */ 1858 /* This encodes a single target window. */
1851 while (window_pos < stream->dec_tgtlen && 1859 while (window_pos < window_size &&
1852 inst_pos < stream->whole_target.instlen) 1860 inst_pos < stream->whole_target.instlen)
1853 { 1861 {
1854 xd3_winst *inst = &stream->whole_target.inst[inst_pos]; 1862 xd3_winst *inst = &stream->whole_target.inst[inst_pos];
1855 usize_t take = min(inst->size, stream->dec_tgtlen - window_pos); 1863 usize_t take = min(inst->size, window_size - window_pos);
1856 xoff_t addr; 1864 xoff_t addr;
1857 1865
1858 switch (inst->type) 1866 switch (inst->type)
diff --git a/xdelta3/xdelta3-merge.h b/xdelta3/xdelta3-merge.h
index fefe55d..553fbf0 100644
--- a/xdelta3/xdelta3-merge.h
+++ b/xdelta3/xdelta3-merge.h
@@ -28,15 +28,19 @@ xd3_whole_state_init (xd3_stream *stream)
28{ 28{
29 XD3_ASSERT (stream->whole_target.adds == NULL); 29 XD3_ASSERT (stream->whole_target.adds == NULL);
30 XD3_ASSERT (stream->whole_target.inst == NULL); 30 XD3_ASSERT (stream->whole_target.inst == NULL);
31 XD3_ASSERT (stream->whole_target.winsizes == NULL);
31 XD3_ASSERT (stream->whole_target.length == 0); 32 XD3_ASSERT (stream->whole_target.length == 0);
32 33
33 stream->whole_target.adds_alloc = XD3_ALLOCSIZE; 34 stream->whole_target.adds_alloc = XD3_ALLOCSIZE;
34 stream->whole_target.inst_alloc = XD3_ALLOCSIZE / sizeof (xd3_winst); 35 stream->whole_target.inst_alloc = XD3_ALLOCSIZE;
36 stream->whole_target.winsizes_alloc = XD3_ALLOCSIZE;
35 37
36 if ((stream->whole_target.adds = (uint8_t*) 38 if ((stream->whole_target.adds = (uint8_t*)
37 xd3_alloc (stream, XD3_ALLOCSIZE, 1)) == NULL || 39 xd3_alloc (stream, stream->whole_target.adds_alloc, 1)) == NULL ||
38 (stream->whole_target.inst = (xd3_winst*) 40 (stream->whole_target.inst = (xd3_winst*)
39 xd3_alloc (stream, XD3_ALLOCSIZE, sizeof(xd3_winst))) == NULL) 41 xd3_alloc (stream, stream->whole_target.inst_alloc, 1)) == NULL ||
42 (stream->whole_target.winsizes = (usize_t*)
43 xd3_alloc (stream, stream->whole_target.winsizes_alloc, 1)) == NULL)
40 { 44 {
41 return ENOMEM; 45 return ENOMEM;
42 } 46 }
@@ -50,6 +54,7 @@ xd3_swap_whole_state (xd3_whole_state *a,
50 xd3_whole_state tmp; 54 xd3_whole_state tmp;
51 XD3_ASSERT (a->inst != NULL && a->adds != NULL); 55 XD3_ASSERT (a->inst != NULL && a->adds != NULL);
52 XD3_ASSERT (b->inst != NULL && b->adds != NULL); 56 XD3_ASSERT (b->inst != NULL && b->adds != NULL);
57 XD3_ASSERT (b->winsizes != NULL && b->winsizes != NULL);
53 memcpy (&tmp, a, sizeof (xd3_whole_state)); 58 memcpy (&tmp, a, sizeof (xd3_whole_state));
54 memcpy (a, b, sizeof (xd3_whole_state)); 59 memcpy (a, b, sizeof (xd3_whole_state));
55 memcpy (b, &tmp, sizeof (xd3_whole_state)); 60 memcpy (b, &tmp, sizeof (xd3_whole_state));
@@ -134,6 +139,27 @@ xd3_whole_alloc_adds (xd3_stream *stream,
134} 139}
135 140
136static int 141static int
142xd3_whole_alloc_winsize (xd3_stream *stream,
143 usize_t **winsizep)
144{
145 int ret;
146
147 if ((ret = xd3_realloc_buffer (stream,
148 stream->whole_target.winsizeslen,
149 sizeof (xd3_winst),
150 1,
151 & stream->whole_target.winsizes_alloc,
152 (void**) & stream->whole_target.winsizes)))
153 {
154 return ret;
155 }
156
157 *winsizep = &stream->whole_target.winsizes[stream->whole_target.winsizeslen++];
158
159 return 0;
160}
161
162static int
137xd3_whole_append_inst (xd3_stream *stream, 163xd3_whole_append_inst (xd3_stream *stream,
138 xd3_hinst *inst) 164 xd3_hinst *inst)
139{ 165{
@@ -197,8 +223,13 @@ int
197xd3_whole_append_window (xd3_stream *stream) 223xd3_whole_append_window (xd3_stream *stream)
198{ 224{
199 int ret; 225 int ret;
226 usize_t *winsize;
200 227
201 stream->whole_target.windows += 1; 228 stream->whole_target.windows += 1;
229
230 if ((ret = xd3_whole_alloc_winsize (stream, &winsize))) { return ret; }
231
232 *winsize = stream->dec_tgtlen;
202 233
203 while (stream->inst_sect.buf < stream->inst_sect.buf_max) 234 while (stream->inst_sect.buf < stream->inst_sect.buf_max)
204 { 235 {
@@ -325,7 +356,6 @@ xd3_merge_target_copy (xd3_stream *stream,
325 } 356 }
326 357
327 XD3_ASSERT (stream->whole_target.length == iinst->position); 358 XD3_ASSERT (stream->whole_target.length == iinst->position);
328 stream->whole_target.length += iinst->size;
329 359
330 memcpy (oinst, iinst, sizeof (*oinst)); 360 memcpy (oinst, iinst, sizeof (*oinst));
331 return 0; 361 return 0;
@@ -381,7 +411,7 @@ xd3_merge_find_position (xd3_stream *stream,
381static int 411static int
382xd3_merge_source_copy (xd3_stream *stream, 412xd3_merge_source_copy (xd3_stream *stream,
383 xd3_whole_state *source, 413 xd3_whole_state *source,
384 xd3_winst *iinst_orig) 414 const xd3_winst *iinst_orig)
385{ 415{
386 int ret; 416 int ret;
387 xd3_winst iinst; 417 xd3_winst iinst;
@@ -455,12 +485,35 @@ xd3_merge_source_copy (xd3_stream *stream,
455 stream->whole_target.addslen += this_take; 485 stream->whole_target.addslen += this_take;
456 break; 486 break;
457 default: 487 default:
458 minst->mode = sinst->mode; 488 if (sinst->mode != 0)
459 minst->addr = sinst->addr + sinst_offset; 489 {
490 minst->mode = sinst->mode;
491 minst->addr = sinst->addr + sinst_offset;
492 }
493 else
494 {
495 // TODO: this is slow because of the recursion, which
496 // could reach a depth equal to the number of target
497 // copies, and this is compression-inefficient because
498 // it can produce duplicate adds.
499 xd3_winst tinst;
500 tinst.type = XD3_CPY;
501 tinst.mode = iinst.mode;
502 tinst.addr = sinst->addr + sinst_offset;
503 tinst.size = this_take;
504 tinst.position = iinst.position;
505
506 // The instruction allocated in this frame will not be used.
507 stream->whole_target.instlen -= 1;
508
509 if ((ret = xd3_merge_source_copy (stream, source, &tinst)))
510 {
511 return ret;
512 }
513 }
460 break; 514 break;
461 } 515 }
462 516
463 stream->whole_target.length += this_take;
464 iinst.position += this_take; 517 iinst.position += this_take;
465 iinst.addr += this_take; 518 iinst.addr += this_take;
466 iinst.size -= this_take; 519 iinst.size -= this_take;
@@ -477,8 +530,17 @@ int xd3_merge_inputs (xd3_stream *stream,
477 xd3_whole_state *input) 530 xd3_whole_state *input)
478{ 531{
479 int ret = 0; 532 int ret = 0;
533 usize_t i;
480 size_t input_i; 534 size_t input_i;
481 535
536 for (i = 0; i < input->winsizeslen; ++i) {
537 usize_t *copysize;
538
539 if ((ret = xd3_whole_alloc_winsize (stream, &copysize))) { return ret; }
540
541 *copysize = input->winsizes[i];
542 }
543
482 /* iterate over each instruction. */ 544 /* iterate over each instruction. */
483 for (input_i = 0; ret == 0 && input_i < input->instlen; ++input_i) 545 for (input_i = 0; ret == 0 && input_i < input->instlen; ++input_i)
484 { 546 {
@@ -493,7 +555,7 @@ int xd3_merge_inputs (xd3_stream *stream,
493 ret = xd3_merge_add (stream, input, iinst); 555 ret = xd3_merge_add (stream, input, iinst);
494 break; 556 break;
495 default: 557 default:
496 /* Note: VCD_TARGET support is completely untested all 558 /* TODO: VCD_TARGET support is completely untested all
497 * throughout. */ 559 * throughout. */
498 if (iinst->mode == 0 || iinst->mode == VCD_TARGET) 560 if (iinst->mode == 0 || iinst->mode == VCD_TARGET)
499 { 561 {
@@ -503,6 +565,10 @@ int xd3_merge_inputs (xd3_stream *stream,
503 { 565 {
504 ret = xd3_merge_source_copy (stream, source, iinst); 566 ret = xd3_merge_source_copy (stream, source, iinst);
505 } 567 }
568
569 /* The whole_target.length is not updated in the xd3_merge*copy
570 * routine because of recursion in xd3_merge_source_copy. */
571 stream->whole_target.length += iinst->size;
506 break; 572 break;
507 } 573 }
508 } 574 }
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c
index bdf02af..7921556 100644
--- a/xdelta3/xdelta3.c
+++ b/xdelta3/xdelta3.c
@@ -2295,6 +2295,7 @@ xd3_free_stream (xd3_stream *stream)
2295 2295
2296 xd3_free (stream, stream->whole_target.adds); 2296 xd3_free (stream, stream->whole_target.adds);
2297 xd3_free (stream, stream->whole_target.inst); 2297 xd3_free (stream, stream->whole_target.inst);
2298 xd3_free (stream, stream->whole_target.winsizes);
2298 2299
2299 XD3_ASSERT (stream->alloc_cnt == stream->free_cnt); 2300 XD3_ASSERT (stream->alloc_cnt == stream->free_cnt);
2300 2301
diff --git a/xdelta3/xdelta3.h b/xdelta3/xdelta3.h
index fc3316a..1e6d4af 100644
--- a/xdelta3/xdelta3.h
+++ b/xdelta3/xdelta3.h
@@ -643,9 +643,15 @@ struct _xd3_whole_state {
643 usize_t addslen; 643 usize_t addslen;
644 uint8_t *adds; 644 uint8_t *adds;
645 usize_t adds_alloc; 645 usize_t adds_alloc;
646
646 usize_t instlen; 647 usize_t instlen;
647 xd3_winst *inst; 648 xd3_winst *inst;
648 usize_t inst_alloc; 649 usize_t inst_alloc;
650
651 usize_t winsizeslen;
652 usize_t *winsizes;
653 usize_t winsizes_alloc;
654
649 xoff_t length; 655 xoff_t length;
650 xoff_t windows; 656 xoff_t windows;
651}; 657};