Fossil SCM
Add the test-delta-analyze command.
Commit
fd302a26118849db815f04bc494bbe3bbd197029
Parent
a50be7b87adcd48…
2 files changed
+61
+47
-4
+61
| --- src/delta.c | ||
| +++ src/delta.c | ||
| @@ -589,10 +589,71 @@ | ||
| 589 | 589 | /* ERROR: generated size does not match predicted size */ |
| 590 | 590 | return -1; |
| 591 | 591 | } |
| 592 | 592 | return total; |
| 593 | 593 | } |
| 594 | + default: { | |
| 595 | + /* ERROR: unknown delta operator */ | |
| 596 | + return -1; | |
| 597 | + } | |
| 598 | + } | |
| 599 | + } | |
| 600 | + /* ERROR: unterminated delta */ | |
| 601 | + return -1; | |
| 602 | +} | |
| 603 | + | |
| 604 | +/* | |
| 605 | +** Analyze a delta. Figure out the total number of bytes copied from | |
| 606 | +** source to target, and the total number of bytes inserted by the delta, | |
| 607 | +** and return both numbers. | |
| 608 | +*/ | |
| 609 | +int delta_analyze( | |
| 610 | + const char *zDelta, /* Delta to apply to the pattern */ | |
| 611 | + int lenDelta, /* Length of the delta */ | |
| 612 | + int *pnCopy, /* OUT: Number of bytes copied */ | |
| 613 | + int *pnInsert /* OUT: Number of bytes inserted */ | |
| 614 | +){ | |
| 615 | + unsigned int nInsert = 0; | |
| 616 | + unsigned int nCopy = 0; | |
| 617 | + | |
| 618 | + (void)getInt(&zDelta, &lenDelta); | |
| 619 | + if( *zDelta!='\n' ){ | |
| 620 | + /* ERROR: size integer not terminated by "\n" */ | |
| 621 | + return -1; | |
| 622 | + } | |
| 623 | + zDelta++; lenDelta--; | |
| 624 | + while( *zDelta && lenDelta>0 ){ | |
| 625 | + unsigned int cnt, ofst; | |
| 626 | + cnt = getInt(&zDelta, &lenDelta); | |
| 627 | + switch( zDelta[0] ){ | |
| 628 | + case '@': { | |
| 629 | + zDelta++; lenDelta--; | |
| 630 | + ofst = getInt(&zDelta, &lenDelta); | |
| 631 | + if( lenDelta>0 && zDelta[0]!=',' ){ | |
| 632 | + /* ERROR: copy command not terminated by ',' */ | |
| 633 | + return -1; | |
| 634 | + } | |
| 635 | + zDelta++; lenDelta--; | |
| 636 | + nCopy += cnt; | |
| 637 | + break; | |
| 638 | + } | |
| 639 | + case ':': { | |
| 640 | + zDelta++; lenDelta--; | |
| 641 | + nInsert += cnt; | |
| 642 | + if( cnt>lenDelta ){ | |
| 643 | + /* ERROR: insert count exceeds size of delta */ | |
| 644 | + return -1; | |
| 645 | + } | |
| 646 | + zDelta += cnt; | |
| 647 | + lenDelta -= cnt; | |
| 648 | + break; | |
| 649 | + } | |
| 650 | + case ';': { | |
| 651 | + *pnCopy = nCopy; | |
| 652 | + *pnInsert = nInsert; | |
| 653 | + return 0; | |
| 654 | + } | |
| 594 | 655 | default: { |
| 595 | 656 | /* ERROR: unknown delta operator */ |
| 596 | 657 | return -1; |
| 597 | 658 | } |
| 598 | 659 | } |
| 599 | 660 |
| --- src/delta.c | |
| +++ src/delta.c | |
| @@ -589,10 +589,71 @@ | |
| 589 | /* ERROR: generated size does not match predicted size */ |
| 590 | return -1; |
| 591 | } |
| 592 | return total; |
| 593 | } |
| 594 | default: { |
| 595 | /* ERROR: unknown delta operator */ |
| 596 | return -1; |
| 597 | } |
| 598 | } |
| 599 |
| --- src/delta.c | |
| +++ src/delta.c | |
| @@ -589,10 +589,71 @@ | |
| 589 | /* ERROR: generated size does not match predicted size */ |
| 590 | return -1; |
| 591 | } |
| 592 | return total; |
| 593 | } |
| 594 | default: { |
| 595 | /* ERROR: unknown delta operator */ |
| 596 | return -1; |
| 597 | } |
| 598 | } |
| 599 | } |
| 600 | /* ERROR: unterminated delta */ |
| 601 | return -1; |
| 602 | } |
| 603 | |
| 604 | /* |
| 605 | ** Analyze a delta. Figure out the total number of bytes copied from |
| 606 | ** source to target, and the total number of bytes inserted by the delta, |
| 607 | ** and return both numbers. |
| 608 | */ |
| 609 | int delta_analyze( |
| 610 | const char *zDelta, /* Delta to apply to the pattern */ |
| 611 | int lenDelta, /* Length of the delta */ |
| 612 | int *pnCopy, /* OUT: Number of bytes copied */ |
| 613 | int *pnInsert /* OUT: Number of bytes inserted */ |
| 614 | ){ |
| 615 | unsigned int nInsert = 0; |
| 616 | unsigned int nCopy = 0; |
| 617 | |
| 618 | (void)getInt(&zDelta, &lenDelta); |
| 619 | if( *zDelta!='\n' ){ |
| 620 | /* ERROR: size integer not terminated by "\n" */ |
| 621 | return -1; |
| 622 | } |
| 623 | zDelta++; lenDelta--; |
| 624 | while( *zDelta && lenDelta>0 ){ |
| 625 | unsigned int cnt, ofst; |
| 626 | cnt = getInt(&zDelta, &lenDelta); |
| 627 | switch( zDelta[0] ){ |
| 628 | case '@': { |
| 629 | zDelta++; lenDelta--; |
| 630 | ofst = getInt(&zDelta, &lenDelta); |
| 631 | if( lenDelta>0 && zDelta[0]!=',' ){ |
| 632 | /* ERROR: copy command not terminated by ',' */ |
| 633 | return -1; |
| 634 | } |
| 635 | zDelta++; lenDelta--; |
| 636 | nCopy += cnt; |
| 637 | break; |
| 638 | } |
| 639 | case ':': { |
| 640 | zDelta++; lenDelta--; |
| 641 | nInsert += cnt; |
| 642 | if( cnt>lenDelta ){ |
| 643 | /* ERROR: insert count exceeds size of delta */ |
| 644 | return -1; |
| 645 | } |
| 646 | zDelta += cnt; |
| 647 | lenDelta -= cnt; |
| 648 | break; |
| 649 | } |
| 650 | case ';': { |
| 651 | *pnCopy = nCopy; |
| 652 | *pnInsert = nInsert; |
| 653 | return 0; |
| 654 | } |
| 655 | default: { |
| 656 | /* ERROR: unknown delta operator */ |
| 657 | return -1; |
| 658 | } |
| 659 | } |
| 660 |
+47
-4
| --- src/deltacmd.c | ||
| +++ src/deltacmd.c | ||
| @@ -43,12 +43,14 @@ | ||
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | /* |
| 46 | 46 | ** COMMAND: test-delta-create |
| 47 | 47 | ** |
| 48 | -** Given two input files, create and output a delta that carries | |
| 49 | -** the first file into the second. | |
| 48 | +** Usage: %fossil test-delta-create FILE1 FILE2 DELTA | |
| 49 | +** | |
| 50 | +** Create and output a delta that carries FILE1 into FILE2. | |
| 51 | +** Store the result in DELTA. | |
| 50 | 52 | */ |
| 51 | 53 | void delta_create_cmd(void){ |
| 52 | 54 | Blob orig, target, delta; |
| 53 | 55 | if( g.argc!=5 ){ |
| 54 | 56 | usage("ORIGIN TARGET DELTA"); |
| @@ -65,10 +67,47 @@ | ||
| 65 | 67 | } |
| 66 | 68 | blob_reset(&orig); |
| 67 | 69 | blob_reset(&target); |
| 68 | 70 | blob_reset(&delta); |
| 69 | 71 | } |
| 72 | + | |
| 73 | +/* | |
| 74 | +** COMMAND: test-delta-analyze | |
| 75 | +** | |
| 76 | +** Usage: %fossil test-delta-analyze FILE1 FILE2 | |
| 77 | +** | |
| 78 | +** Create and a delta that carries FILE1 into FILE2. Print the | |
| 79 | +** number bytes copied and the number of bytes inserted. | |
| 80 | +*/ | |
| 81 | +void delta_analyze_cmd(void){ | |
| 82 | + Blob orig, target, delta; | |
| 83 | + int nCopy = 0; | |
| 84 | + int nInsert = 0; | |
| 85 | + int sz1, sz2; | |
| 86 | + if( g.argc!=4 ){ | |
| 87 | + usage("ORIGIN TARGET"); | |
| 88 | + } | |
| 89 | + if( blob_read_from_file(&orig, g.argv[2])<0 ){ | |
| 90 | + fossil_fatal("cannot read %s\n", g.argv[2]); | |
| 91 | + } | |
| 92 | + if( blob_read_from_file(&target, g.argv[3])<0 ){ | |
| 93 | + fossil_fatal("cannot read %s\n", g.argv[3]); | |
| 94 | + } | |
| 95 | + blob_delta_create(&orig, &target, &delta); | |
| 96 | + delta_analyze(blob_buffer(&delta), blob_size(&delta), &nCopy, &nInsert); | |
| 97 | + sz1 = blob_size(&orig); | |
| 98 | + sz2 = blob_size(&target); | |
| 99 | + blob_reset(&orig); | |
| 100 | + blob_reset(&target); | |
| 101 | + blob_reset(&delta); | |
| 102 | + fossil_print("original size: %8d\n", sz1); | |
| 103 | + fossil_print("bytes copied: %8d (%.1f%% of target)\n", | |
| 104 | + nCopy, (100.0*nCopy)/sz2); | |
| 105 | + fossil_print("bytes inserted: %8d (%.1f%% of target)\n", | |
| 106 | + nInsert, (100.0*nInsert)/sz2); | |
| 107 | + fossil_print("final size: %8d\n", sz2); | |
| 108 | +} | |
| 70 | 109 | |
| 71 | 110 | /* |
| 72 | 111 | ** Apply the delta in pDelta to the original file pOriginal to generate |
| 73 | 112 | ** the target file pTarget. The pTarget blob is initialized by this |
| 74 | 113 | ** routine. |
| @@ -102,12 +141,13 @@ | ||
| 102 | 141 | } |
| 103 | 142 | |
| 104 | 143 | /* |
| 105 | 144 | ** COMMAND: test-delta-apply |
| 106 | 145 | ** |
| 107 | -** Given an input files and a delta, apply the delta to the input file | |
| 108 | -** and write the result. | |
| 146 | +** Usage: %fossil test-delta-apply FILE1 DELTA | |
| 147 | +** | |
| 148 | +** Apply DELTA to FILE1 and output the result. | |
| 109 | 149 | */ |
| 110 | 150 | void delta_apply_cmd(void){ |
| 111 | 151 | Blob orig, target, delta; |
| 112 | 152 | if( g.argc!=5 ){ |
| 113 | 153 | usage("ORIGIN DELTA TARGET"); |
| @@ -124,13 +164,16 @@ | ||
| 124 | 164 | } |
| 125 | 165 | blob_reset(&orig); |
| 126 | 166 | blob_reset(&target); |
| 127 | 167 | blob_reset(&delta); |
| 128 | 168 | } |
| 169 | + | |
| 129 | 170 | |
| 130 | 171 | /* |
| 131 | 172 | ** COMMAND: test-delta |
| 173 | +** | |
| 174 | +** Usage: %fossil test-delta FILE1 FILE2 | |
| 132 | 175 | ** |
| 133 | 176 | ** Read two files named on the command-line. Create and apply deltas |
| 134 | 177 | ** going in both directions. Verify that the original files are |
| 135 | 178 | ** correctly recovered. |
| 136 | 179 | */ |
| 137 | 180 |
| --- src/deltacmd.c | |
| +++ src/deltacmd.c | |
| @@ -43,12 +43,14 @@ | |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | ** COMMAND: test-delta-create |
| 47 | ** |
| 48 | ** Given two input files, create and output a delta that carries |
| 49 | ** the first file into the second. |
| 50 | */ |
| 51 | void delta_create_cmd(void){ |
| 52 | Blob orig, target, delta; |
| 53 | if( g.argc!=5 ){ |
| 54 | usage("ORIGIN TARGET DELTA"); |
| @@ -65,10 +67,47 @@ | |
| 65 | } |
| 66 | blob_reset(&orig); |
| 67 | blob_reset(&target); |
| 68 | blob_reset(&delta); |
| 69 | } |
| 70 | |
| 71 | /* |
| 72 | ** Apply the delta in pDelta to the original file pOriginal to generate |
| 73 | ** the target file pTarget. The pTarget blob is initialized by this |
| 74 | ** routine. |
| @@ -102,12 +141,13 @@ | |
| 102 | } |
| 103 | |
| 104 | /* |
| 105 | ** COMMAND: test-delta-apply |
| 106 | ** |
| 107 | ** Given an input files and a delta, apply the delta to the input file |
| 108 | ** and write the result. |
| 109 | */ |
| 110 | void delta_apply_cmd(void){ |
| 111 | Blob orig, target, delta; |
| 112 | if( g.argc!=5 ){ |
| 113 | usage("ORIGIN DELTA TARGET"); |
| @@ -124,13 +164,16 @@ | |
| 124 | } |
| 125 | blob_reset(&orig); |
| 126 | blob_reset(&target); |
| 127 | blob_reset(&delta); |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | ** COMMAND: test-delta |
| 132 | ** |
| 133 | ** Read two files named on the command-line. Create and apply deltas |
| 134 | ** going in both directions. Verify that the original files are |
| 135 | ** correctly recovered. |
| 136 | */ |
| 137 |
| --- src/deltacmd.c | |
| +++ src/deltacmd.c | |
| @@ -43,12 +43,14 @@ | |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | ** COMMAND: test-delta-create |
| 47 | ** |
| 48 | ** Usage: %fossil test-delta-create FILE1 FILE2 DELTA |
| 49 | ** |
| 50 | ** Create and output a delta that carries FILE1 into FILE2. |
| 51 | ** Store the result in DELTA. |
| 52 | */ |
| 53 | void delta_create_cmd(void){ |
| 54 | Blob orig, target, delta; |
| 55 | if( g.argc!=5 ){ |
| 56 | usage("ORIGIN TARGET DELTA"); |
| @@ -65,10 +67,47 @@ | |
| 67 | } |
| 68 | blob_reset(&orig); |
| 69 | blob_reset(&target); |
| 70 | blob_reset(&delta); |
| 71 | } |
| 72 | |
| 73 | /* |
| 74 | ** COMMAND: test-delta-analyze |
| 75 | ** |
| 76 | ** Usage: %fossil test-delta-analyze FILE1 FILE2 |
| 77 | ** |
| 78 | ** Create and a delta that carries FILE1 into FILE2. Print the |
| 79 | ** number bytes copied and the number of bytes inserted. |
| 80 | */ |
| 81 | void delta_analyze_cmd(void){ |
| 82 | Blob orig, target, delta; |
| 83 | int nCopy = 0; |
| 84 | int nInsert = 0; |
| 85 | int sz1, sz2; |
| 86 | if( g.argc!=4 ){ |
| 87 | usage("ORIGIN TARGET"); |
| 88 | } |
| 89 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 90 | fossil_fatal("cannot read %s\n", g.argv[2]); |
| 91 | } |
| 92 | if( blob_read_from_file(&target, g.argv[3])<0 ){ |
| 93 | fossil_fatal("cannot read %s\n", g.argv[3]); |
| 94 | } |
| 95 | blob_delta_create(&orig, &target, &delta); |
| 96 | delta_analyze(blob_buffer(&delta), blob_size(&delta), &nCopy, &nInsert); |
| 97 | sz1 = blob_size(&orig); |
| 98 | sz2 = blob_size(&target); |
| 99 | blob_reset(&orig); |
| 100 | blob_reset(&target); |
| 101 | blob_reset(&delta); |
| 102 | fossil_print("original size: %8d\n", sz1); |
| 103 | fossil_print("bytes copied: %8d (%.1f%% of target)\n", |
| 104 | nCopy, (100.0*nCopy)/sz2); |
| 105 | fossil_print("bytes inserted: %8d (%.1f%% of target)\n", |
| 106 | nInsert, (100.0*nInsert)/sz2); |
| 107 | fossil_print("final size: %8d\n", sz2); |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | ** Apply the delta in pDelta to the original file pOriginal to generate |
| 112 | ** the target file pTarget. The pTarget blob is initialized by this |
| 113 | ** routine. |
| @@ -102,12 +141,13 @@ | |
| 141 | } |
| 142 | |
| 143 | /* |
| 144 | ** COMMAND: test-delta-apply |
| 145 | ** |
| 146 | ** Usage: %fossil test-delta-apply FILE1 DELTA |
| 147 | ** |
| 148 | ** Apply DELTA to FILE1 and output the result. |
| 149 | */ |
| 150 | void delta_apply_cmd(void){ |
| 151 | Blob orig, target, delta; |
| 152 | if( g.argc!=5 ){ |
| 153 | usage("ORIGIN DELTA TARGET"); |
| @@ -124,13 +164,16 @@ | |
| 164 | } |
| 165 | blob_reset(&orig); |
| 166 | blob_reset(&target); |
| 167 | blob_reset(&delta); |
| 168 | } |
| 169 | |
| 170 | |
| 171 | /* |
| 172 | ** COMMAND: test-delta |
| 173 | ** |
| 174 | ** Usage: %fossil test-delta FILE1 FILE2 |
| 175 | ** |
| 176 | ** Read two files named on the command-line. Create and apply deltas |
| 177 | ** going in both directions. Verify that the original files are |
| 178 | ** correctly recovered. |
| 179 | */ |
| 180 |