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 |
} |