blob: 0febbf46a328e1ce4a71f7a3d1f9a86c7230e9ac [file] [log] [blame]
vlm0e329f22004-10-28 13:22:54 +00001/*
vlmcb14b502005-08-16 03:19:59 +00002 * Generic BER decoder template for any defined ASN.1 type.
3 * 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 */
24
25/*
vlme3470e72005-03-10 13:39:03 +000026 * Open file and parse its contens.
vlm0e329f22004-10-28 13:22:54 +000027 */
vlme3470e72005-03-10 13:39:03 +000028static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
29 const char *fname, ssize_t suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +000030
31 int opt_debug; /* -d */
32static int opt_check; /* -c */
vlm0e329f22004-10-28 13:22:54 +000033static int opt_stack; /* -s */
vlmceb458f2005-04-28 02:59:51 +000034static enum output_method {
35 OUT_NONE, /* No pretty-printing */
36 OUT_PRINT, /* -p flag */
vlme66fd8a2005-07-21 09:32:49 +000037 OUT_XML /* -x flag */
vlmceb458f2005-04-28 02:59:51 +000038} opt_ometh; /* -p or -x */
vlm0e329f22004-10-28 13:22:54 +000039
40#define DEBUG(fmt, args...) do { \
41 if(!opt_debug) break; \
42 fprintf(stderr, fmt, ##args); \
43 fprintf(stderr, "\n"); \
44} while(0)
45
46int
47main(int ac, char **av) {
48 ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
vlme3470e72005-03-10 13:39:03 +000049 asn_TYPE_descriptor_t *pduType = &asn_DEF;
vlm0e329f22004-10-28 13:22:54 +000050 int number_of_iterations = 1;
51 int num;
52 int ch;
53
54 /*
55 * Pocess the command-line argments.
56 */
57 while((ch = getopt(ac, av, "b:cdn:hps:x")) != -1)
58 switch(ch) {
59 case 'b':
60 suggested_bufsize = atoi(optarg);
61 if(suggested_bufsize < 1
62 || suggested_bufsize > 16 * 1024 * 1024) {
63 fprintf(stderr,
64 "-b %s: Improper buffer size (1..16M)\n",
65 optarg);
66 exit(EX_UNAVAILABLE);
67 }
68 break;
69 case 'c':
70 opt_check = 1;
71 break;
72 case 'd':
73 opt_debug++; /* Double -dd means ASN.1 debug */
74 break;
75 case 'n':
76 number_of_iterations = atoi(optarg);
77 if(number_of_iterations < 1) {
78 fprintf(stderr,
79 "-n %s: Improper iterations count\n", optarg);
80 exit(EX_UNAVAILABLE);
81 }
82 break;
83 case 'p':
vlmceb458f2005-04-28 02:59:51 +000084 opt_ometh = OUT_PRINT;
vlm0e329f22004-10-28 13:22:54 +000085 break;
86 case 's':
87 opt_stack = atoi(optarg);
88 if(opt_stack <= 0) {
89 fprintf(stderr,
90 "-s %s: Value greater than 0 expected\n",
91 optarg);
92 exit(EX_UNAVAILABLE);
93 }
94 break;
95 case 'x':
vlmceb458f2005-04-28 02:59:51 +000096 opt_ometh = OUT_XML;
vlm0e329f22004-10-28 13:22:54 +000097 break;
98 case 'h':
99 default:
100 fprintf(stderr,
101 "Usage: %s [options] <data.ber> ...\n"
102 "Where options are:\n"
103 " -b <size> Set the i/o buffer size (default is %ld)\n"
104 " -c Check ASN.1 constraints after decoding\n"
105 " -d Enable debugging (-dd is even better)\n"
106 " -n <num> Process files <num> times\n"
107 " -s <size> Set the stack usage limit\n"
108 " -p Print out the decoded contents\n"
vlme0fb9ce2005-04-08 19:28:18 +0000109 " -x Print out as XML"
110#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
111 " (default)"
112#endif
113 "\n"
vlm0e329f22004-10-28 13:22:54 +0000114 , av[0], (long)suggested_bufsize);
115 exit(EX_USAGE);
116 }
117
118 ac -= optind;
119 av += optind;
120
121 if(ac < 1) {
122 fprintf(stderr, "Error: missing filename\n");
123 exit(EX_USAGE);
124 }
125
vlme0fb9ce2005-04-08 19:28:18 +0000126#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
vlmceb458f2005-04-28 02:59:51 +0000127 if(opt_ometh == OUT_NONE) opt_ometh = OUT_XML;
vlme0fb9ce2005-04-08 19:28:18 +0000128#endif
129
vlm0e329f22004-10-28 13:22:54 +0000130 setvbuf(stdout, 0, _IOLBF, 0);
131
132 for(num = 0; num < number_of_iterations; num++) {
133 int ac_i;
134 /*
135 * Process all files in turn.
136 */
137 for(ac_i = 0; ac_i < ac; ac_i++) {
138 char *fname = av[ac_i];
139 void *structure;
140
141 /*
142 * Decode the encoded structure from file.
143 */
vlme3470e72005-03-10 13:39:03 +0000144 structure = data_decode_from_file(pduType,
145 fname, suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000146 if(!structure) {
147 /* Error message is already printed */
148 exit(EX_DATAERR);
149 }
150
vlmceb458f2005-04-28 02:59:51 +0000151 switch(opt_ometh) {
152 case OUT_NONE:
153 fprintf(stderr, "%s: decoded successfully\n", fname);
154 break;
155 case OUT_PRINT: /* -p */
156 asn_fprint(stdout, pduType, structure);
157 break;
158 case OUT_XML: /* -x */
159 if(xer_fprint(stdout, pduType, structure)) {
160 fprintf(stderr, "%s: Cannot convert into XML\n",
161 fname);
162 exit(EX_UNAVAILABLE);
163 }
164 break;
vlm0e329f22004-10-28 13:22:54 +0000165 }
166
167 /* Check ASN.1 constraints */
168 if(opt_check) {
169 char errbuf[128];
170 size_t errlen = sizeof(errbuf);
vlme3470e72005-03-10 13:39:03 +0000171 if(asn_check_constraints(pduType, structure,
vlm0e329f22004-10-28 13:22:54 +0000172 errbuf, &errlen)) {
173 fprintf(stderr, "%s: ASN.1 constraint "
174 "check failed: %s\n", fname, errbuf);
175 exit(EX_DATAERR);
176 }
177 }
178
vlme3470e72005-03-10 13:39:03 +0000179 pduType->free_struct(pduType, structure, 0);
vlm0e329f22004-10-28 13:22:54 +0000180 }
181 }
182
183 return 0;
184}
185
186
187static char *buffer;
188static size_t buf_offset; /* Offset from the start */
189static size_t buf_len; /* Length of meaningful contents */
190static size_t buf_size; /* Allocated memory */
191static off_t buf_shifted; /* Number of bytes ever shifted */
192
193#define bufptr (buffer + buf_offset)
194#define bufend (buffer + buf_offset + buf_len)
195
196/*
197 * Ensure that the buffer contains at least this amoount of free space.
198 */
199static void buf_extend(size_t bySize) {
200
201 DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
202 (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
203
204 if(buf_size >= (buf_offset + buf_len + bySize)) {
205 return; /* Nothing to do */
206 } else if(bySize <= buf_offset) {
207 DEBUG("\tContents shifted by %ld", (long)buf_offset);
208
209 /* Shift the buffer contents */
210 memmove(buffer, buffer + buf_offset, buf_len);
211 buf_shifted += buf_offset;
212 buf_offset = 0;
213 } else {
214 size_t newsize = (buf_size << 2) + bySize;
215 void *p = realloc(buffer, newsize);
216 if(p) {
vlmd3c80792004-12-15 23:23:53 +0000217 buffer = (char *)p;
vlm0e329f22004-10-28 13:22:54 +0000218 buf_size = newsize;
219
220 DEBUG("\tBuffer reallocated to %ld", (long)newsize);
221 } else {
222 perror("realloc()");
223 exit(EX_OSERR);
224 }
225 }
226}
227
vlme3470e72005-03-10 13:39:03 +0000228static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
vlm0e329f22004-10-28 13:22:54 +0000229 static char *fbuf;
230 static ssize_t fbuf_size;
231 static asn_codec_ctx_t s_codec_ctx;
232 asn_codec_ctx_t *opt_codec_ctx = 0;
233 void *structure = 0;
234 size_t rd;
235 FILE *fp;
236
237 if(opt_stack) {
238 s_codec_ctx.max_stack_size = opt_stack;
239 opt_codec_ctx = &s_codec_ctx;
240 }
241
242 DEBUG("Processing file %s", fname);
243
244 fp = fopen(fname, "r");
245
246 if(!fp) {
247 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
248 return 0;
249 }
250
251 /* prepare the file buffer */
252 if(fbuf_size != suggested_bufsize) {
vlmd3c80792004-12-15 23:23:53 +0000253 fbuf = (char *)realloc(fbuf, suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000254 if(!fbuf) {
255 perror("realloc()");
256 exit(EX_OSERR);
257 }
258 fbuf_size = suggested_bufsize;
259 }
260
261 buf_shifted = 0;
262 buf_offset = 0;
263 buf_len = 0;
264
265 while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
266 asn_dec_rval_t rval;
267 int using_local_buf;
268
269 /*
270 * Copy the data over, or use the original buffer.
271 */
272 if(buf_len) {
273 /* Append the new data into the intermediate buffer */
274 buf_extend(rd);
275 memcpy(bufend, fbuf, rd);
276 buf_len += rd;
277
vlme3470e72005-03-10 13:39:03 +0000278 rval = ber_decode(opt_codec_ctx, pduType,
vlm0e329f22004-10-28 13:22:54 +0000279 (void **)&structure, bufptr, buf_len);
280 DEBUG("ber_decode(%ld) consumed %ld, code %d",
281 (long)buf_len, (long)rval.consumed, rval.code);
282
283 /*
284 * Adjust position inside the source buffer.
285 */
286 assert(rval.consumed <= buf_len);
287 buf_offset += rval.consumed;
288 buf_len -= rval.consumed;
289 } else {
290 using_local_buf = 1;
291
vlme3470e72005-03-10 13:39:03 +0000292 /* Feed the chunk of data into a decoder routine */
293 rval = ber_decode(opt_codec_ctx, pduType,
vlm0e329f22004-10-28 13:22:54 +0000294 (void **)&structure, fbuf, rd);
295 DEBUG("ber_decode(%ld) consumed %ld, code %d",
296 (long)rd, (long)rval.consumed, rval.code);
297
298 /*
299 * Switch the remainder into the intermediate buffer.
300 */
301 if(rval.code != RC_FAIL && rval.consumed < rd) {
302 buf_extend(rd - rval.consumed);
303 memcpy(bufend,
304 fbuf + rval.consumed,
305 rd - rval.consumed);
306 buf_len = rd - rval.consumed;
307 }
308 }
309
310 switch(rval.code) {
311 case RC_OK:
312 DEBUG("RC_OK, finishing up");
313 fclose(fp);
314 return structure;
315 case RC_WMORE:
316 DEBUG("RC_WMORE, continuing...");
317 continue;
318 case RC_FAIL:
319 break;
320 }
321 break;
322 }
323
324 fclose(fp);
325
326 /* Clean up partially decoded structure */
vlme3470e72005-03-10 13:39:03 +0000327 pduType->free_struct(pduType, structure, 0);
vlm0e329f22004-10-28 13:22:54 +0000328
329 fprintf(stderr, "%s: "
vlme3470e72005-03-10 13:39:03 +0000330 "Decode failed past %lld byte\n",
vlm0e329f22004-10-28 13:22:54 +0000331 fname, (long long)(buf_shifted + buf_offset));
332
333 return 0;
334}
335