From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- src/deltacmd.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 src/deltacmd.c (limited to 'src/deltacmd.c') diff --git a/src/deltacmd.c b/src/deltacmd.c new file mode 100644 index 0000000..98ddad0 --- /dev/null +++ b/src/deltacmd.c @@ -0,0 +1,198 @@ +/* +** Copyright (c) 2006 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) + +** 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. +** +** 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){ + const char *zOrig, *zTarg; + int lenOrig, lenTarg; + int len; + char *zRes; + blob_zero(pDelta); + zOrig = blob_materialize(pOriginal); + lenOrig = blob_size(pOriginal); + zTarg = blob_materialize(pTarget); + lenTarg = blob_size(pTarget); + blob_resize(pDelta, lenTarg+16); + zRes = blob_materialize(pDelta); + len = delta_create(zOrig, lenOrig, zTarg, lenTarg, zRes); + blob_resize(pDelta, len); + return 0; +} + +/* +** COMMAND: test-delta-create +** +** Usage: %fossil test-delta-create FILE1 FILE2 DELTA +** +** Create and output a delta that carries FILE1 into FILE2. +** Store the result in DELTA. +*/ +void delta_create_cmd(void){ + Blob orig, target, delta; + if( g.argc!=5 ){ + usage("ORIGIN TARGET DELTA"); + } + if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){ + fossil_fatal("cannot read %s", g.argv[2]); + } + if( blob_read_from_file(&target, g.argv[3], ExtFILE)<0 ){ + fossil_fatal("cannot read %s", g.argv[3]); + } + blob_delta_create(&orig, &target, &delta); + if( blob_write_to_file(&delta, g.argv[4])<(int)blob_size(&delta) ){ + fossil_fatal("cannot write %s", g.argv[4]); + } + blob_reset(&orig); + blob_reset(&target); + blob_reset(&delta); +} + +/* +** COMMAND: test-delta-analyze +** +** Usage: %fossil test-delta-analyze FILE1 FILE2 +** +** Create and a delta that carries FILE1 into FILE2. Print the +** number bytes copied and the number of bytes inserted. +*/ +void delta_analyze_cmd(void){ + Blob orig, target, delta; + int nCopy = 0; + int nInsert = 0; + int sz1, sz2, sz3; + if( g.argc!=4 ){ + usage("ORIGIN TARGET"); + } + if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){ + fossil_fatal("cannot read %s", g.argv[2]); + } + if( blob_read_from_file(&target, g.argv[3], ExtFILE)<0 ){ + fossil_fatal("cannot read %s", g.argv[3]); + } + blob_delta_create(&orig, &target, &delta); + delta_analyze(blob_buffer(&delta), blob_size(&delta), &nCopy, &nInsert); + sz1 = blob_size(&orig); + sz2 = blob_size(&target); + sz3 = blob_size(&delta); + blob_reset(&orig); + blob_reset(&target); + blob_reset(&delta); + fossil_print("original size: %8d\n", sz1); + fossil_print("bytes copied: %8d (%.2f%% of target)\n", + nCopy, (100.0*nCopy)/sz2); + fossil_print("bytes inserted: %8d (%.2f%% of target)\n", + nInsert, (100.0*nInsert)/sz2); + fossil_print("final size: %8d\n", sz2); + fossil_print("delta size: %8d\n", sz3); +} + +/* +** 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); + if( n<0 ) return -1; + 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 +** +** Usage: %fossil test-delta-apply FILE1 DELTA FILE2 +** +** Apply DELTA to FILE1 and output the result in FILE2. +*/ +void delta_apply_cmd(void){ + Blob orig, target, delta; + if( g.argc!=5 ){ + usage("ORIGIN DELTA TARGET"); + } + if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){ + fossil_fatal("cannot read %s", g.argv[2]); + } + if( blob_read_from_file(&delta, g.argv[3], ExtFILE)<0 ){ + fossil_fatal("cannot read %s", g.argv[3]); + } + blob_init(&target, 0, 0); + blob_delta_apply(&orig, &delta, &target); + if( blob_write_to_file(&target, g.argv[4])<(int)blob_size(&target) ){ + fossil_fatal("cannot write %s", g.argv[4]); + } + blob_reset(&orig); + blob_reset(&target); + blob_reset(&delta); +} + + +/* +** COMMAND: test-delta +** +** Usage: %fossil test-delta FILE1 FILE2 +** +** 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], ExtFILE); + blob_read_from_file(&f2, g.argv[3], ExtFILE); + 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_fatal("delta test failed"); + } + fossil_print("ok\n"); +} -- cgit v1.3.1