| /* Copyright (C) 2007 Josh MacDonald */ |
| |
| #include <stdio.h> |
| |
| #define PAGE_SIZE 4096 |
| |
| #define SPACE_MAX 131072 // how much memory per process |
| #define OUTPUT_MAX 1024 // max size for output |
| #define XD3_ALLOCSIZE 256 // internal size for various buffers |
| #define IOPT_SIZE 128 // instruction buffer |
| |
| // SPACE_MAX of 32K is sufficient for most inputs with XD3_COMPLEVEL_1 |
| // XD3_COMPLEVEL_9 requires about 4x more space than XD3_COMPLEVEL_1 |
| |
| #include "xdelta3.h" |
| #include "xdelta3.c" |
| |
| typedef struct _context { |
| uint8_t *buffer; |
| int allocated; |
| } context_t; |
| |
| static int max_allocated = 0; |
| |
| void* |
| process_alloc (void* opaque, usize_t items, usize_t size) |
| { |
| context_t *ctx = (context_t*) opaque; |
| usize_t t = items * size; |
| void *ret; |
| |
| if (ctx->allocated + t > SPACE_MAX) |
| { |
| return NULL; |
| } |
| |
| ret = ctx->buffer + ctx->allocated; |
| ctx->allocated += t; |
| return ret; |
| } |
| |
| void |
| process_free (void* opaque, void *ptr) |
| { |
| } |
| |
| int |
| process_page (int is_encode, |
| int (*func) (xd3_stream *), |
| const uint8_t *input, |
| usize_t input_size, |
| const uint8_t *source, |
| uint8_t *output, |
| usize_t *output_size, |
| usize_t output_size_max, |
| int flags) { |
| |
| /* On my x86 this is 1072 of objects on the stack */ |
| xd3_stream stream; |
| xd3_config config; |
| xd3_source src; |
| context_t *ctx = calloc(SPACE_MAX, 1); |
| int ret; |
| |
| memset (&config, 0, sizeof(config)); |
| |
| if (ctx == NULL) |
| { |
| printf("calloc failed\n"); |
| return -1; |
| } |
| |
| ctx->buffer = (uint8_t*)ctx; |
| ctx->allocated = sizeof(*ctx); |
| |
| config.flags = flags; |
| config.winsize = PAGE_SIZE; |
| config.sprevsz = PAGE_SIZE; |
| config.srcwin_maxsz = PAGE_SIZE; |
| config.iopt_size = IOPT_SIZE; |
| config.alloc = &process_alloc; |
| config.freef = &process_free; |
| config.opaque = (void*) ctx; |
| |
| src.size = PAGE_SIZE; |
| src.blksize = PAGE_SIZE; |
| src.onblk = PAGE_SIZE; |
| src.curblk = source; |
| src.curblkno = 0; |
| |
| if ((ret = xd3_config_stream (&stream, &config)) != 0 || |
| (ret = xd3_set_source (&stream, &src)) != 0 || |
| (ret = xd3_process_stream (is_encode, |
| &stream, |
| func, 1, |
| input, input_size, |
| output, output_size, |
| output_size_max)) != 0) |
| { |
| if (stream.msg != NULL) |
| { |
| fprintf(stderr, "stream message: %s\n", stream.msg); |
| } |
| } |
| |
| xd3_free_stream (&stream); |
| if (max_allocated < ctx->allocated) |
| { |
| max_allocated = ctx->allocated; |
| fprintf(stderr, "max allocated %d\n", max_allocated); |
| } |
| |
| free(ctx); |
| return ret; |
| } |
| |
| int test(int stride, int encode_flags) |
| { |
| uint8_t frompg[PAGE_SIZE]; |
| uint8_t topg[PAGE_SIZE]; |
| uint8_t output[OUTPUT_MAX]; |
| uint8_t reout[PAGE_SIZE]; |
| usize_t output_size; |
| usize_t re_size; |
| int i, j, ret; |
| |
| for (i = 0; i < PAGE_SIZE; i++) |
| { |
| topg[i] = frompg[i] = (rand() >> 3 ^ rand() >> 6 ^ rand() >> 9); |
| } |
| |
| // change 1 byte every stride |
| if (stride > 0) |
| { |
| for (j = stride; j <= PAGE_SIZE; j += stride) |
| { |
| topg[j - 1] ^= 0xff; |
| } |
| } |
| |
| if ((ret = process_page (1, xd3_encode_input, |
| topg, PAGE_SIZE, |
| frompg, output, |
| &output_size, OUTPUT_MAX, |
| encode_flags)) != 0) |
| { |
| fprintf (stderr, "encode failed: stride %u flags 0x%x\n", |
| stride, encode_flags); |
| return ret; |
| } |
| |
| if ((ret = process_page (0, xd3_decode_input, |
| output, output_size, |
| frompg, reout, |
| &re_size, PAGE_SIZE, |
| 0)) != 0) |
| { |
| fprintf (stderr, "decode failed: stride %u output_size %u flags 0x%x\n", |
| stride, output_size, encode_flags); |
| return ret; |
| } |
| |
| if (output_size > OUTPUT_MAX || re_size != PAGE_SIZE) |
| { |
| fprintf (stderr, "internal error: %u != %u\n", output_size, re_size); |
| return -1; |
| } |
| |
| for (i = 0; i < PAGE_SIZE; i++) |
| { |
| if (reout[i] != topg[i]) |
| { |
| fprintf (stderr, "encode-decode error: position %d\n", i); |
| return -1; |
| } |
| } |
| |
| fprintf(stderr, "stride %d flags 0x%x size %u ", |
| stride, encode_flags, output_size); |
| fprintf(stderr, "%s\n", (ret == 0) ? "OK" : "FAIL"); |
| |
| return 0; |
| } |
| |
| int main() |
| { |
| int stride; |
| int level; |
| |
| for (level = 1; level < 10; level = (level == 1 ? 3 : level + 3)) |
| { |
| int lflag = level << XD3_COMPLEVEL_SHIFT; |
| |
| for (stride = 2; stride <= PAGE_SIZE; stride += 2) |
| { |
| test(stride, lflag); |
| test(stride, lflag | XD3_SEC_DJW); |
| } |
| } |
| |
| return 0; |
| } |