Algorithm-GDiffDelta
view release on metacpan or search on metacpan
GDiffDelta.pm view on Meta::CPAN
=head1 SYNOPSIS
use Algorithm::GDiffDelta qw(
gdiff_adler32 gdiff_delta gdiff_apply
);
# Pass in two file handles for reading from and one to
# writing the GDIFF binary delta to:
gdiff_delta($orig, $changed, $delta);
# Pass in file handles of original file and GDIFF delta
# to read from, and file to write reconstructed changed
# file to:
gdiff_apply($orig, $delta, $changed);
# A fast adler32 digest implementation is also available:
my $adler32 = gdiff_adler32(1, 'some data');
$adler32 = gdiff_adler32($adler32, 'some more data');
=head1 DESCRIPTION
GDiffDelta.xs view on Meta::CPAN
/* Start by looking at the last (possibly incomplete) block */
if ((offset = (orig_size / QEF_BLK_SIZE) * QEF_BLK_SIZE) == orig_size)
offset -= QEF_BLK_SIZE;
while (1) {
brec = qef_cha_alloc(&bdf->cha);
brec->fp = adler32_file(orig, 0, offset,
QEF_MIN(QEF_BLK_SIZE, orig_size - offset),
"original");
brec->offset = offset;
i = QEF_HASHLONG(brec->fp, fphbits);
brec->next = fphash[i];
fphash[i] = brec;
if (offset < QEF_BLK_SIZE)
break;
offset -= QEF_BLK_SIZE;
}
GDiffDelta.xs view on Meta::CPAN
QefBDFile bdf;
QefBDRecord *brec;
unsigned char insbuf[QEF_BUFSZ], buf1[QEF_BUFSZ], buf2[QEF_BUFSZ];
size_t pos, sz1, sz2, minsz;
Off_t ins_offset, ins_size;
int stop;
changed_size = file_size(changed, "changed file");
if (changed_size == 0)
return;
orig_size = file_size(orig, "original");
prepare_bdfile(orig, orig_size, &bdf);
ins_size = 0;
changed_offset = 0;
while (changed_offset < changed_size) {
rsize = QEF_MIN(QEF_BLK_SIZE, changed_size - changed_offset);
fp = adler32_file(changed, 0, changed_offset, rsize, "changed file");
brec = bdf.fphash[QEF_HASHLONG(fp, bdf.fphbits)];
GDiffDelta.xs view on Meta::CPAN
newmsize = 0;
newmoff = off1;
stop = 0;
while (!stop) {
sz1 = QEF_MIN(QEF_BUFSZ, orig_size - off1);
sz2 = QEF_MIN(QEF_BUFSZ, changed_size - off2);
minsz = QEF_MIN(sz1, sz2);
if (minsz == 0)
break;
/* TODO - is there a better way to buffer these? */
careful_fseek(orig, off1, "original");
careful_fread(buf1, minsz, orig, "original");
careful_fseek(changed, off2, "changed file");
careful_fread(buf2, minsz, changed, "changed file");
for (pos = 0; pos < minsz; ++pos) {
if (buf1[pos] != buf2[pos]) {
stop = 1;
break;
}
}
newmsize += pos;
off1 += minsz;
GDiffDelta.xs view on Meta::CPAN
s = read_ushort(delta);
copy_data(delta, output, s, buf, "delta", "output");
break;
case 248: /* int, <n> bytes - append <n> data bytes */
s = read_int(delta);
copy_data(delta, output, s, buf, "delta", "output");
break;
case 249: /* ushort, ubyte - copy <position>, <length> */
r = read_ushort(delta);
s = read_ubyte(delta);
careful_fseek(orig, r, "original");
copy_data(orig, output, s, buf, "original", "output");
break;
case 250: /* ushort, ushort - copy <position>, <length> */
r = read_ushort(delta);
s = read_ushort(delta);
careful_fseek(orig, r, "original");
copy_data(orig, output, s, buf, "original", "output");
break;
case 251: /* ushort, int - copy <position>, <length> */
r = read_ushort(delta);
s = read_int(delta);
careful_fseek(orig, r, "original");
copy_data(orig, output, s, buf, "original", "output");
break;
case 252: /* int, ubyte - copy <position>, <length> */
r = read_int(delta);
s = read_ubyte(delta);
careful_fseek(orig, r, "original");
copy_data(orig, output, s, buf, "original", "output");
break;
case 253: /* int, ushort - copy <position>, <length> */
r = read_int(delta);
s = read_ushort(delta);
careful_fseek(orig, r, "original");
copy_data(orig, output, s, buf, "original", "output");
break;
case 254: /* int, int - copy <position>, <length> */
r = read_int(delta);
s = read_int(delta);
careful_fseek(orig, r, "original");
copy_data(orig, output, s, buf, "original", "output");
break;
case 255: /* long, int - copy <position>, <length> */
/* TODO - 64 seeking */
assert(0);
break;
default: assert(0);
}
}
}
t/20apply.t view on Meta::CPAN
my $orig_bak = $orig;
my $new = 'ABXYCDBCDE';
my $delta = "\xD1\xFF\xD1\xFF\x04" .
"\xF9\0\0\x02\x02XY\xF9\0\x02\x02\xF9\0\x01\x04\0";
my $delta_bak = $delta;
my $ios_orig_file = IO::Scalar->new(\$orig);
my $ios_delta_file = IO::Scalar->new(\$delta);
my $ios_new_file = IO::Scalar->new;
gdiff_apply($ios_orig_file, $ios_delta_file, $ios_new_file);
is("$ios_orig_file", $orig_bak,
'make sure original data in IO::Scalar still OK');
is("$ios_delta_file", $delta_bak,
'make sure delta in IO::Scalar still OK');
is("$ios_new_file", $new, 'apply example delta using IO::Scalar');
# Now test with real files, using sample data in 't/data'.
for (1 .. 2) {
my $orig_filename = catfile($data_dir, "$_.orig");
my $delta_filename = catfile($data_dir, "$_.gdiff");
my $new_filename = catfile($data_dir, "$_.new");
t/30delta.t view on Meta::CPAN
# Test generating deltas of predefined files. Make sure that the output can
# be applied to the original file to get the changed one (i.e., that it is
# a correct delta) and also that the delta is as small as I'd expect.
use strict;
use warnings;
use Test::More tests => 6 + 2 * 3;
use IO::Scalar;
use Algorithm::GDiffDelta qw( gdiff_delta gdiff_apply );
use File::Spec::Functions;
use File::Temp qw( tmpnam );
t/30delta.t view on Meta::CPAN
my $orig_bak = $orig;
my $new = 'ABXYCDBCDE';
my $new_bak = $new;
my $delta = "\xD1\xFF\xD1\xFF\x04" .
"\xF9\0\0\x02\x02XY\xF9\0\x02\x02\xF9\0\x01\x04\0";
my $ios_orig_file = IO::Scalar->new(\$orig);
my $ios_new_file = IO::Scalar->new(\$new);
my $ios_delta_file = IO::Scalar->new;
gdiff_delta($ios_orig_file, $ios_new_file, $ios_delta_file);
is("$ios_orig_file", $orig_bak,
'make sure original data in IO::Scalar still OK');
is("$ios_new_file", $new_bak,
'make sure new data in IO::Scalar still OK');
is(length "$ios_delta_file", 17,
'check delta produced with IO::Scalar is right length');
like("$ios_delta_file", qr/^\xD1\xFF\xD1\xFF\x04/, 'GDIFF header is right');
like("$ios_delta_file", qr/\x00\z/, 'GDIFF delta ends in EOF opcode');
$ios_orig_file = IO::Scalar->new(\$orig);
$ios_delta_file = IO::Scalar->new(\"$ios_delta_file");
$ios_new_file = IO::Scalar->new;
gdiff_apply($ios_orig_file, $ios_delta_file, $ios_new_file);
} while (0)
#define QEF_BE32_PUT(buf, idx, num) \
do { \
buf[idx++] = ((num) >> 24) & 0xFF; \
buf[idx++] = ((num) >> 16) & 0xFF; \
buf[idx++] = ((num) >> 8) & 0xFF; \
buf[idx++] = (num) & 0xFF; \
} while (0)
/* Data structures for the hashes of the original file. */
struct QefChaNode {
struct QefChaNode *next;
long icurr;
};
typedef struct QefChaNode QefChaNode;
struct QefChaStore {
QefChaNode *head, *tail;
long isize, nsize;
QefChaNode *ancur;
( run in 0.255 second using v1.01-cache-2.11-cpan-1c8d708658b )