dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Copyright (c) 2006 D. Richard Hipp dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This program is free software; you can redistribute it and/or dbda8d6ce9 2007-07-21 drh: ** modify it under the terms of the GNU General Public dbda8d6ce9 2007-07-21 drh: ** License version 2 as published by the Free Software Foundation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This program is distributed in the hope that it will be useful, dbda8d6ce9 2007-07-21 drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of dbda8d6ce9 2007-07-21 drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dbda8d6ce9 2007-07-21 drh: ** General Public License for more details. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** You should have received a copy of the GNU General Public dbda8d6ce9 2007-07-21 drh: ** License along with this library; if not, write to the dbda8d6ce9 2007-07-21 drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, dbda8d6ce9 2007-07-21 drh: ** Boston, MA 02111-1307, USA. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Author contact information: dbda8d6ce9 2007-07-21 drh: ** drh@hwaci.com dbda8d6ce9 2007-07-21 drh: ** http://www.hwaci.com/drh/ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ******************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This module implements the interface to the delta generator. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include "config.h" dbda8d6ce9 2007-07-21 drh: #include "deltacmd.h" dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Create a delta that describes the change from pOriginal to pTarget dbda8d6ce9 2007-07-21 drh: ** and put that delta in pDelta. The pDelta blob is assumed to be dbda8d6ce9 2007-07-21 drh: ** uninitialized. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int blob_delta_create(Blob *pOriginal, Blob *pTarget, Blob *pDelta){ dbda8d6ce9 2007-07-21 drh: const char *zOrig, *zTarg; dbda8d6ce9 2007-07-21 drh: int lenOrig, lenTarg; dbda8d6ce9 2007-07-21 drh: int len; dbda8d6ce9 2007-07-21 drh: char *zRes; 3a25b68390 2007-07-30 drh: blob_zero(pDelta); dbda8d6ce9 2007-07-21 drh: zOrig = blob_buffer(pOriginal); dbda8d6ce9 2007-07-21 drh: lenOrig = blob_size(pOriginal); dbda8d6ce9 2007-07-21 drh: zTarg = blob_buffer(pTarget); dbda8d6ce9 2007-07-21 drh: lenTarg = blob_size(pTarget); dbda8d6ce9 2007-07-21 drh: blob_resize(pDelta, lenTarg+16); dbda8d6ce9 2007-07-21 drh: zRes = blob_buffer(pDelta); dbda8d6ce9 2007-07-21 drh: len = delta_create(zOrig, lenOrig, zTarg, lenTarg, zRes); dbda8d6ce9 2007-07-21 drh: blob_resize(pDelta, len); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** COMMAND: test-delta-create dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Given two input files, create and output a delta that carries dbda8d6ce9 2007-07-21 drh: ** the first file into the second. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void delta_create_cmd(void){ dbda8d6ce9 2007-07-21 drh: Blob orig, target, delta; dbda8d6ce9 2007-07-21 drh: if( g.argc!=5 ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"Usage: %s %s ORIGIN TARGET DELTA\n", g.argv[0], g.argv[1]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( blob_read_from_file(&orig, g.argv[2])<0 ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"cannot read %s\n", g.argv[2]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( blob_read_from_file(&target, g.argv[3])<0 ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"cannot read %s\n", g.argv[3]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: blob_delta_create(&orig, &target, &delta); dbda8d6ce9 2007-07-21 drh: if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"cannot write %s\n", g.argv[4]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: blob_reset(&orig); dbda8d6ce9 2007-07-21 drh: blob_reset(&target); dbda8d6ce9 2007-07-21 drh: blob_reset(&delta); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Apply the delta in pDelta to the original file pOriginal to generate dbda8d6ce9 2007-07-21 drh: ** the target file pTarget. The pTarget blob is initialized by this dbda8d6ce9 2007-07-21 drh: ** routine. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** It works ok for pTarget and pOriginal to be the same blob. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the length of the target. Return -1 if there is an error. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int blob_delta_apply(Blob *pOriginal, Blob *pDelta, Blob *pTarget){ dbda8d6ce9 2007-07-21 drh: int len, n; dbda8d6ce9 2007-07-21 drh: Blob out; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: n = delta_output_size(blob_buffer(pDelta), blob_size(pDelta)); dbda8d6ce9 2007-07-21 drh: blob_zero(&out); dbda8d6ce9 2007-07-21 drh: blob_resize(&out, n); dbda8d6ce9 2007-07-21 drh: len = delta_apply( dbda8d6ce9 2007-07-21 drh: blob_buffer(pOriginal), blob_size(pOriginal), dbda8d6ce9 2007-07-21 drh: blob_buffer(pDelta), blob_size(pDelta), dbda8d6ce9 2007-07-21 drh: blob_buffer(&out)); dbda8d6ce9 2007-07-21 drh: if( len<0 ){ dbda8d6ce9 2007-07-21 drh: blob_reset(&out); dbda8d6ce9 2007-07-21 drh: }else if( len!=n ){ dbda8d6ce9 2007-07-21 drh: blob_resize(&out, len); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( pTarget==pOriginal ){ dbda8d6ce9 2007-07-21 drh: blob_reset(pOriginal); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: *pTarget = out; dbda8d6ce9 2007-07-21 drh: return len; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** COMMAND: test-delta-apply dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Given an input files and a delta, apply the delta to the input file dbda8d6ce9 2007-07-21 drh: ** and write the result. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void delta_apply_cmd(void){ dbda8d6ce9 2007-07-21 drh: Blob orig, target, delta; dbda8d6ce9 2007-07-21 drh: if( g.argc!=5 ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"Usage: %s %s ORIGIN DELTA TARGET\n", g.argv[0], g.argv[1]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( blob_read_from_file(&orig, g.argv[2])<0 ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"cannot read %s\n", g.argv[2]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( blob_read_from_file(&delta, g.argv[3])<0 ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"cannot read %s\n", g.argv[3]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: blob_delta_apply(&orig, &delta, &target); dbda8d6ce9 2007-07-21 drh: if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){ dbda8d6ce9 2007-07-21 drh: fprintf(stderr,"cannot write %s\n", g.argv[4]); dbda8d6ce9 2007-07-21 drh: exit(1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: blob_reset(&orig); dbda8d6ce9 2007-07-21 drh: blob_reset(&target); dbda8d6ce9 2007-07-21 drh: blob_reset(&delta); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** COMMAND: test-delta dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Read two files named on the command-line. Create and apply deltas dbda8d6ce9 2007-07-21 drh: ** going in both directions. Verify that the original files are dbda8d6ce9 2007-07-21 drh: ** correctly recovered. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void cmd_test_delta(void){ dbda8d6ce9 2007-07-21 drh: Blob f1, f2; /* Original file content */ dbda8d6ce9 2007-07-21 drh: Blob d12, d21; /* Deltas from f1->f2 and f2->f1 */ dbda8d6ce9 2007-07-21 drh: Blob a1, a2; /* Recovered file content */ dbda8d6ce9 2007-07-21 drh: if( g.argc!=4 ) usage("FILE1 FILE2"); dbda8d6ce9 2007-07-21 drh: blob_read_from_file(&f1, g.argv[2]); dbda8d6ce9 2007-07-21 drh: blob_read_from_file(&f2, g.argv[3]); dbda8d6ce9 2007-07-21 drh: blob_delta_create(&f1, &f2, &d12); dbda8d6ce9 2007-07-21 drh: blob_delta_create(&f2, &f1, &d21); dbda8d6ce9 2007-07-21 drh: blob_delta_apply(&f1, &d12, &a2); dbda8d6ce9 2007-07-21 drh: blob_delta_apply(&f2, &d21, &a1); dbda8d6ce9 2007-07-21 drh: if( blob_compare(&f1,&a1) || blob_compare(&f2, &a2) ){ dbda8d6ce9 2007-07-21 drh: fossil_panic("delta test failed"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: printf("ok\n"); dbda8d6ce9 2007-07-21 drh: }