d60fc1c864
After experimenting with code to add the ability to encode a delta against part of the deltified file, it turns out that resulting packs are _bigger_ than when this ability is not used. The raw delta output might be smaller, but it doesn't compress as well using gzip with a negative net saving on average. Said bit would in fact be more useful to allow for encoding the copying of chunks larger than 64KB providing more savings with large files. This will correspond to packs version 3. While the current code still produces packs version 2, it is made future proof so pack versions 2 and 3 are accepted. Any pack version 2 are compatible with version 3 since the redefined bit was never used before. When enough time has passed, code to use that bit to produce version 3 packs could be added. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
73 lines
1.7 KiB
C
73 lines
1.7 KiB
C
/*
|
|
* patch-delta.c:
|
|
* recreate a buffer from a source and the delta produced by diff-delta.c
|
|
*
|
|
* (C) 2005 Nicolas Pitre <nico@cam.org>
|
|
*
|
|
* This code 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "delta.h"
|
|
|
|
void *patch_delta(void *src_buf, unsigned long src_size,
|
|
void *delta_buf, unsigned long delta_size,
|
|
unsigned long *dst_size)
|
|
{
|
|
const unsigned char *data, *top;
|
|
unsigned char *dst_buf, *out, cmd;
|
|
unsigned long size;
|
|
|
|
if (delta_size < DELTA_SIZE_MIN)
|
|
return NULL;
|
|
|
|
data = delta_buf;
|
|
top = delta_buf + delta_size;
|
|
|
|
/* make sure the orig file size matches what we expect */
|
|
size = get_delta_hdr_size(&data);
|
|
if (size != src_size)
|
|
return NULL;
|
|
|
|
/* now the result size */
|
|
size = get_delta_hdr_size(&data);
|
|
dst_buf = malloc(size + 1);
|
|
if (!dst_buf)
|
|
return NULL;
|
|
dst_buf[size] = 0;
|
|
|
|
out = dst_buf;
|
|
while (data < top) {
|
|
cmd = *data++;
|
|
if (cmd & 0x80) {
|
|
unsigned long cp_off = 0, cp_size = 0;
|
|
if (cmd & 0x01) cp_off = *data++;
|
|
if (cmd & 0x02) cp_off |= (*data++ << 8);
|
|
if (cmd & 0x04) cp_off |= (*data++ << 16);
|
|
if (cmd & 0x08) cp_off |= (*data++ << 24);
|
|
if (cmd & 0x10) cp_size = *data++;
|
|
if (cmd & 0x20) cp_size |= (*data++ << 8);
|
|
if (cmd & 0x40) cp_size |= (*data++ << 16);
|
|
if (cp_size == 0) cp_size = 0x10000;
|
|
memcpy(out, src_buf + cp_off, cp_size);
|
|
out += cp_size;
|
|
} else {
|
|
memcpy(out, data, cmd);
|
|
out += cmd;
|
|
data += cmd;
|
|
}
|
|
}
|
|
|
|
/* sanity check */
|
|
if (data != top || out - dst_buf != size) {
|
|
free(dst_buf);
|
|
return NULL;
|
|
}
|
|
|
|
*dst_size = size;
|
|
return dst_buf;
|
|
}
|