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