blob: c50d8b9c146eda1e89c182273bebcde4f8b48089 [file] [log] [blame]
vlm0e329f22004-10-28 13:22:54 +00001/*
vlm6d44a542005-11-08 03:06:16 +00002 * Generic decoder template for a selected ASN.1 type.
vlmcb14b502005-08-16 03:19:59 +00003 * Copyright (c) 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
vlm0e329f22004-10-28 13:22:54 +00004 *
vlme641d392005-03-10 11:59:44 +00005 * To compile with your own ASN.1 type, please redefine the asn_DEF as shown:
vlm0e329f22004-10-28 13:22:54 +00006 *
vlme641d392005-03-10 11:59:44 +00007 * cc -Dasn_DEF=asn_DEF_MyCustomType -o myDecoder.o -c asn-decoder-template.c
vlm0e329f22004-10-28 13:22:54 +00008 */
9#ifdef HAVE_CONFIG_H
10#include <config.h>
11#endif
12#include <stdio.h>
13#include <sys/types.h>
vlm066dc102005-08-22 12:23:54 +000014#include <stdlib.h> /* for atoi(3) */
15#include <unistd.h> /* for getopt(3) */
vlm0e329f22004-10-28 13:22:54 +000016#include <string.h> /* for strerror(3) */
vlm0e329f22004-10-28 13:22:54 +000017#include <sysexits.h> /* for EX_* exit codes */
vlm5ec2fe12005-03-29 17:21:14 +000018#include <assert.h> /* for assert(3) */
19#include <errno.h> /* for errno */
vlm0e329f22004-10-28 13:22:54 +000020
vlme3470e72005-03-10 13:39:03 +000021#include <asn_application.h>
vlm0e329f22004-10-28 13:22:54 +000022
23extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */
vlm337167e2005-11-26 11:25:14 +000024#ifdef ASN_PDU_COLLECTION /* Generated by asn1c: -pdu=... */
25extern asn_TYPE_descriptor_t *asn_pdu_collection[];
26#endif
vlm0e329f22004-10-28 13:22:54 +000027
28/*
vlme3470e72005-03-10 13:39:03 +000029 * Open file and parse its contens.
vlm0e329f22004-10-28 13:22:54 +000030 */
vlme3470e72005-03-10 13:39:03 +000031static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
32 const char *fname, ssize_t suggested_bufsize);
vlm6d44a542005-11-08 03:06:16 +000033static int write_out(const void *buffer, size_t size, void *key);
vlm0e329f22004-10-28 13:22:54 +000034
35 int opt_debug; /* -d */
36static int opt_check; /* -c */
vlm0e329f22004-10-28 13:22:54 +000037static int opt_stack; /* -s */
vlm6d44a542005-11-08 03:06:16 +000038
39/* Input data format selector */
40static enum input_format {
41 INP_BER, /* -iber: BER input */
vlm337167e2005-11-26 11:25:14 +000042 INP_XER, /* -ixer: XER input */
43 INP_PER /* -iper: Unaligned PER input */
vlm6d44a542005-11-08 03:06:16 +000044} iform; /* -i<format> */
45
46/* Output data format selector */
47static enum output_format {
48 OUT_XER, /* -oxer: XER (XML) output */
49 OUT_DER, /* -oder: DER output */
50 OUT_TEXT, /* -otext: semi-structured text */
51 OUT_NULL /* -onull: No pretty-printing */
52} oform; /* -o<format> */
vlm0e329f22004-10-28 13:22:54 +000053
54#define DEBUG(fmt, args...) do { \
55 if(!opt_debug) break; \
56 fprintf(stderr, fmt, ##args); \
57 fprintf(stderr, "\n"); \
58} while(0)
59
60int
61main(int ac, char **av) {
vlm337167e2005-11-26 11:25:14 +000062 static asn_TYPE_descriptor_t *pduType = &asn_DEF;
vlm0e329f22004-10-28 13:22:54 +000063 ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
64 int number_of_iterations = 1;
65 int num;
66 int ch;
67
vlm337167e2005-11-26 11:25:14 +000068 /* Figure out if Unaligned PER needs to be default */
69 if(pduType->uper_decoder)
70 iform = INP_PER;
71
vlm0e329f22004-10-28 13:22:54 +000072 /*
73 * Pocess the command-line argments.
74 */
vlm337167e2005-11-26 11:25:14 +000075 while((ch = getopt(ac, av, "i:o:b:cdn:p:hs:")) != -1)
vlm0e329f22004-10-28 13:22:54 +000076 switch(ch) {
vlm6d44a542005-11-08 03:06:16 +000077 case 'i':
78 if(optarg[0] == 'b') { iform = INP_BER; break; }
79 if(optarg[0] == 'x') { iform = INP_XER; break; }
vlm337167e2005-11-26 11:25:14 +000080 if(pduType->uper_decoder
81 && optarg[0] == 'p') { iform = INP_PER; break; }
vlm6d44a542005-11-08 03:06:16 +000082 fprintf(stderr, "-i<format>: '%s': improper format selector",
83 optarg);
84 exit(EX_UNAVAILABLE);
85 case 'o':
86 if(optarg[0] == 'd') { oform = OUT_DER; break; }
87 if(optarg[0] == 'x') { oform = OUT_XER; break; }
88 if(optarg[0] == 't') { oform = OUT_TEXT; break; }
89 if(optarg[0] == 'n') { oform = OUT_NULL; break; }
90 fprintf(stderr, "-o<format>: '%s': improper format selector",
91 optarg);
92 exit(EX_UNAVAILABLE);
vlm337167e2005-11-26 11:25:14 +000093 case 'p':
94#ifdef ASN_PDU_COLLECTION
95 {
96 asn_TYPE_descriptor_t **pdu = asn_pdu_collection;
97 if(optarg[0] < 'A' || optarg[0] > 'Z') {
98 fprintf(stderr, "Available PDU types:\n");
99 for(; *pdu; pdu++) printf("%s\n", (*pdu)->name);
100 exit(0);
101 }
102 while(*pdu && strcmp((*pdu)->name, optarg)) pdu++;
103 if(*pdu) { pduType = *pdu; break; }
104 }
105#endif /* ASN_PDU_COLLECTION */
106 fprintf(stderr, "-p %s: Unrecognized PDU\n", optarg);
107 exit(EX_UNAVAILABLE);
vlm0e329f22004-10-28 13:22:54 +0000108 case 'b':
109 suggested_bufsize = atoi(optarg);
110 if(suggested_bufsize < 1
111 || suggested_bufsize > 16 * 1024 * 1024) {
112 fprintf(stderr,
113 "-b %s: Improper buffer size (1..16M)\n",
114 optarg);
115 exit(EX_UNAVAILABLE);
116 }
117 break;
118 case 'c':
119 opt_check = 1;
120 break;
121 case 'd':
122 opt_debug++; /* Double -dd means ASN.1 debug */
123 break;
124 case 'n':
125 number_of_iterations = atoi(optarg);
126 if(number_of_iterations < 1) {
127 fprintf(stderr,
128 "-n %s: Improper iterations count\n", optarg);
129 exit(EX_UNAVAILABLE);
130 }
131 break;
vlm0e329f22004-10-28 13:22:54 +0000132 case 's':
133 opt_stack = atoi(optarg);
134 if(opt_stack <= 0) {
135 fprintf(stderr,
136 "-s %s: Value greater than 0 expected\n",
137 optarg);
138 exit(EX_UNAVAILABLE);
139 }
140 break;
vlm0e329f22004-10-28 13:22:54 +0000141 case 'h':
142 default:
vlm337167e2005-11-26 11:25:14 +0000143 fprintf(stderr, "Usage: %s [options] <data.ber> ...\n", av[0]);
144 fprintf(stderr, "Where options are:\n");
145 if(pduType->uper_decoder)
vlm0e329f22004-10-28 13:22:54 +0000146 fprintf(stderr,
vlm337167e2005-11-26 11:25:14 +0000147 " -iper (I) Input is in Unaligned PER (Packed Encoding Rules)\n");
148 fprintf(stderr,
149 " -iber %s Input is in BER (Basic Encoding Rules)\n",
150 iform == INP_PER ? " " : "(I)");
151 fprintf(stderr,
vlm6d44a542005-11-08 03:06:16 +0000152 " -ixer Input is in XER (XML Encoding Rules)\n"
153 " -oder Output in DER (Distinguished Encoding Rules)\n"
154 " -oxer (O) Output in XER (XML Encoding Rules)\n"
155 " -otext Output in plain semi-structured text (dump)\n"
vlm337167e2005-11-26 11:25:14 +0000156 " -onull Verify (decode) input, but do not output\n");
157#ifdef ASN_PDU_COLLECTION
158 fprintf(stderr,
159 " -p <PDU> Specify PDU type to decode\n"
160 " -p list List available PDUs\n");
161#endif /* ASN_PDU_COLLECTION */
162 fprintf(stderr,
vlm0e329f22004-10-28 13:22:54 +0000163 " -b <size> Set the i/o buffer size (default is %ld)\n"
164 " -c Check ASN.1 constraints after decoding\n"
165 " -d Enable debugging (-dd is even better)\n"
166 " -n <num> Process files <num> times\n"
167 " -s <size> Set the stack usage limit\n"
vlm337167e2005-11-26 11:25:14 +0000168 , (long)suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000169 exit(EX_USAGE);
170 }
171
172 ac -= optind;
173 av += optind;
174
175 if(ac < 1) {
vlm6d44a542005-11-08 03:06:16 +0000176 fprintf(stderr, "%s: No input files specified. "
177 "Try '-h' for more information\n",
178 av[-optind]);
vlm0e329f22004-10-28 13:22:54 +0000179 exit(EX_USAGE);
180 }
181
182 setvbuf(stdout, 0, _IOLBF, 0);
183
184 for(num = 0; num < number_of_iterations; num++) {
185 int ac_i;
186 /*
187 * Process all files in turn.
188 */
189 for(ac_i = 0; ac_i < ac; ac_i++) {
190 char *fname = av[ac_i];
191 void *structure;
vlm6d44a542005-11-08 03:06:16 +0000192 asn_enc_rval_t erv;
vlm0e329f22004-10-28 13:22:54 +0000193
194 /*
195 * Decode the encoded structure from file.
196 */
vlme3470e72005-03-10 13:39:03 +0000197 structure = data_decode_from_file(pduType,
198 fname, suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000199 if(!structure) {
200 /* Error message is already printed */
201 exit(EX_DATAERR);
202 }
203
vlm0e329f22004-10-28 13:22:54 +0000204 /* Check ASN.1 constraints */
205 if(opt_check) {
206 char errbuf[128];
207 size_t errlen = sizeof(errbuf);
vlme3470e72005-03-10 13:39:03 +0000208 if(asn_check_constraints(pduType, structure,
vlm0e329f22004-10-28 13:22:54 +0000209 errbuf, &errlen)) {
210 fprintf(stderr, "%s: ASN.1 constraint "
211 "check failed: %s\n", fname, errbuf);
212 exit(EX_DATAERR);
213 }
214 }
215
vlm6d44a542005-11-08 03:06:16 +0000216 switch(oform) {
217 case OUT_NULL:
218 fprintf(stderr, "%s: decoded successfully\n", fname);
219 break;
220 case OUT_TEXT: /* -otext */
221 asn_fprint(stdout, pduType, structure);
222 break;
223 case OUT_XER: /* -oxer */
224 if(xer_fprint(stdout, pduType, structure)) {
225 fprintf(stderr, "%s: Cannot convert into XML\n",
226 fname);
227 exit(EX_UNAVAILABLE);
228 }
229 break;
230 case OUT_DER:
231 erv = der_encode(pduType, structure, write_out, stdout);
232 if(erv.encoded < 0) {
233 fprintf(stderr, "%s: Cannot convert into DER\n",
234 fname);
235 exit(EX_UNAVAILABLE);
236 }
237 break;
238 }
239
vlme3470e72005-03-10 13:39:03 +0000240 pduType->free_struct(pduType, structure, 0);
vlm0e329f22004-10-28 13:22:54 +0000241 }
242 }
243
244 return 0;
245}
246
vlm6d44a542005-11-08 03:06:16 +0000247/* Dump the buffer */
248static int write_out(const void *buffer, size_t size, void *key) {
vlm337167e2005-11-26 11:25:14 +0000249 FILE *fp = (FILE *)key;
250 return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1;
vlm6d44a542005-11-08 03:06:16 +0000251}
vlm0e329f22004-10-28 13:22:54 +0000252
253static char *buffer;
254static size_t buf_offset; /* Offset from the start */
255static size_t buf_len; /* Length of meaningful contents */
256static size_t buf_size; /* Allocated memory */
257static off_t buf_shifted; /* Number of bytes ever shifted */
258
259#define bufptr (buffer + buf_offset)
260#define bufend (buffer + buf_offset + buf_len)
261
262/*
vlm6d44a542005-11-08 03:06:16 +0000263 * Ensure that the buffer contains at least this amount of free space.
vlm0e329f22004-10-28 13:22:54 +0000264 */
265static void buf_extend(size_t bySize) {
266
267 DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
268 (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
269
270 if(buf_size >= (buf_offset + buf_len + bySize)) {
271 return; /* Nothing to do */
272 } else if(bySize <= buf_offset) {
273 DEBUG("\tContents shifted by %ld", (long)buf_offset);
274
275 /* Shift the buffer contents */
276 memmove(buffer, buffer + buf_offset, buf_len);
277 buf_shifted += buf_offset;
278 buf_offset = 0;
279 } else {
280 size_t newsize = (buf_size << 2) + bySize;
281 void *p = realloc(buffer, newsize);
282 if(p) {
vlmd3c80792004-12-15 23:23:53 +0000283 buffer = (char *)p;
vlm0e329f22004-10-28 13:22:54 +0000284 buf_size = newsize;
285
286 DEBUG("\tBuffer reallocated to %ld", (long)newsize);
287 } else {
288 perror("realloc()");
289 exit(EX_OSERR);
290 }
291 }
292}
293
vlme3470e72005-03-10 13:39:03 +0000294static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
vlm0e329f22004-10-28 13:22:54 +0000295 static char *fbuf;
296 static ssize_t fbuf_size;
297 static asn_codec_ctx_t s_codec_ctx;
298 asn_codec_ctx_t *opt_codec_ctx = 0;
299 void *structure = 0;
vlm6d44a542005-11-08 03:06:16 +0000300 asn_dec_rval_t rval;
vlm0e329f22004-10-28 13:22:54 +0000301 size_t rd;
302 FILE *fp;
303
304 if(opt_stack) {
305 s_codec_ctx.max_stack_size = opt_stack;
306 opt_codec_ctx = &s_codec_ctx;
307 }
308
vlm6d44a542005-11-08 03:06:16 +0000309 if(strcmp(fname, "-")) {
310 DEBUG("Processing file %s", fname);
311 fp = fopen(fname, "r");
312 } else {
313 DEBUG("Processing standard input");
314 fname = "stdin";
315 fp = stdin;
316 }
vlm0e329f22004-10-28 13:22:54 +0000317
318 if(!fp) {
319 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
320 return 0;
321 }
322
323 /* prepare the file buffer */
324 if(fbuf_size != suggested_bufsize) {
vlmd3c80792004-12-15 23:23:53 +0000325 fbuf = (char *)realloc(fbuf, suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000326 if(!fbuf) {
327 perror("realloc()");
328 exit(EX_OSERR);
329 }
330 fbuf_size = suggested_bufsize;
331 }
332
333 buf_shifted = 0;
334 buf_offset = 0;
335 buf_len = 0;
336
vlm6d44a542005-11-08 03:06:16 +0000337 /* Pretend immediate EOF */
338 rval.code = RC_WMORE;
339 rval.consumed = 0;
340
vlm0e329f22004-10-28 13:22:54 +0000341 while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
vlm337167e2005-11-26 11:25:14 +0000342 asn_per_data_t pd;
vlm6d44a542005-11-08 03:06:16 +0000343 char *i_bptr;
344 size_t i_size;
vlm0e329f22004-10-28 13:22:54 +0000345
346 /*
347 * Copy the data over, or use the original buffer.
348 */
349 if(buf_len) {
350 /* Append the new data into the intermediate buffer */
351 buf_extend(rd);
352 memcpy(bufend, fbuf, rd);
353 buf_len += rd;
354
vlm6d44a542005-11-08 03:06:16 +0000355 i_bptr = bufptr;
356 i_size = buf_len;
vlm0e329f22004-10-28 13:22:54 +0000357 } else {
vlm6d44a542005-11-08 03:06:16 +0000358 i_bptr = fbuf;
359 i_size = rd;
360 }
vlm0e329f22004-10-28 13:22:54 +0000361
vlm6d44a542005-11-08 03:06:16 +0000362 switch(iform) {
363 case INP_BER:
vlme3470e72005-03-10 13:39:03 +0000364 rval = ber_decode(opt_codec_ctx, pduType,
vlm6d44a542005-11-08 03:06:16 +0000365 (void **)&structure, i_bptr, i_size);
366 break;
367 case INP_XER:
368 rval = xer_decode(opt_codec_ctx, pduType,
369 (void **)&structure, i_bptr, i_size);
370 break;
vlm337167e2005-11-26 11:25:14 +0000371 case INP_PER:
372 pd.buffer = (uint8_t *)i_bptr;
373 pd.nboff = 0;
374 pd.nbits = i_size * 8;
375 rval = pduType->uper_decoder(opt_codec_ctx, pduType, 0,
376 (void **)&structure, &pd);
377 break;
vlm6d44a542005-11-08 03:06:16 +0000378 }
379 DEBUG("decode(%ld) consumed %ld, code %d",
380 (long)buf_len, (long)rval.consumed, rval.code);
vlm0e329f22004-10-28 13:22:54 +0000381
vlm6d44a542005-11-08 03:06:16 +0000382 if(buf_len == 0) {
vlm0e329f22004-10-28 13:22:54 +0000383 /*
384 * Switch the remainder into the intermediate buffer.
385 */
386 if(rval.code != RC_FAIL && rval.consumed < rd) {
387 buf_extend(rd - rval.consumed);
388 memcpy(bufend,
389 fbuf + rval.consumed,
390 rd - rval.consumed);
391 buf_len = rd - rval.consumed;
392 }
393 }
394
395 switch(rval.code) {
396 case RC_OK:
397 DEBUG("RC_OK, finishing up");
vlm6d44a542005-11-08 03:06:16 +0000398 if(fp != stdin) fclose(fp);
vlm0e329f22004-10-28 13:22:54 +0000399 return structure;
400 case RC_WMORE:
401 DEBUG("RC_WMORE, continuing...");
vlm6d44a542005-11-08 03:06:16 +0000402 /*
403 * Adjust position inside the source buffer.
404 */
405 buf_offset += rval.consumed;
406 buf_len -= rval.consumed;
407 rval.consumed = 0;
vlm0e329f22004-10-28 13:22:54 +0000408 continue;
409 case RC_FAIL:
410 break;
411 }
412 break;
413 }
414
415 fclose(fp);
416
417 /* Clean up partially decoded structure */
vlme3470e72005-03-10 13:39:03 +0000418 pduType->free_struct(pduType, structure, 0);
vlm0e329f22004-10-28 13:22:54 +0000419
420 fprintf(stderr, "%s: "
vlm6d44a542005-11-08 03:06:16 +0000421 "Decode failed past byte %ld: %s\n",
422 fname, (long)(buf_shifted + buf_offset + rval.consumed),
423 (rval.code == RC_WMORE)
424 ? "Unexpected end of input"
425 : "Input processing error");
vlm0e329f22004-10-28 13:22:54 +0000426
427 return 0;
428}
429