| 1 |
/* Copyright (C) 2007 Josh MacDonald */ |
| 2 |
|
| 3 |
#include <stdio.h> |
| 4 |
|
| 5 |
#define PAGE_SIZE 4096 |
| 6 |
|
| 7 |
#define SPACE_MAX 131072 // how much memory per process |
| 8 |
#define OUTPUT_MAX 1024 // max size for output |
| 9 |
#define XD3_ALLOCSIZE 256 // internal size for various buffers |
| 10 |
#define IOPT_SIZE 128 // instruction buffer |
| 11 |
|
| 12 |
// SPACE_MAX of 32K is sufficient for most inputs with XD3_COMPLEVEL_1 |
| 13 |
// XD3_COMPLEVEL_9 requires about 4x more space than XD3_COMPLEVEL_1 |
| 14 |
|
| 15 |
#include "xdelta3.h" |
| 16 |
#include "xdelta3.c" |
| 17 |
|
| 18 |
typedef struct _context { |
| 19 |
uint8_t *buffer; |
| 20 |
int allocated; |
| 21 |
} context_t; |
| 22 |
|
| 23 |
static int max_allocated = 0; |
| 24 |
|
| 25 |
void* |
| 26 |
process_alloc (void* opaque, usize_t items, usize_t size) |
| 27 |
{ |
| 28 |
context_t *ctx = (context_t*) opaque; |
| 29 |
usize_t t = items * size; |
| 30 |
void *ret; |
| 31 |
|
| 32 |
if (ctx->allocated + t > SPACE_MAX) |
| 33 |
{ |
| 34 |
return NULL; |
| 35 |
} |
| 36 |
|
| 37 |
ret = ctx->buffer + ctx->allocated; |
| 38 |
ctx->allocated += t; |
| 39 |
return ret; |
| 40 |
} |
| 41 |
|
| 42 |
void |
| 43 |
process_free (void* opaque, void *ptr) |
| 44 |
{ |
| 45 |
} |
| 46 |
|
| 47 |
int |
| 48 |
process_page (int is_encode, |
| 49 |
int (*func) (xd3_stream *), |
| 50 |
const uint8_t *input, |
| 51 |
usize_t input_size, |
| 52 |
const uint8_t *source, |
| 53 |
uint8_t *output, |
| 54 |
usize_t *output_size, |
| 55 |
usize_t output_size_max, |
| 56 |
int flags) { |
| 57 |
|
| 58 |
/* On my x86 this is 1072 of objects on the stack */ |
| 59 |
xd3_stream stream; |
| 60 |
xd3_config config; |
| 61 |
xd3_source src; |
| 62 |
context_t *ctx = calloc(SPACE_MAX, 1); |
| 63 |
int ret; |
| 64 |
|
| 65 |
if (ctx == NULL) |
| 66 |
{ |
| 67 |
printf("calloc failed\n"); |
| 68 |
return -1; |
| 69 |
} |
| 70 |
|
| 71 |
ctx->buffer = (uint8_t*)ctx; |
| 72 |
ctx->allocated = sizeof(*ctx); |
| 73 |
|
| 74 |
config.flags = flags; |
| 75 |
config.winsize = PAGE_SIZE; |
| 76 |
config.sprevsz = PAGE_SIZE; |
| 77 |
config.srcwin_maxsz = PAGE_SIZE; |
| 78 |
config.iopt_size = IOPT_SIZE; |
| 79 |
config.alloc = &process_alloc; |
| 80 |
config.freef = &process_free; |
| 81 |
config.opaque = (void*) ctx; |
| 82 |
|
| 83 |
src.size = PAGE_SIZE; |
| 84 |
src.blksize = PAGE_SIZE; |
| 85 |
src.onblk = PAGE_SIZE; |
| 86 |
src.curblk = source; |
| 87 |
src.curblkno = 0; |
| 88 |
|
| 89 |
if ((ret = xd3_config_stream (&stream, &config)) != 0 || |
| 90 |
(ret = xd3_set_source (&stream, &src)) != 0 || |
| 91 |
(ret = xd3_process_stream (is_encode, |
| 92 |
&stream, |
| 93 |
func, 1, |
| 94 |
input, input_size, |
| 95 |
output, output_size, |
| 96 |
output_size_max)) != 0) |
| 97 |
{ |
| 98 |
if (stream.msg != NULL) |
| 99 |
{ |
| 100 |
fprintf(stderr, "stream message: %s\n", stream.msg); |
| 101 |
} |
| 102 |
} |
| 103 |
|
| 104 |
xd3_free_stream (&stream); |
| 105 |
if (max_allocated < ctx->allocated) |
| 106 |
{ |
| 107 |
max_allocated = ctx->allocated; |
| 108 |
fprintf(stderr, "max allocated %d\n", max_allocated); |
| 109 |
} |
| 110 |
|
| 111 |
free(ctx); |
| 112 |
return ret; |
| 113 |
} |
| 114 |
|
| 115 |
int test(int stride, int encode_flags) |
| 116 |
{ |
| 117 |
uint8_t frompg[PAGE_SIZE]; |
| 118 |
uint8_t topg[PAGE_SIZE]; |
| 119 |
uint8_t output[OUTPUT_MAX]; |
| 120 |
uint8_t reout[PAGE_SIZE]; |
| 121 |
usize_t output_size; |
| 122 |
usize_t re_size; |
| 123 |
int i, j, ret; |
| 124 |
|
| 125 |
for (i = 0; i < PAGE_SIZE; i++) |
| 126 |
{ |
| 127 |
topg[i] = frompg[i] = (rand() >> 3 ^ rand() >> 6 ^ rand() >> 9); |
| 128 |
} |
| 129 |
|
| 130 |
// change 1 byte every stride |
| 131 |
if (stride > 0) |
| 132 |
{ |
| 133 |
for (j = stride; j <= PAGE_SIZE; j += stride) |
| 134 |
{ |
| 135 |
topg[j - 1] ^= 0xff; |
| 136 |
} |
| 137 |
} |
| 138 |
|
| 139 |
if ((ret = process_page (1, xd3_encode_input, |
| 140 |
topg, PAGE_SIZE, |
| 141 |
frompg, output, |
| 142 |
&output_size, OUTPUT_MAX, |
| 143 |
encode_flags)) != 0) |
| 144 |
{ |
| 145 |
fprintf (stderr, "encode failed: stride %u flags 0x%x\n", stride, encode_flags); |
| 146 |
return ret; |
| 147 |
} |
| 148 |
|
| 149 |
if ((ret = process_page (0, xd3_decode_input, |
| 150 |
output, output_size, |
| 151 |
frompg, reout, |
| 152 |
&re_size, PAGE_SIZE, |
| 153 |
0)) != 0) |
| 154 |
{ |
| 155 |
fprintf (stderr, "decode failed: stride %u output_size %u flags 0x%x\n", |
| 156 |
stride, output_size, encode_flags); |
| 157 |
return ret; |
| 158 |
} |
| 159 |
|
| 160 |
if (output_size > OUTPUT_MAX || re_size != PAGE_SIZE) |
| 161 |
{ |
| 162 |
fprintf (stderr, "internal error: %u != %u\n", output_size, re_size); |
| 163 |
return -1; |
| 164 |
} |
| 165 |
|
| 166 |
for (i = 0; i < PAGE_SIZE; i++) |
| 167 |
{ |
| 168 |
if (reout[i] != topg[i]) |
| 169 |
{ |
| 170 |
fprintf (stderr, "encode-decode error: position %d\n", i); |
| 171 |
return -1; |
| 172 |
} |
| 173 |
} |
| 174 |
|
| 175 |
fprintf(stderr, "stride %d flags 0x%x size %u ", stride, encode_flags, output_size); |
| 176 |
fprintf(stderr, "%s\n", (ret == 0) ? "OK" : "FAIL"); |
| 177 |
|
| 178 |
return 0; |
| 179 |
} |
| 180 |
|
| 181 |
int main() |
| 182 |
{ |
| 183 |
int stride; |
| 184 |
int level; |
| 185 |
|
| 186 |
for (level = 1; level < 10; level = (level == 1 ? 3 : level + 3)) |
| 187 |
{ |
| 188 |
int lflag = level << XD3_COMPLEVEL_SHIFT; |
| 189 |
|
| 190 |
for (stride = 2; stride <= PAGE_SIZE; stride += 2) |
| 191 |
{ |
| 192 |
test(stride, lflag); |
| 193 |
test(stride, lflag | XD3_SEC_DJW); |
| 194 |
} |
| 195 |
} |
| 196 |
|
| 197 |
return 0; |
| 198 |
} |