blob: 76559d10da30f44454f1c1084e3789fe39c54a0b [file] [log] [blame]
vlm0e329f22004-10-28 13:22:54 +00001/*
2 * This is a generic BER decoder template for any ASN.1 type.
3 *
vlme641d392005-03-10 11:59:44 +00004 * To compile with your own ASN.1 type, please redefine the asn_DEF as shown:
vlm0e329f22004-10-28 13:22:54 +00005 *
vlme641d392005-03-10 11:59:44 +00006 * cc -Dasn_DEF=asn_DEF_MyCustomType -o myDecoder.o -c asn-decoder-template.c
vlm0e329f22004-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) */
vlm0e329f22004-10-28 13:22:54 +000015#include <sysexits.h> /* for EX_* exit codes */
vlm5ec2fe12005-03-29 17:21:14 +000016#include <assert.h> /* for assert(3) */
17#include <errno.h> /* for errno */
vlm0e329f22004-10-28 13:22:54 +000018
vlme3470e72005-03-10 13:39:03 +000019#include <asn_application.h>
vlm0e329f22004-10-28 13:22:54 +000020
21extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */
22
23/*
vlme3470e72005-03-10 13:39:03 +000024 * Open file and parse its contens.
vlm0e329f22004-10-28 13:22:54 +000025 */
vlme3470e72005-03-10 13:39:03 +000026static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
27 const char *fname, ssize_t suggested_bufsize);
vlm0e329f22004-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 */
33static int opt_toxml; /* -x */
34
35#define DEBUG(fmt, args...) do { \
36 if(!opt_debug) break; \
37 fprintf(stderr, fmt, ##args); \
38 fprintf(stderr, "\n"); \
39} while(0)
40
41int
42main(int ac, char **av) {
43 ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
vlme3470e72005-03-10 13:39:03 +000044 asn_TYPE_descriptor_t *pduType = &asn_DEF;
vlm0e329f22004-10-28 13:22:54 +000045 int number_of_iterations = 1;
46 int num;
47 int ch;
48
49 /*
50 * Pocess the command-line argments.
51 */
52 while((ch = getopt(ac, av, "b:cdn:hps:x")) != -1)
53 switch(ch) {
54 case 'b':
55 suggested_bufsize = atoi(optarg);
56 if(suggested_bufsize < 1
57 || suggested_bufsize > 16 * 1024 * 1024) {
58 fprintf(stderr,
59 "-b %s: Improper buffer size (1..16M)\n",
60 optarg);
61 exit(EX_UNAVAILABLE);
62 }
63 break;
64 case 'c':
65 opt_check = 1;
66 break;
67 case 'd':
68 opt_debug++; /* Double -dd means ASN.1 debug */
69 break;
70 case 'n':
71 number_of_iterations = atoi(optarg);
72 if(number_of_iterations < 1) {
73 fprintf(stderr,
74 "-n %s: Improper iterations count\n", optarg);
75 exit(EX_UNAVAILABLE);
76 }
77 break;
78 case 'p':
vlme0fb9ce2005-04-08 19:28:18 +000079 opt_toxml = 0; /* Override '-x' */
vlm0e329f22004-10-28 13:22:54 +000080 opt_print++;
81 break;
82 case 's':
83 opt_stack = atoi(optarg);
84 if(opt_stack <= 0) {
85 fprintf(stderr,
86 "-s %s: Value greater than 0 expected\n",
87 optarg);
88 exit(EX_UNAVAILABLE);
89 }
90 break;
91 case 'x':
vlme0fb9ce2005-04-08 19:28:18 +000092 opt_print = 0; /* Override '-p' */
vlm0e329f22004-10-28 13:22:54 +000093 opt_toxml++;
94 break;
95 case 'h':
96 default:
97 fprintf(stderr,
98 "Usage: %s [options] <data.ber> ...\n"
99 "Where options are:\n"
100 " -b <size> Set the i/o buffer size (default is %ld)\n"
101 " -c Check ASN.1 constraints after decoding\n"
102 " -d Enable debugging (-dd is even better)\n"
103 " -n <num> Process files <num> times\n"
104 " -s <size> Set the stack usage limit\n"
105 " -p Print out the decoded contents\n"
vlme0fb9ce2005-04-08 19:28:18 +0000106 " -x Print out as XML"
107#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
108 " (default)"
109#endif
110 "\n"
vlm0e329f22004-10-28 13:22:54 +0000111 , av[0], (long)suggested_bufsize);
112 exit(EX_USAGE);
113 }
114
115 ac -= optind;
116 av += optind;
117
118 if(ac < 1) {
119 fprintf(stderr, "Error: missing filename\n");
120 exit(EX_USAGE);
121 }
122
vlme0fb9ce2005-04-08 19:28:18 +0000123#ifdef ASN_DECODER_DEFAULT_OUTPUT_XML
124 if(!opt_print) opt_toxml++;
125#endif
126
vlm0e329f22004-10-28 13:22:54 +0000127 setvbuf(stdout, 0, _IOLBF, 0);
128
129 for(num = 0; num < number_of_iterations; num++) {
130 int ac_i;
131 /*
132 * Process all files in turn.
133 */
134 for(ac_i = 0; ac_i < ac; ac_i++) {
135 char *fname = av[ac_i];
136 void *structure;
137
138 /*
139 * Decode the encoded structure from file.
140 */
vlme3470e72005-03-10 13:39:03 +0000141 structure = data_decode_from_file(pduType,
142 fname, suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000143 if(!structure) {
144 /* Error message is already printed */
145 exit(EX_DATAERR);
146 }
147
148 fprintf(stderr, "%s: decoded successfully\n", fname);
149
vlme3470e72005-03-10 13:39:03 +0000150 if(opt_print) asn_fprint(stdout, pduType, structure);
vlm0e329f22004-10-28 13:22:54 +0000151
152 if(opt_toxml
vlme3470e72005-03-10 13:39:03 +0000153 && xer_fprint(stdout, pduType, structure)) {
vlm0e329f22004-10-28 13:22:54 +0000154 fprintf(stderr, "%s: Cannot convert into XML\n", fname);
155 exit(EX_UNAVAILABLE);
156 }
157
158 /* Check ASN.1 constraints */
159 if(opt_check) {
160 char errbuf[128];
161 size_t errlen = sizeof(errbuf);
vlme3470e72005-03-10 13:39:03 +0000162 if(asn_check_constraints(pduType, structure,
vlm0e329f22004-10-28 13:22:54 +0000163 errbuf, &errlen)) {
164 fprintf(stderr, "%s: ASN.1 constraint "
165 "check failed: %s\n", fname, errbuf);
166 exit(EX_DATAERR);
167 }
168 }
169
vlme3470e72005-03-10 13:39:03 +0000170 pduType->free_struct(pduType, structure, 0);
vlm0e329f22004-10-28 13:22:54 +0000171 }
172 }
173
174 return 0;
175}
176
177
178static char *buffer;
179static size_t buf_offset; /* Offset from the start */
180static size_t buf_len; /* Length of meaningful contents */
181static size_t buf_size; /* Allocated memory */
182static off_t buf_shifted; /* Number of bytes ever shifted */
183
184#define bufptr (buffer + buf_offset)
185#define bufend (buffer + buf_offset + buf_len)
186
187/*
188 * Ensure that the buffer contains at least this amoount of free space.
189 */
190static void buf_extend(size_t bySize) {
191
192 DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
193 (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
194
195 if(buf_size >= (buf_offset + buf_len + bySize)) {
196 return; /* Nothing to do */
197 } else if(bySize <= buf_offset) {
198 DEBUG("\tContents shifted by %ld", (long)buf_offset);
199
200 /* Shift the buffer contents */
201 memmove(buffer, buffer + buf_offset, buf_len);
202 buf_shifted += buf_offset;
203 buf_offset = 0;
204 } else {
205 size_t newsize = (buf_size << 2) + bySize;
206 void *p = realloc(buffer, newsize);
207 if(p) {
vlmd3c80792004-12-15 23:23:53 +0000208 buffer = (char *)p;
vlm0e329f22004-10-28 13:22:54 +0000209 buf_size = newsize;
210
211 DEBUG("\tBuffer reallocated to %ld", (long)newsize);
212 } else {
213 perror("realloc()");
214 exit(EX_OSERR);
215 }
216 }
217}
218
vlme3470e72005-03-10 13:39:03 +0000219static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
vlm0e329f22004-10-28 13:22:54 +0000220 static char *fbuf;
221 static ssize_t fbuf_size;
222 static asn_codec_ctx_t s_codec_ctx;
223 asn_codec_ctx_t *opt_codec_ctx = 0;
224 void *structure = 0;
225 size_t rd;
226 FILE *fp;
227
228 if(opt_stack) {
229 s_codec_ctx.max_stack_size = opt_stack;
230 opt_codec_ctx = &s_codec_ctx;
231 }
232
233 DEBUG("Processing file %s", fname);
234
235 fp = fopen(fname, "r");
236
237 if(!fp) {
238 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
239 return 0;
240 }
241
242 /* prepare the file buffer */
243 if(fbuf_size != suggested_bufsize) {
vlmd3c80792004-12-15 23:23:53 +0000244 fbuf = (char *)realloc(fbuf, suggested_bufsize);
vlm0e329f22004-10-28 13:22:54 +0000245 if(!fbuf) {
246 perror("realloc()");
247 exit(EX_OSERR);
248 }
249 fbuf_size = suggested_bufsize;
250 }
251
252 buf_shifted = 0;
253 buf_offset = 0;
254 buf_len = 0;
255
256 while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
257 asn_dec_rval_t rval;
258 int using_local_buf;
259
260 /*
261 * Copy the data over, or use the original buffer.
262 */
263 if(buf_len) {
264 /* Append the new data into the intermediate buffer */
265 buf_extend(rd);
266 memcpy(bufend, fbuf, rd);
267 buf_len += rd;
268
vlme3470e72005-03-10 13:39:03 +0000269 rval = ber_decode(opt_codec_ctx, pduType,
vlm0e329f22004-10-28 13:22:54 +0000270 (void **)&structure, bufptr, buf_len);
271 DEBUG("ber_decode(%ld) consumed %ld, code %d",
272 (long)buf_len, (long)rval.consumed, rval.code);
273
274 /*
275 * Adjust position inside the source buffer.
276 */
277 assert(rval.consumed <= buf_len);
278 buf_offset += rval.consumed;
279 buf_len -= rval.consumed;
280 } else {
281 using_local_buf = 1;
282
vlme3470e72005-03-10 13:39:03 +0000283 /* Feed the chunk of data into a decoder routine */
284 rval = ber_decode(opt_codec_ctx, pduType,
vlm0e329f22004-10-28 13:22:54 +0000285 (void **)&structure, fbuf, rd);
286 DEBUG("ber_decode(%ld) consumed %ld, code %d",
287 (long)rd, (long)rval.consumed, rval.code);
288
289 /*
290 * Switch the remainder into the intermediate buffer.
291 */
292 if(rval.code != RC_FAIL && rval.consumed < rd) {
293 buf_extend(rd - rval.consumed);
294 memcpy(bufend,
295 fbuf + rval.consumed,
296 rd - rval.consumed);
297 buf_len = rd - rval.consumed;
298 }
299 }
300
301 switch(rval.code) {
302 case RC_OK:
303 DEBUG("RC_OK, finishing up");
304 fclose(fp);
305 return structure;
306 case RC_WMORE:
307 DEBUG("RC_WMORE, continuing...");
308 continue;
309 case RC_FAIL:
310 break;
311 }
312 break;
313 }
314
315 fclose(fp);
316
317 /* Clean up partially decoded structure */
vlme3470e72005-03-10 13:39:03 +0000318 pduType->free_struct(pduType, structure, 0);
vlm0e329f22004-10-28 13:22:54 +0000319
320 fprintf(stderr, "%s: "
vlme3470e72005-03-10 13:39:03 +0000321 "Decode failed past %lld byte\n",
vlm0e329f22004-10-28 13:22:54 +0000322 fname, (long long)(buf_shifted + buf_offset));
323
324 return 0;
325}
326