diff-delta: fold two special tests into one plus cleanups
Testing for realloc and size limit can be done with only one test per loop. Make it so and fix a theoretical off-by-one comparison error in the process. The output buffer memory allocation is also bounded by max_size when specified. Finally make some variable unsigned to allow the handling of files up to 4GB in size instead of 2GB. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
cac251d0bc
commit
fe474b588b
24
diff-delta.c
24
diff-delta.c
@ -148,16 +148,20 @@ static void delta_cleanup(bdfile_t *bdf)
|
|||||||
cha_free(&bdf->cha);
|
cha_free(&bdf->cha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* provide the size of the copy opcode given the block offset and size */
|
||||||
#define COPYOP_SIZE(o, s) \
|
#define COPYOP_SIZE(o, s) \
|
||||||
(!!(o & 0xff) + !!(o & 0xff00) + !!(o & 0xff0000) + !!(o & 0xff000000) + \
|
(!!(o & 0xff) + !!(o & 0xff00) + !!(o & 0xff0000) + !!(o & 0xff000000) + \
|
||||||
!!(s & 0xff) + !!(s & 0xff00) + 1)
|
!!(s & 0xff) + !!(s & 0xff00) + 1)
|
||||||
|
|
||||||
|
/* the maximum size for any opcode */
|
||||||
|
#define MAX_OP_SIZE COPYOP_SIZE(0xffffffff, 0xffffffff)
|
||||||
|
|
||||||
void *diff_delta(void *from_buf, unsigned long from_size,
|
void *diff_delta(void *from_buf, unsigned long from_size,
|
||||||
void *to_buf, unsigned long to_size,
|
void *to_buf, unsigned long to_size,
|
||||||
unsigned long *delta_size,
|
unsigned long *delta_size,
|
||||||
unsigned long max_size)
|
unsigned long max_size)
|
||||||
{
|
{
|
||||||
int i, outpos, outsize, inscnt, csize, msize, moff;
|
unsigned int i, outpos, outsize, inscnt, csize, msize, moff;
|
||||||
unsigned int fp;
|
unsigned int fp;
|
||||||
const unsigned char *ref_data, *ref_top, *data, *top, *ptr1, *ptr2;
|
const unsigned char *ref_data, *ref_top, *data, *top, *ptr1, *ptr2;
|
||||||
unsigned char *out, *orig;
|
unsigned char *out, *orig;
|
||||||
@ -169,6 +173,8 @@ void *diff_delta(void *from_buf, unsigned long from_size,
|
|||||||
|
|
||||||
outpos = 0;
|
outpos = 0;
|
||||||
outsize = 8192;
|
outsize = 8192;
|
||||||
|
if (max_size && outsize >= max_size)
|
||||||
|
outsize = max_size + MAX_OP_SIZE + 1;
|
||||||
out = malloc(outsize);
|
out = malloc(outsize);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
delta_cleanup(&bdf);
|
delta_cleanup(&bdf);
|
||||||
@ -259,17 +265,15 @@ void *diff_delta(void *from_buf, unsigned long from_size,
|
|||||||
*orig = i;
|
*orig = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_size && outpos > max_size) {
|
if (outpos >= outsize - MAX_OP_SIZE) {
|
||||||
free(out);
|
|
||||||
delta_cleanup(&bdf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* next time around the largest possible output is 1 + 4 + 3 */
|
|
||||||
if (outpos > outsize - 8) {
|
|
||||||
void *tmp = out;
|
void *tmp = out;
|
||||||
outsize = outsize * 3 / 2;
|
outsize = outsize * 3 / 2;
|
||||||
out = realloc(out, outsize);
|
if (max_size && outsize >= max_size)
|
||||||
|
outsize = max_size + MAX_OP_SIZE + 1;
|
||||||
|
if (max_size && outpos > max_size)
|
||||||
|
out = NULL;
|
||||||
|
else
|
||||||
|
out = realloc(out, outsize);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
free(tmp);
|
free(tmp);
|
||||||
delta_cleanup(&bdf);
|
delta_cleanup(&bdf);
|
||||||
|
Loading…
Reference in New Issue
Block a user