/* Copyright (C) 2007 Josh MacDonald */ #include #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; }