blob: 5116529d86ef3770dc05e664231f09b071f01e65 [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 */
Lev Walkin22b54552004-10-28 13:22:54 +000031static int opt_stack; /* -s */
Lev Walkin7bee1282005-04-28 02:59:51 +000032static enum output_method {
33 OUT_NONE, /* No pretty-printing */
34 OUT_PRINT, /* -p flag */
35 OUT_XML, /* -x flag */
36} opt_ometh; /* -p or -x */
Lev Walkin22b54552004-10-28 13:22:54 +000037
38#define DEBUG(fmt, args...) do { \
39 if(!opt_debug) break; \
40 fprintf(stderr, fmt, ##args); \
41 fprintf(stderr, "\n"); \
42} while(0)
43
44int
45main(int ac, char **av) {
46 ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
Lev Walkin00949562005-03-10 13:39:03 +000047 asn_TYPE_descriptor_t *pduType = &asn_DEF;
Lev Walkin22b54552004-10-28 13:22:54 +000048 int number_of_iterations = 1;
49 int num;
50 int ch;
51
52 /*
53 * Pocess the command-line argments.
54 */
55 while((ch = getopt(ac, av, "b:cdn:hps:x")) != -1)
56 switch(ch) {
57 case 'b':
58 suggested_bufsize = atoi(optarg);
59 if(suggested_bufsize < 1
60 || suggested_bufsize > 16 * 1024 * 1024) {
61 fprintf(stderr,
62 "-b %s: Improper buffer size (1..16M)\n",
63 optarg);
64 exit(EX_UNAVAILABLE);
65 }
66 break;
67 case 'c':
68 opt_check = 1;
69 break;
70 case 'd':
71 opt_debug++; /* Double -dd means ASN.1 debug */
72 break;
73 case 'n':
74 number_of_iterations = atoi(optarg);
75 if(number_of_iterations < 1) {
76 fprintf(stderr,
77 "-n %s: Improper iterations count\n", optarg);
78 exit(EX_UNAVAILABLE);
79 }
80 break;
81 case 'p':
Lev Walkin7bee1282005-04-28 02:59:51 +000082 opt_ometh = OUT_PRINT;
Lev Walkin22b54552004-10-28 13:22:54 +000083 break;
84 case 's':
85 opt_stack = atoi(optarg);
86 if(opt_stack <= 0) {
87 fprintf(stderr,
88 "-s %s: Value greater than 0 expected\n",
89 optarg);
90 exit(EX_UNAVAILABLE);
91 }
92 break;
93 case 'x':
Lev Walkin7bee1282005-04-28 02:59:51 +000094 opt_ometh = OUT_XML;
Lev Walkin22b54552004-10-28 13:22:54 +000095 break;
96 case 'h':
97 default:
98 fprintf(stderr,
99 "Usage: %s [options] <data.ber> ...\n"
100 "Where options are:\n"
101 " -b <size> Set the i/o buffer size (default is %ld)\n"
102 " -c Check ASN.1 constraints after decoding\n"
103 " -d Enable debugging (-dd is even better)\n"
104 " -n <num> Process files <num> times\n"
105 " -s <size> Set the stack usage limit\n"
106 " -p Print out the decoded contents\n"
Lev Walkin5ba113b2005-04-08 19:28:18 +0000107 " -x Print out as XML"
108#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
109 " (default)"
110#endif
111 "\n"
Lev Walkin22b54552004-10-28 13:22:54 +0000112 , av[0], (long)suggested_bufsize);
113 exit(EX_USAGE);
114 }
115
116 ac -= optind;
117 av += optind;
118
119 if(ac < 1) {
120 fprintf(stderr, "Error: missing filename\n");
121 exit(EX_USAGE);
122 }
123
Lev Walkin5ba113b2005-04-08 19:28:18 +0000124#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
Lev Walkin7bee1282005-04-28 02:59:51 +0000125 if(opt_ometh == OUT_NONE) opt_ometh = OUT_XML;
Lev Walkin5ba113b2005-04-08 19:28:18 +0000126#endif
127
Lev Walkin22b54552004-10-28 13:22:54 +0000128 setvbuf(stdout, 0, _IOLBF, 0);
129
130 for(num = 0; num < number_of_iterations; num++) {
131 int ac_i;
132 /*
133 * Process all files in turn.
134 */
135 for(ac_i = 0; ac_i < ac; ac_i++) {
136 char *fname = av[ac_i];
137 void *structure;
138
139 /*
140 * Decode the encoded structure from file.
141 */
Lev Walkin00949562005-03-10 13:39:03 +0000142 structure = data_decode_from_file(pduType,
143 fname, suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +0000144 if(!structure) {
145 /* Error message is already printed */
146 exit(EX_DATAERR);
147 }
148
Lev Walkin7bee1282005-04-28 02:59:51 +0000149 switch(opt_ometh) {
150 case OUT_NONE:
151 fprintf(stderr, "%s: decoded successfully\n", fname);
152 break;
153 case OUT_PRINT: /* -p */
154 asn_fprint(stdout, pduType, structure);
155 break;
156 case OUT_XML: /* -x */
157 if(xer_fprint(stdout, pduType, structure)) {
158 fprintf(stderr, "%s: Cannot convert into XML\n",
159 fname);
160 exit(EX_UNAVAILABLE);
161 }
162 break;
Lev Walkin22b54552004-10-28 13:22:54 +0000163 }
164
165 /* Check ASN.1 constraints */
166 if(opt_check) {
167 char errbuf[128];
168 size_t errlen = sizeof(errbuf);
Lev Walkin00949562005-03-10 13:39:03 +0000169 if(asn_check_constraints(pduType, structure,
Lev Walkin22b54552004-10-28 13:22:54 +0000170 errbuf, &errlen)) {
171 fprintf(stderr, "%s: ASN.1 constraint "
172 "check failed: %s\n", fname, errbuf);
173 exit(EX_DATAERR);
174 }
175 }
176
Lev Walkin00949562005-03-10 13:39:03 +0000177 pduType->free_struct(pduType, structure, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000178 }
179 }
180
181 return 0;
182}
183
184
185static char *buffer;
186static size_t buf_offset; /* Offset from the start */
187static size_t buf_len; /* Length of meaningful contents */
188static size_t buf_size; /* Allocated memory */
189static off_t buf_shifted; /* Number of bytes ever shifted */
190
191#define bufptr (buffer + buf_offset)
192#define bufend (buffer + buf_offset + buf_len)
193
194/*
195 * Ensure that the buffer contains at least this amoount of free space.
196 */
197static void buf_extend(size_t bySize) {
198
199 DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
200 (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
201
202 if(buf_size >= (buf_offset + buf_len + bySize)) {
203 return; /* Nothing to do */
204 } else if(bySize <= buf_offset) {
205 DEBUG("\tContents shifted by %ld", (long)buf_offset);
206
207 /* Shift the buffer contents */
208 memmove(buffer, buffer + buf_offset, buf_len);
209 buf_shifted += buf_offset;
210 buf_offset = 0;
211 } else {
212 size_t newsize = (buf_size << 2) + bySize;
213 void *p = realloc(buffer, newsize);
214 if(p) {
Lev Walkin814cca72004-12-15 23:23:53 +0000215 buffer = (char *)p;
Lev Walkin22b54552004-10-28 13:22:54 +0000216 buf_size = newsize;
217
218 DEBUG("\tBuffer reallocated to %ld", (long)newsize);
219 } else {
220 perror("realloc()");
221 exit(EX_OSERR);
222 }
223 }
224}
225
Lev Walkin00949562005-03-10 13:39:03 +0000226static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
Lev Walkin22b54552004-10-28 13:22:54 +0000227 static char *fbuf;
228 static ssize_t fbuf_size;
229 static asn_codec_ctx_t s_codec_ctx;
230 asn_codec_ctx_t *opt_codec_ctx = 0;
231 void *structure = 0;
232 size_t rd;
233 FILE *fp;
234
235 if(opt_stack) {
236 s_codec_ctx.max_stack_size = opt_stack;
237 opt_codec_ctx = &s_codec_ctx;
238 }
239
240 DEBUG("Processing file %s", fname);
241
242 fp = fopen(fname, "r");
243
244 if(!fp) {
245 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
246 return 0;
247 }
248
249 /* prepare the file buffer */
250 if(fbuf_size != suggested_bufsize) {
Lev Walkin814cca72004-12-15 23:23:53 +0000251 fbuf = (char *)realloc(fbuf, suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +0000252 if(!fbuf) {
253 perror("realloc()");
254 exit(EX_OSERR);
255 }
256 fbuf_size = suggested_bufsize;
257 }
258
259 buf_shifted = 0;
260 buf_offset = 0;
261 buf_len = 0;
262
263 while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
264 asn_dec_rval_t rval;
265 int using_local_buf;
266
267 /*
268 * Copy the data over, or use the original buffer.
269 */
270 if(buf_len) {
271 /* Append the new data into the intermediate buffer */
272 buf_extend(rd);
273 memcpy(bufend, fbuf, rd);
274 buf_len += rd;
275
Lev Walkin00949562005-03-10 13:39:03 +0000276 rval = ber_decode(opt_codec_ctx, pduType,
Lev Walkin22b54552004-10-28 13:22:54 +0000277 (void **)&structure, bufptr, buf_len);
278 DEBUG("ber_decode(%ld) consumed %ld, code %d",
279 (long)buf_len, (long)rval.consumed, rval.code);
280
281 /*
282 * Adjust position inside the source buffer.
283 */
284 assert(rval.consumed <= buf_len);
285 buf_offset += rval.consumed;
286 buf_len -= rval.consumed;
287 } else {
288 using_local_buf = 1;
289
Lev Walkin00949562005-03-10 13:39:03 +0000290 /* Feed the chunk of data into a decoder routine */
291 rval = ber_decode(opt_codec_ctx, pduType,
Lev Walkin22b54552004-10-28 13:22:54 +0000292 (void **)&structure, fbuf, rd);
293 DEBUG("ber_decode(%ld) consumed %ld, code %d",
294 (long)rd, (long)rval.consumed, rval.code);
295
296 /*
297 * Switch the remainder into the intermediate buffer.
298 */
299 if(rval.code != RC_FAIL && rval.consumed < rd) {
300 buf_extend(rd - rval.consumed);
301 memcpy(bufend,
302 fbuf + rval.consumed,
303 rd - rval.consumed);
304 buf_len = rd - rval.consumed;
305 }
306 }
307
308 switch(rval.code) {
309 case RC_OK:
310 DEBUG("RC_OK, finishing up");
311 fclose(fp);
312 return structure;
313 case RC_WMORE:
314 DEBUG("RC_WMORE, continuing...");
315 continue;
316 case RC_FAIL:
317 break;
318 }
319 break;
320 }
321
322 fclose(fp);
323
324 /* Clean up partially decoded structure */
Lev Walkin00949562005-03-10 13:39:03 +0000325 pduType->free_struct(pduType, structure, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000326
327 fprintf(stderr, "%s: "
Lev Walkin00949562005-03-10 13:39:03 +0000328 "Decode failed past %lld byte\n",
Lev Walkin22b54552004-10-28 13:22:54 +0000329 fname, (long long)(buf_shifted + buf_offset));
330
331 return 0;
332}
333