blob: 4a53bc94df34d1f23eb7041da63a718c92b9b9ac [file] [log] [blame]
Lev Walkin22b54552004-10-28 13:22:54 +00001/*
2 * This is a generic BER decoder template for any ASN.1 type.
3 *
Lev Walkinc490ff82005-03-10 11:59:44 +00004 * To compile with your own ASN.1 type, please redefine the asn_DEF as shown:
Lev Walkin22b54552004-10-28 13:22:54 +00005 *
Lev Walkinc490ff82005-03-10 11:59:44 +00006 * cc -Dasn_DEF=asn_DEF_MyCustomType -o myDecoder.o -c asn-decoder-template.c
Lev Walkin22b54552004-10-28 13:22:54 +00007 */
8#ifdef HAVE_CONFIG_H
9#include <config.h>
10#endif
11#include <stdio.h>
12#include <sys/types.h>
13#include <unistd.h> /* for getopt */
14#include <string.h> /* for strerror(3) */
Lev Walkin22b54552004-10-28 13:22:54 +000015#include <sysexits.h> /* for EX_* exit codes */
Lev Walkinfc776432005-03-29 17:21:14 +000016#include <assert.h> /* for assert(3) */
17#include <errno.h> /* for errno */
Lev Walkin22b54552004-10-28 13:22:54 +000018
Lev Walkin00949562005-03-10 13:39:03 +000019#include <asn_application.h>
Lev Walkin22b54552004-10-28 13:22:54 +000020
21extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */
22
23/*
Lev Walkin00949562005-03-10 13:39:03 +000024 * Open file and parse its contens.
Lev Walkin22b54552004-10-28 13:22:54 +000025 */
Lev Walkin00949562005-03-10 13:39:03 +000026static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
27 const char *fname, ssize_t suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +000028
29 int opt_debug; /* -d */
30static int opt_check; /* -c */
31static int opt_print; /* -p */
32static int opt_stack; /* -s */
Lev Walkin7bee1282005-04-28 02:59:51 +000033static enum output_method {
34 OUT_NONE, /* No pretty-printing */
35 OUT_PRINT, /* -p flag */
36 OUT_XML, /* -x flag */
37} opt_ometh; /* -p or -x */
Lev Walkin22b54552004-10-28 13:22:54 +000038
39#define DEBUG(fmt, args...) do { \
40 if(!opt_debug) break; \
41 fprintf(stderr, fmt, ##args); \
42 fprintf(stderr, "\n"); \
43} while(0)
44
45int
46main(int ac, char **av) {
47 ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
Lev Walkin00949562005-03-10 13:39:03 +000048 asn_TYPE_descriptor_t *pduType = &asn_DEF;
Lev Walkin22b54552004-10-28 13:22:54 +000049 int number_of_iterations = 1;
50 int num;
51 int ch;
52
53 /*
54 * Pocess the command-line argments.
55 */
56 while((ch = getopt(ac, av, "b:cdn:hps:x")) != -1)
57 switch(ch) {
58 case 'b':
59 suggested_bufsize = atoi(optarg);
60 if(suggested_bufsize < 1
61 || suggested_bufsize > 16 * 1024 * 1024) {
62 fprintf(stderr,
63 "-b %s: Improper buffer size (1..16M)\n",
64 optarg);
65 exit(EX_UNAVAILABLE);
66 }
67 break;
68 case 'c':
69 opt_check = 1;
70 break;
71 case 'd':
72 opt_debug++; /* Double -dd means ASN.1 debug */
73 break;
74 case 'n':
75 number_of_iterations = atoi(optarg);
76 if(number_of_iterations < 1) {
77 fprintf(stderr,
78 "-n %s: Improper iterations count\n", optarg);
79 exit(EX_UNAVAILABLE);
80 }
81 break;
82 case 'p':
Lev Walkin7bee1282005-04-28 02:59:51 +000083 opt_ometh = OUT_PRINT;
Lev Walkin22b54552004-10-28 13:22:54 +000084 break;
85 case 's':
86 opt_stack = atoi(optarg);
87 if(opt_stack <= 0) {
88 fprintf(stderr,
89 "-s %s: Value greater than 0 expected\n",
90 optarg);
91 exit(EX_UNAVAILABLE);
92 }
93 break;
94 case 'x':
Lev Walkin7bee1282005-04-28 02:59:51 +000095 opt_ometh = OUT_XML;
Lev Walkin22b54552004-10-28 13:22:54 +000096 break;
97 case 'h':
98 default:
99 fprintf(stderr,
100 "Usage: %s [options] <data.ber> ...\n"
101 "Where options are:\n"
102 " -b <size> Set the i/o buffer size (default is %ld)\n"
103 " -c Check ASN.1 constraints after decoding\n"
104 " -d Enable debugging (-dd is even better)\n"
105 " -n <num> Process files <num> times\n"
106 " -s <size> Set the stack usage limit\n"
107 " -p Print out the decoded contents\n"
Lev Walkin5ba113b2005-04-08 19:28:18 +0000108 " -x Print out as XML"
109#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
110 " (default)"
111#endif
112 "\n"
Lev Walkin22b54552004-10-28 13:22:54 +0000113 , av[0], (long)suggested_bufsize);
114 exit(EX_USAGE);
115 }
116
117 ac -= optind;
118 av += optind;
119
120 if(ac < 1) {
121 fprintf(stderr, "Error: missing filename\n");
122 exit(EX_USAGE);
123 }
124
Lev Walkin5ba113b2005-04-08 19:28:18 +0000125#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
Lev Walkin7bee1282005-04-28 02:59:51 +0000126 if(opt_ometh == OUT_NONE) opt_ometh = OUT_XML;
Lev Walkin5ba113b2005-04-08 19:28:18 +0000127#endif
128
Lev Walkin22b54552004-10-28 13:22:54 +0000129 setvbuf(stdout, 0, _IOLBF, 0);
130
131 for(num = 0; num < number_of_iterations; num++) {
132 int ac_i;
133 /*
134 * Process all files in turn.
135 */
136 for(ac_i = 0; ac_i < ac; ac_i++) {
137 char *fname = av[ac_i];
138 void *structure;
139
140 /*
141 * Decode the encoded structure from file.
142 */
Lev Walkin00949562005-03-10 13:39:03 +0000143 structure = data_decode_from_file(pduType,
144 fname, suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +0000145 if(!structure) {
146 /* Error message is already printed */
147 exit(EX_DATAERR);
148 }
149
Lev Walkin7bee1282005-04-28 02:59:51 +0000150 switch(opt_ometh) {
151 case OUT_NONE:
152 fprintf(stderr, "%s: decoded successfully\n", fname);
153 break;
154 case OUT_PRINT: /* -p */
155 asn_fprint(stdout, pduType, structure);
156 break;
157 case OUT_XML: /* -x */
158 if(xer_fprint(stdout, pduType, structure)) {
159 fprintf(stderr, "%s: Cannot convert into XML\n",
160 fname);
161 exit(EX_UNAVAILABLE);
162 }
163 break;
Lev Walkin22b54552004-10-28 13:22:54 +0000164 }
165
166 /* Check ASN.1 constraints */
167 if(opt_check) {
168 char errbuf[128];
169 size_t errlen = sizeof(errbuf);
Lev Walkin00949562005-03-10 13:39:03 +0000170 if(asn_check_constraints(pduType, structure,
Lev Walkin22b54552004-10-28 13:22:54 +0000171 errbuf, &errlen)) {
172 fprintf(stderr, "%s: ASN.1 constraint "
173 "check failed: %s\n", fname, errbuf);
174 exit(EX_DATAERR);
175 }
176 }
177
Lev Walkin00949562005-03-10 13:39:03 +0000178 pduType->free_struct(pduType, structure, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000179 }
180 }
181
182 return 0;
183}
184
185
186static char *buffer;
187static size_t buf_offset; /* Offset from the start */
188static size_t buf_len; /* Length of meaningful contents */
189static size_t buf_size; /* Allocated memory */
190static off_t buf_shifted; /* Number of bytes ever shifted */
191
192#define bufptr (buffer + buf_offset)
193#define bufend (buffer + buf_offset + buf_len)
194
195/*
196 * Ensure that the buffer contains at least this amoount of free space.
197 */
198static void buf_extend(size_t bySize) {
199
200 DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
201 (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
202
203 if(buf_size >= (buf_offset + buf_len + bySize)) {
204 return; /* Nothing to do */
205 } else if(bySize <= buf_offset) {
206 DEBUG("\tContents shifted by %ld", (long)buf_offset);
207
208 /* Shift the buffer contents */
209 memmove(buffer, buffer + buf_offset, buf_len);
210 buf_shifted += buf_offset;
211 buf_offset = 0;
212 } else {
213 size_t newsize = (buf_size << 2) + bySize;
214 void *p = realloc(buffer, newsize);
215 if(p) {
Lev Walkin814cca72004-12-15 23:23:53 +0000216 buffer = (char *)p;
Lev Walkin22b54552004-10-28 13:22:54 +0000217 buf_size = newsize;
218
219 DEBUG("\tBuffer reallocated to %ld", (long)newsize);
220 } else {
221 perror("realloc()");
222 exit(EX_OSERR);
223 }
224 }
225}
226
Lev Walkin00949562005-03-10 13:39:03 +0000227static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
Lev Walkin22b54552004-10-28 13:22:54 +0000228 static char *fbuf;
229 static ssize_t fbuf_size;
230 static asn_codec_ctx_t s_codec_ctx;
231 asn_codec_ctx_t *opt_codec_ctx = 0;
232 void *structure = 0;
233 size_t rd;
234 FILE *fp;
235
236 if(opt_stack) {
237 s_codec_ctx.max_stack_size = opt_stack;
238 opt_codec_ctx = &s_codec_ctx;
239 }
240
241 DEBUG("Processing file %s", fname);
242
243 fp = fopen(fname, "r");
244
245 if(!fp) {
246 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
247 return 0;
248 }
249
250 /* prepare the file buffer */
251 if(fbuf_size != suggested_bufsize) {
Lev Walkin814cca72004-12-15 23:23:53 +0000252 fbuf = (char *)realloc(fbuf, suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +0000253 if(!fbuf) {
254 perror("realloc()");
255 exit(EX_OSERR);
256 }
257 fbuf_size = suggested_bufsize;
258 }
259
260 buf_shifted = 0;
261 buf_offset = 0;
262 buf_len = 0;
263
264 while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
265 asn_dec_rval_t rval;
266 int using_local_buf;
267
268 /*
269 * Copy the data over, or use the original buffer.
270 */
271 if(buf_len) {
272 /* Append the new data into the intermediate buffer */
273 buf_extend(rd);
274 memcpy(bufend, fbuf, rd);
275 buf_len += rd;
276
Lev Walkin00949562005-03-10 13:39:03 +0000277 rval = ber_decode(opt_codec_ctx, pduType,
Lev Walkin22b54552004-10-28 13:22:54 +0000278 (void **)&structure, bufptr, buf_len);
279 DEBUG("ber_decode(%ld) consumed %ld, code %d",
280 (long)buf_len, (long)rval.consumed, rval.code);
281
282 /*
283 * Adjust position inside the source buffer.
284 */
285 assert(rval.consumed <= buf_len);
286 buf_offset += rval.consumed;
287 buf_len -= rval.consumed;
288 } else {
289 using_local_buf = 1;
290
Lev Walkin00949562005-03-10 13:39:03 +0000291 /* Feed the chunk of data into a decoder routine */
292 rval = ber_decode(opt_codec_ctx, pduType,
Lev Walkin22b54552004-10-28 13:22:54 +0000293 (void **)&structure, fbuf, rd);
294 DEBUG("ber_decode(%ld) consumed %ld, code %d",
295 (long)rd, (long)rval.consumed, rval.code);
296
297 /*
298 * Switch the remainder into the intermediate buffer.
299 */
300 if(rval.code != RC_FAIL && rval.consumed < rd) {
301 buf_extend(rd - rval.consumed);
302 memcpy(bufend,
303 fbuf + rval.consumed,
304 rd - rval.consumed);
305 buf_len = rd - rval.consumed;
306 }
307 }
308
309 switch(rval.code) {
310 case RC_OK:
311 DEBUG("RC_OK, finishing up");
312 fclose(fp);
313 return structure;
314 case RC_WMORE:
315 DEBUG("RC_WMORE, continuing...");
316 continue;
317 case RC_FAIL:
318 break;
319 }
320 break;
321 }
322
323 fclose(fp);
324
325 /* Clean up partially decoded structure */
Lev Walkin00949562005-03-10 13:39:03 +0000326 pduType->free_struct(pduType, structure, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000327
328 fprintf(stderr, "%s: "
Lev Walkin00949562005-03-10 13:39:03 +0000329 "Decode failed past %lld byte\n",
Lev Walkin22b54552004-10-28 13:22:54 +0000330 fname, (long long)(buf_shifted + buf_offset));
331
332 return 0;
333}
334