NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / tests / tests-c-compiler / check-src / check-119.-gen-PER.c
1 /*
2  * Mode of operation:
3  * 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.
6  */
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
20 #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
28 enum 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
37 static unsigned char buf[4096];
38 static size_t buf_offset;
39
40 static int
41 _buf_writer(const void *buffer, size_t size, void *app_key) {
42         (void)app_key;
43         assert(buf_offset + size < sizeof(buf));
44         memcpy(buf + buf_offset, buffer, size);
45 #ifdef ASN_EMIT_DEBUG
46         unsigned char *b, *bend;
47         b = buf + buf_offset;
48         bend = b + size;
49         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         }
56         fprintf(stderr, "]:%zd\n", size);
57 #endif
58         buf_offset += size;
59         return 0;
60 }
61
62 enum enctype {
63         AS_PER,
64         AS_DER,
65         AS_XER,
66         AS_CXER,
67 };
68
69 static void
70 save_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, 0, st,
81                         _buf_writer, 0);
82                 if(exp == EXP_PER_NOCOMP)
83                         assert(rval.encoded == -1);
84                 else
85                         assert(rval.encoded > 0);
86                 fprintf(stderr, "SAVED OBJECT IN SIZE %zd\n", buf_offset);
87                 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     default:
101         assert(!"Unreachable");
102         }
103
104         if (rval.encoded == -1) {
105                 fprintf(stderr,
106                         "Cannot encode %s: %s\n",
107                         rval.failed_type->name, strerror(errno));
108                 assert(rval.encoded != -1);
109                 return;
110         }
111
112         fprintf(stderr, "SAVED OBJECT IN SIZE %zd\n", buf_offset);
113 }
114
115 static PDU_t *
116 load_object_from(const char *fname, enum expectation expectation, unsigned char *fbuf, size_t size, enum enctype how) {
117         asn_dec_rval_t rval;
118         PDU_t *st = 0;
119         size_t csize = 1;
120
121         if(getenv("INITIAL_CHUNK_SIZE"))
122                 csize = atoi(getenv("INITIAL_CHUNK_SIZE"));
123
124         /* Perform multiple iterations with multiple chunks sizes */
125         for(; csize < 20; csize += 1) {
126                 int fbuf_offset = 0;
127                 int fbuf_left = size;
128                 int fbuf_chunk = csize;
129
130                 fprintf(stderr, "LOADING OBJECT OF SIZE %zd FROM [%s] as %s,"
131                         " chunks %zd\n",
132                         size, fname, how==AS_PER?"PER":"XER", csize);
133
134                 if(st) ASN_STRUCT_FREE(asn_DEF_PDU, st);
135                 st = 0;
136
137                 do {
138                         ASN_DEBUG("Decoding bytes %d..%d (left %d)",
139                                 fbuf_offset,
140                                         fbuf_chunk < fbuf_left
141                                                 ? fbuf_chunk : fbuf_left,
142                                         fbuf_left);
143 #ifdef  ASN_EMIT_DEBUG
144                         if(st) {
145                                 fprintf(stderr, "=== currently ===\n");
146                                 asn_fprint(stderr, &asn_DEF_PDU, st);
147                                 fprintf(stderr, "=== end ===\n");
148                         }
149 #endif
150                         switch(how) {
151                         case AS_XER:
152                                 rval = xer_decode(0, &asn_DEF_PDU, (void **)&st,
153                                         fbuf + fbuf_offset,
154                                         fbuf_chunk < fbuf_left 
155                                         ? fbuf_chunk : fbuf_left);
156                                 break;
157                         case AS_PER:
158                                 rval = uper_decode(0, &asn_DEF_PDU,
159                                         (void **)&st, fbuf + fbuf_offset,
160                                         fbuf_chunk < fbuf_left 
161                                         ? fbuf_chunk : fbuf_left, 0, 0);
162                                 if(rval.code == RC_WMORE) {
163                                         rval.consumed = 0; /* Not restartable */
164                                         ASN_STRUCT_FREE(asn_DEF_PDU, st);
165                                         st = 0;
166                                         ASN_DEBUG("-> PER wants more");
167                                 } else {
168                                         ASN_DEBUG("-> PER ret %d/%zd",
169                                                 rval.code, rval.consumed);
170                                         /* uper_decode() returns _bits_ */
171                                         rval.consumed += 7;
172                                         rval.consumed /= 8;
173                                 }
174                                 break;
175             case AS_DER:
176             case AS_CXER:
177                 assert(!"Unexpected DER or CXER load request");
178             default:
179                 assert(!"Unreachable");
180                         }
181                         fbuf_offset += rval.consumed;
182                         fbuf_left -= rval.consumed;
183                         if(rval.code == RC_WMORE)
184                                 fbuf_chunk += 1;        /* Give little more */
185                         else
186                                 fbuf_chunk = csize;     /* Back off */
187                 } while(fbuf_left && rval.code == RC_WMORE);
188
189                 if(expectation != EXP_BROKEN) {
190                         assert(rval.code == RC_OK);
191                         if(how == AS_PER) {
192                                 fprintf(stderr, "[left %d, off %d, size %zd]\n",
193                                         fbuf_left, fbuf_offset, size);
194                                 assert(fbuf_offset == (ssize_t)size);
195                         } else {
196                                 assert((fbuf_offset + 1 /* "\n" */  == (ssize_t)size
197                                         && fbuf[size - 1] == '\n')
198                                 || (fbuf_offset + 2 /* "\r\n" */  == (ssize_t)size
199                                         && fbuf[size - 2] == '\r'
200                                         && fbuf[size - 1] == '\n')
201                                 );
202                         }
203                 } else {
204                         assert(rval.code != RC_OK);
205                         fprintf(stderr, "Failed, but this was expected\n");
206                         ASN_STRUCT_FREE(asn_DEF_PDU, st);
207                         st = 0; /* ignore leak for now */
208                 }
209         }
210
211         if(st) asn_fprint(stderr, &asn_DEF_PDU, st);
212         return st;
213 }
214
215 static int
216 xer_encoding_equal(void *obufp, size_t osize, void *nbufp, size_t nsize) {
217     char *obuf = obufp;
218     char *nbuf = nbufp;
219         char *oend = obuf + osize;
220         char *nend = nbuf + nsize;
221
222         if((osize && !nsize) || (!osize && nsize))
223                 return 0;       /* not equal apriori */
224
225         while(1) {
226                 while(obuf < oend && isspace(*obuf)) obuf++;
227                 while(nbuf < nend && isspace(*nbuf)) nbuf++;
228
229                 if(obuf == oend || nbuf == nend) {
230                         if(obuf == oend && nbuf == nend)
231                                 break;
232                         fprintf(stderr, "%s data in reconstructed encoding\n",
233                                 (obuf == oend) ? "More" : "Less");
234                         return 0;
235                 }
236
237                 if(*obuf != *nbuf) {
238                         printf("%c%c != %c%c\n",
239                                 obuf[0], obuf[1],
240                                 nbuf[0], nbuf[1]);
241                         return 0;
242                 }
243                 obuf++, nbuf++;
244         }
245
246         return 1;
247 }
248
249 static void
250 process_XER_data(const char *fname, enum expectation expectation, unsigned char *fbuf, ssize_t size) {
251         PDU_t *st;
252
253         st = load_object_from(fname, expectation, fbuf, size, AS_XER);
254         if(!st) return;
255
256         /* Save and re-load as PER */
257         save_object_as(st, expectation, AS_PER);
258         ASN_STRUCT_FREE(asn_DEF_PDU, st);
259
260         if(expectation == EXP_PER_NOCOMP)
261                 return; /* Already checked */
262         st = load_object_from("buffer", expectation, buf, buf_offset, AS_PER);
263         assert(st);
264
265         save_object_as(st,
266                         expectation,
267                         (expectation == EXP_CXER_EXACT
268                         || expectation == EXP_CXER_DIFF)
269                         ? AS_CXER : AS_XER);
270         fprintf(stderr, "=== original ===\n");
271         fwrite(fbuf, 1, size, stderr);
272         fprintf(stderr, "=== re-encoded ===\n");
273         fwrite(buf, 1, buf_offset, stderr);
274         fprintf(stderr, "=== end ===\n");
275
276         switch(expectation) {
277         case EXP_DIFFERENT:
278                 assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
279                 break;
280         case EXP_BROKEN:
281                 assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
282                 break;
283         case EXP_CXER_EXACT:
284                 buf[buf_offset++] = '\n';
285                 assert((ssize_t)size == (ssize_t)buf_offset);
286                 assert(memcmp(fbuf, buf, size) == 0);
287                 break;
288         case EXP_CXER_DIFF:
289                 buf[buf_offset++] = '\n';
290                 assert((ssize_t)size != (ssize_t)buf_offset
291                         || memcmp(fbuf, buf, size));
292                 break;
293         case EXP_OK:
294         case EXP_PER_NOCOMP:
295                 assert(xer_encoding_equal(fbuf, size, buf, buf_offset));
296                 break;
297         }
298
299         ASN_STRUCT_FREE(asn_DEF_PDU, st);
300 }
301
302 /*
303  * Decode the .der files and try to regenerate them.
304  */
305 static int
306 process(const char *fname) {
307         unsigned char fbuf[4096];
308         char *ext = strrchr(fname, '.');
309         enum expectation expectation;
310         int rd;
311         FILE *fp;
312
313         if(ext == 0 || strcmp(ext, ".in"))
314                 return 0;
315
316         switch(ext[-1]) {
317         case 'B':       /* The file is intentionally broken */
318                 expectation = EXP_BROKEN; break;
319         case 'D':       /* Reconstructing should yield different data */
320                 expectation = EXP_DIFFERENT; break;
321         case 'E':       /* Byte to byte exact reconstruction */
322                 expectation = EXP_CXER_EXACT; break;
323         case 'X':       /* Should fail byte-to-byte comparison */
324                 expectation = EXP_CXER_DIFF; break;
325         case 'P':       /* Incompatible with PER */
326                 expectation = EXP_PER_NOCOMP; break;
327         default:
328                 expectation = EXP_OK; break;
329         }
330
331         fprintf(stderr, "\nProcessing file [../%s]\n", fname);
332
333         snprintf((char *)fbuf, sizeof(fbuf), SRCDIR_S "/data-119/%s", fname);
334         fp = fopen((char *)fbuf, "r");
335         assert(fp);
336
337         rd = fread(fbuf, 1, sizeof(fbuf), fp);
338         fclose(fp);
339
340         assert(rd < (ssize_t)sizeof(fbuf));     /* expect small files */
341
342         process_XER_data(fname, expectation, fbuf, rd);
343
344         fprintf(stderr, "Finished [%s]\n", fname);
345
346         return 1;
347 }
348
349 int
350 main() {
351         DIR *dir;
352         struct dirent *dent;
353         int processed_files = 0;
354         char *str;
355
356         /* Process a specific test file */
357         str = getenv("DATA_119_FILE");
358         if(str && strncmp(str, "data-119-", 9) == 0) {
359                 process(str);
360                 return 0;
361         }
362
363         dir = opendir(SRCDIR_S "/data-119");
364         assert(dir);
365
366         /*
367          * Process each file in that directory.
368          */
369         while((dent = readdir(dir))) {
370                 if(strncmp(dent->d_name, "data-119-", 9) == 0)
371                         if(process(dent->d_name))
372                                 processed_files++;
373         }
374
375         assert(processed_files);
376         closedir(dir);
377
378         return 0;
379 }
380