blob: bb52eac3a8240d9204fd9a21662fb5119b4d00bb [file] [log] [blame]
Lev Walkin725883b2006-10-09 12:07:58 +00001/*
2 * Mode of operation:
Lev Walkin93896cc2007-06-23 18:41:51 +00003 * Each of the *.in files is XER-decoded, then converted into PER,
4 * then decoded back from PER, then encoded into XER again,
5 * and finally compared to the original encoding.
Lev Walkin725883b2006-10-09 12:07:58 +00006 */
7#undef NDEBUG
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/types.h>
11#include <unistd.h> /* for chdir(2) */
12#include <string.h>
13#include <dirent.h>
14#include <assert.h>
15#include <ctype.h>
16#include <errno.h>
17
18#include <PDU.h>
19
Lev Walkine0d321a2014-09-11 01:28:57 -070020#ifndef SRCDIR
21#define SRCDIR_S ".."
22#else
23#define STRINGIFY_MACRO2(x) #x
24#define STRINGIFY_MACRO(x) STRINGIFY_MACRO2(x)
25#define SRCDIR_S STRINGIFY_MACRO(SRCDIR)
26#endif
27
Lev Walkin725883b2006-10-09 12:07:58 +000028enum expectation {
29 EXP_OK, /* Encoding/decoding must succeed */
30 EXP_CXER_EXACT, /* Encoding/decoding using CXER must be exact */
31 EXP_CXER_DIFF, /* Encoding/decoding using CXER must be different */
32 EXP_BROKEN, /* Decoding must fail */
33 EXP_DIFFERENT, /* Reconstruction will yield different encoding */
34 EXP_PER_NOCOMP, /* Not PER compatible */
35};
36
37static unsigned char buf[4096];
Lev Walkin1715b322013-03-28 04:02:13 -070038static size_t buf_offset;
Lev Walkin725883b2006-10-09 12:07:58 +000039
40static int
41_buf_writer(const void *buffer, size_t size, void *app_key) {
42 unsigned char *b, *bend;
43 (void)app_key;
44 assert(buf_offset + size < sizeof(buf));
45 memcpy(buf + buf_offset, buffer, size);
46 b = buf + buf_offset;
47 bend = b + size;
Lev Walkin15d38f42014-09-17 01:19:31 -070048#ifdef EMIT_ASN_DEBUG
Lev Walkin725883b2006-10-09 12:07:58 +000049 fprintf(stderr, "=> [");
50 for(; b < bend; b++) {
51 if(*b >= 32 && *b < 127 && *b != '%')
52 fprintf(stderr, "%c", *b);
53 else
54 fprintf(stderr, "%%%02x", *b);
55 }
Lev Walkin1715b322013-03-28 04:02:13 -070056 fprintf(stderr, "]:%zd\n", size);
Lev Walkin15d38f42014-09-17 01:19:31 -070057#endif
Lev Walkin725883b2006-10-09 12:07:58 +000058 buf_offset += size;
59 return 0;
60}
61
62enum enctype {
63 AS_PER,
64 AS_DER,
65 AS_XER,
66 AS_CXER,
67};
68
69static void
70save_object_as(PDU_t *st, enum expectation exp, enum enctype how) {
71 asn_enc_rval_t rval; /* Return value */
72
73 buf_offset = 0;
74
75 /*
76 * Save object using specified method.
77 */
78 switch(how) {
79 case AS_PER:
80 rval = uper_encode(&asn_DEF_PDU, st,
81 _buf_writer, 0);
82 if(exp == EXP_PER_NOCOMP)
83 assert(rval.encoded == -1);
84 else
85 assert(rval.encoded > 0);
Lev Walkin1715b322013-03-28 04:02:13 -070086 fprintf(stderr, "SAVED OBJECT IN SIZE %zd\n", buf_offset);
Lev Walkin725883b2006-10-09 12:07:58 +000087 return;
88 case AS_DER:
89 rval = der_encode(&asn_DEF_PDU, st,
90 _buf_writer, 0);
91 break;
92 case AS_XER:
93 rval = xer_encode(&asn_DEF_PDU, st, XER_F_BASIC,
94 _buf_writer, 0);
95 break;
96 case AS_CXER:
97 rval = xer_encode(&asn_DEF_PDU, st, XER_F_CANONICAL,
98 _buf_writer, 0);
99 break;
100 }
101
102 if (rval.encoded == -1) {
103 fprintf(stderr,
104 "Cannot encode %s: %s\n",
105 rval.failed_type->name, strerror(errno));
106 assert(rval.encoded != -1);
107 return;
108 }
109
Lev Walkin1715b322013-03-28 04:02:13 -0700110 fprintf(stderr, "SAVED OBJECT IN SIZE %zd\n", buf_offset);
Lev Walkin725883b2006-10-09 12:07:58 +0000111}
112
113static PDU_t *
Lev Walkin5b63acf2014-01-14 01:48:37 -0800114load_object_from(const char *fname, enum expectation expectation, unsigned char *fbuf, size_t size, enum enctype how) {
Lev Walkin725883b2006-10-09 12:07:58 +0000115 asn_dec_rval_t rval;
116 PDU_t *st = 0;
Lev Walkin1715b322013-03-28 04:02:13 -0700117 size_t csize = 1;
Lev Walkin725883b2006-10-09 12:07:58 +0000118
119 if(getenv("INITIAL_CHUNK_SIZE"))
120 csize = atoi(getenv("INITIAL_CHUNK_SIZE"));
121
122 /* Perform multiple iterations with multiple chunks sizes */
123 for(; csize < 20; csize += 1) {
124 int fbuf_offset = 0;
125 int fbuf_left = size;
126 int fbuf_chunk = csize;
127
Lev Walkinb7c40b62013-03-28 05:54:12 -0700128 fprintf(stderr, "LOADING OBJECT OF SIZE %zd FROM [%s] as %s,"
Lev Walkin1715b322013-03-28 04:02:13 -0700129 " chunks %zd\n",
Lev Walkin725883b2006-10-09 12:07:58 +0000130 size, fname, how==AS_PER?"PER":"XER", csize);
131
132 if(st) asn_DEF_PDU.free_struct(&asn_DEF_PDU, st, 0);
133 st = 0;
134
135 do {
Lev Walkin15d38f42014-09-17 01:19:31 -0700136 ASN_DEBUG("Decoding bytes %d..%d (left %d)",
Lev Walkin725883b2006-10-09 12:07:58 +0000137 fbuf_offset,
138 fbuf_chunk < fbuf_left
139 ? fbuf_chunk : fbuf_left,
140 fbuf_left);
Lev Walkin15d38f42014-09-17 01:19:31 -0700141#ifdef EMIT_ASN_DEBUG
Lev Walkin725883b2006-10-09 12:07:58 +0000142 if(st) {
143 fprintf(stderr, "=== currently ===\n");
144 asn_fprint(stderr, &asn_DEF_PDU, st);
145 fprintf(stderr, "=== end ===\n");
146 }
Lev Walkin15d38f42014-09-17 01:19:31 -0700147#endif
Lev Walkin725883b2006-10-09 12:07:58 +0000148 switch(how) {
149 case AS_XER:
150 rval = xer_decode(0, &asn_DEF_PDU, (void **)&st,
151 fbuf + fbuf_offset,
152 fbuf_chunk < fbuf_left
153 ? fbuf_chunk : fbuf_left);
154 break;
155 case AS_PER:
156 rval = uper_decode(0, &asn_DEF_PDU,
157 (void **)&st, fbuf + fbuf_offset,
158 fbuf_chunk < fbuf_left
159 ? fbuf_chunk : fbuf_left, 0, 0);
160 if(rval.code == RC_WMORE) {
161 rval.consumed = 0; /* Not restartable */
162 ASN_STRUCT_FREE(asn_DEF_PDU, st);
163 st = 0;
Lev Walkin15d38f42014-09-17 01:19:31 -0700164 ASN_DEBUG("-> PER wants more");
Lev Walkin725883b2006-10-09 12:07:58 +0000165 } else {
Lev Walkin15d38f42014-09-17 01:19:31 -0700166 ASN_DEBUG("-> PER ret %d/%zd",
Lev Walkin725883b2006-10-09 12:07:58 +0000167 rval.code, rval.consumed);
168 /* uper_decode() returns _bits_ */
169 rval.consumed += 7;
170 rval.consumed /= 8;
171 }
172 break;
Lev Walkin5b63acf2014-01-14 01:48:37 -0800173 case AS_DER:
174 case AS_CXER:
175 assert(!"Unexpected DER or CXER load request");
Lev Walkin725883b2006-10-09 12:07:58 +0000176 }
177 fbuf_offset += rval.consumed;
178 fbuf_left -= rval.consumed;
179 if(rval.code == RC_WMORE)
180 fbuf_chunk += 1; /* Give little more */
181 else
182 fbuf_chunk = csize; /* Back off */
183 } while(fbuf_left && rval.code == RC_WMORE);
184
185 if(expectation != EXP_BROKEN) {
186 assert(rval.code == RC_OK);
187 if(how == AS_PER) {
Lev Walkinb7c40b62013-03-28 05:54:12 -0700188 fprintf(stderr, "[left %d, off %d, size %zd]\n",
Lev Walkin725883b2006-10-09 12:07:58 +0000189 fbuf_left, fbuf_offset, size);
Lev Walkin5b63acf2014-01-14 01:48:37 -0800190 assert(fbuf_offset == (ssize_t)size);
Lev Walkin725883b2006-10-09 12:07:58 +0000191 } else {
192 assert(fbuf_offset - size < 2
Lev Walkin5b63acf2014-01-14 01:48:37 -0800193 || (fbuf_offset + 1 /* "\n" */ == (ssize_t)size
Lev Walkin725883b2006-10-09 12:07:58 +0000194 && fbuf[size - 1] == '\n')
Lev Walkin5b63acf2014-01-14 01:48:37 -0800195 || (fbuf_offset + 2 /* "\r\n" */ == (ssize_t)size
Lev Walkin725883b2006-10-09 12:07:58 +0000196 && fbuf[size - 2] == '\r'
197 && fbuf[size - 1] == '\n')
198 );
199 }
200 } else {
201 assert(rval.code != RC_OK);
202 fprintf(stderr, "Failed, but this was expected\n");
203 asn_DEF_PDU.free_struct(&asn_DEF_PDU, st, 0);
204 st = 0; /* ignore leak for now */
205 }
206 }
207
208 if(st) asn_fprint(stderr, &asn_DEF_PDU, st);
209 return st;
210}
211
212static int
Lev Walkin5b63acf2014-01-14 01:48:37 -0800213xer_encoding_equal(void *obufp, size_t osize, void *nbufp, size_t nsize) {
214 char *obuf = obufp;
215 char *nbuf = nbufp;
Lev Walkin725883b2006-10-09 12:07:58 +0000216 char *oend = obuf + osize;
217 char *nend = nbuf + nsize;
218
219 if((osize && !nsize) || (!osize && nsize))
220 return 0; /* not equal apriori */
221
222 while(1) {
223 while(obuf < oend && isspace(*obuf)) obuf++;
224 while(nbuf < nend && isspace(*nbuf)) nbuf++;
225
226 if(obuf == oend || nbuf == nend) {
227 if(obuf == oend && nbuf == nend)
228 break;
229 fprintf(stderr, "%s data in reconstructed encoding\n",
230 (obuf == oend) ? "More" : "Less");
231 return 0;
232 }
233
234 if(*obuf != *nbuf) {
235 printf("%c%c != %c%c\n",
236 obuf[0], obuf[1],
237 nbuf[0], nbuf[1]);
238 return 0;
239 }
240 obuf++, nbuf++;
241 }
242
243 return 1;
244}
245
246static void
Lev Walkin5b63acf2014-01-14 01:48:37 -0800247process_XER_data(const char *fname, enum expectation expectation, unsigned char *fbuf, ssize_t size) {
Lev Walkin725883b2006-10-09 12:07:58 +0000248 PDU_t *st;
Lev Walkin725883b2006-10-09 12:07:58 +0000249
250 st = load_object_from(fname, expectation, fbuf, size, AS_XER);
251 if(!st) return;
252
Lev Walkin788490d2007-06-23 23:36:51 +0000253 /* Save and re-load as PER */
Lev Walkin725883b2006-10-09 12:07:58 +0000254 save_object_as(st, expectation, AS_PER);
255 if(expectation == EXP_PER_NOCOMP)
256 return; /* Already checked */
257 st = load_object_from("buffer", expectation, buf, buf_offset, AS_PER);
258 assert(st);
259
260 save_object_as(st,
261 expectation,
262 (expectation == EXP_CXER_EXACT
263 || expectation == EXP_CXER_DIFF)
264 ? AS_CXER : AS_XER);
265 fprintf(stderr, "=== original ===\n");
266 fwrite(fbuf, 1, size, stderr);
267 fprintf(stderr, "=== re-encoded ===\n");
268 fwrite(buf, 1, buf_offset, stderr);
269 fprintf(stderr, "=== end ===\n");
270
271 switch(expectation) {
272 case EXP_DIFFERENT:
273 assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
274 break;
275 case EXP_BROKEN:
276 assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
277 break;
278 case EXP_CXER_EXACT:
279 buf[buf_offset++] = '\n';
Lev Walkin5b63acf2014-01-14 01:48:37 -0800280 assert((ssize_t)size == (ssize_t)buf_offset);
Lev Walkin725883b2006-10-09 12:07:58 +0000281 assert(memcmp(fbuf, buf, size) == 0);
282 break;
283 case EXP_CXER_DIFF:
284 buf[buf_offset++] = '\n';
Lev Walkin5b63acf2014-01-14 01:48:37 -0800285 assert((ssize_t)size != (ssize_t)buf_offset
Lev Walkin725883b2006-10-09 12:07:58 +0000286 || memcmp(fbuf, buf, size));
287 break;
288 case EXP_OK:
289 case EXP_PER_NOCOMP:
290 assert(xer_encoding_equal(fbuf, size, buf, buf_offset));
291 break;
292 }
293
294 asn_DEF_PDU.free_struct(&asn_DEF_PDU, st, 0);
295}
296
297/*
298 * Decode the .der files and try to regenerate them.
299 */
300static int
301process(const char *fname) {
Lev Walkin5b63acf2014-01-14 01:48:37 -0800302 unsigned char fbuf[4096];
Lev Walkin725883b2006-10-09 12:07:58 +0000303 char *ext = strrchr(fname, '.');
304 enum expectation expectation;
Lev Walkin725883b2006-10-09 12:07:58 +0000305 int rd;
306 FILE *fp;
307
308 if(ext == 0 || strcmp(ext, ".in"))
309 return 0;
310
311 switch(ext[-1]) {
312 case 'B': /* The file is intentionally broken */
313 expectation = EXP_BROKEN; break;
314 case 'D': /* Reconstructing should yield different data */
315 expectation = EXP_DIFFERENT; break;
316 case 'E': /* Byte to byte exact reconstruction */
317 expectation = EXP_CXER_EXACT; break;
318 case 'X': /* Should fail byte-to-byte comparison */
319 expectation = EXP_CXER_DIFF; break;
320 case 'P': /* Incompatible with PER */
321 expectation = EXP_PER_NOCOMP; break;
322 default:
323 expectation = EXP_OK; break;
324 }
325
326 fprintf(stderr, "\nProcessing file [../%s]\n", fname);
327
Lev Walkine0d321a2014-09-11 01:28:57 -0700328 snprintf((char *)fbuf, sizeof(fbuf), SRCDIR_S "/data-119/%s", fname);
Lev Walkin5b63acf2014-01-14 01:48:37 -0800329 fp = fopen((char *)fbuf, "r");
Lev Walkin725883b2006-10-09 12:07:58 +0000330 assert(fp);
331
332 rd = fread(fbuf, 1, sizeof(fbuf), fp);
333 fclose(fp);
334
Lev Walkin5b63acf2014-01-14 01:48:37 -0800335 assert(rd < (ssize_t)sizeof(fbuf)); /* expect small files */
Lev Walkin725883b2006-10-09 12:07:58 +0000336
337 process_XER_data(fname, expectation, fbuf, rd);
338
339 fprintf(stderr, "Finished [%s]\n", fname);
340
341 return 1;
342}
343
344int
345main() {
346 DIR *dir;
347 struct dirent *dent;
348 int processed_files = 0;
349 char *str;
350
351 /* Process a specific test file */
352 str = getenv("DATA_119_FILE");
353 if(str && strncmp(str, "data-119-", 9) == 0) {
354 process(str);
355 return 0;
356 }
357
Lev Walkine0d321a2014-09-11 01:28:57 -0700358 dir = opendir(SRCDIR_S "/data-119");
Lev Walkin725883b2006-10-09 12:07:58 +0000359 assert(dir);
360
361 /*
362 * Process each file in that directory.
363 */
364 while((dent = readdir(dir))) {
365 if(strncmp(dent->d_name, "data-119-", 9) == 0)
366 if(process(dent->d_name))
367 processed_files++;
368 }
369
370 assert(processed_files);
371 closedir(dir);
372
373 return 0;
374}
375