blob: 4ff524c87e6b3e74a4a4efc9371a0be697d282d0 [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 */
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 */
Lev Walkin00949562005-03-10 13:39:03 +000044 asn_TYPE_descriptor_t *pduType = &asn_DEF;
Lev Walkin22b54552004-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':
79 opt_print++;
80 break;
81 case 's':
82 opt_stack = atoi(optarg);
83 if(opt_stack <= 0) {
84 fprintf(stderr,
85 "-s %s: Value greater than 0 expected\n",
86 optarg);
87 exit(EX_UNAVAILABLE);
88 }
89 break;
90 case 'x':
91 opt_toxml++;
92 break;
93 case 'h':
94 default:
95 fprintf(stderr,
96 "Usage: %s [options] <data.ber> ...\n"
97 "Where options are:\n"
98 " -b <size> Set the i/o buffer size (default is %ld)\n"
99 " -c Check ASN.1 constraints after decoding\n"
100 " -d Enable debugging (-dd is even better)\n"
101 " -n <num> Process files <num> times\n"
102 " -s <size> Set the stack usage limit\n"
103 " -p Print out the decoded contents\n"
104 " -x Print out as XML\n"
105 , av[0], (long)suggested_bufsize);
106 exit(EX_USAGE);
107 }
108
109 ac -= optind;
110 av += optind;
111
112 if(ac < 1) {
113 fprintf(stderr, "Error: missing filename\n");
114 exit(EX_USAGE);
115 }
116
117 setvbuf(stdout, 0, _IOLBF, 0);
118
119 for(num = 0; num < number_of_iterations; num++) {
120 int ac_i;
121 /*
122 * Process all files in turn.
123 */
124 for(ac_i = 0; ac_i < ac; ac_i++) {
125 char *fname = av[ac_i];
126 void *structure;
127
128 /*
129 * Decode the encoded structure from file.
130 */
Lev Walkin00949562005-03-10 13:39:03 +0000131 structure = data_decode_from_file(pduType,
132 fname, suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +0000133 if(!structure) {
134 /* Error message is already printed */
135 exit(EX_DATAERR);
136 }
137
138 fprintf(stderr, "%s: decoded successfully\n", fname);
139
Lev Walkin00949562005-03-10 13:39:03 +0000140 if(opt_print) asn_fprint(stdout, pduType, structure);
Lev Walkin22b54552004-10-28 13:22:54 +0000141
142 if(opt_toxml
Lev Walkin00949562005-03-10 13:39:03 +0000143 && xer_fprint(stdout, pduType, structure)) {
Lev Walkin22b54552004-10-28 13:22:54 +0000144 fprintf(stderr, "%s: Cannot convert into XML\n", fname);
145 exit(EX_UNAVAILABLE);
146 }
147
148 /* Check ASN.1 constraints */
149 if(opt_check) {
150 char errbuf[128];
151 size_t errlen = sizeof(errbuf);
Lev Walkin00949562005-03-10 13:39:03 +0000152 if(asn_check_constraints(pduType, structure,
Lev Walkin22b54552004-10-28 13:22:54 +0000153 errbuf, &errlen)) {
154 fprintf(stderr, "%s: ASN.1 constraint "
155 "check failed: %s\n", fname, errbuf);
156 exit(EX_DATAERR);
157 }
158 }
159
Lev Walkin00949562005-03-10 13:39:03 +0000160 pduType->free_struct(pduType, structure, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000161 }
162 }
163
164 return 0;
165}
166
167
168static char *buffer;
169static size_t buf_offset; /* Offset from the start */
170static size_t buf_len; /* Length of meaningful contents */
171static size_t buf_size; /* Allocated memory */
172static off_t buf_shifted; /* Number of bytes ever shifted */
173
174#define bufptr (buffer + buf_offset)
175#define bufend (buffer + buf_offset + buf_len)
176
177/*
178 * Ensure that the buffer contains at least this amoount of free space.
179 */
180static void buf_extend(size_t bySize) {
181
182 DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
183 (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
184
185 if(buf_size >= (buf_offset + buf_len + bySize)) {
186 return; /* Nothing to do */
187 } else if(bySize <= buf_offset) {
188 DEBUG("\tContents shifted by %ld", (long)buf_offset);
189
190 /* Shift the buffer contents */
191 memmove(buffer, buffer + buf_offset, buf_len);
192 buf_shifted += buf_offset;
193 buf_offset = 0;
194 } else {
195 size_t newsize = (buf_size << 2) + bySize;
196 void *p = realloc(buffer, newsize);
197 if(p) {
Lev Walkin814cca72004-12-15 23:23:53 +0000198 buffer = (char *)p;
Lev Walkin22b54552004-10-28 13:22:54 +0000199 buf_size = newsize;
200
201 DEBUG("\tBuffer reallocated to %ld", (long)newsize);
202 } else {
203 perror("realloc()");
204 exit(EX_OSERR);
205 }
206 }
207}
208
Lev Walkin00949562005-03-10 13:39:03 +0000209static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
Lev Walkin22b54552004-10-28 13:22:54 +0000210 static char *fbuf;
211 static ssize_t fbuf_size;
212 static asn_codec_ctx_t s_codec_ctx;
213 asn_codec_ctx_t *opt_codec_ctx = 0;
214 void *structure = 0;
215 size_t rd;
216 FILE *fp;
217
218 if(opt_stack) {
219 s_codec_ctx.max_stack_size = opt_stack;
220 opt_codec_ctx = &s_codec_ctx;
221 }
222
223 DEBUG("Processing file %s", fname);
224
225 fp = fopen(fname, "r");
226
227 if(!fp) {
228 fprintf(stderr, "%s: %s\n", fname, strerror(errno));
229 return 0;
230 }
231
232 /* prepare the file buffer */
233 if(fbuf_size != suggested_bufsize) {
Lev Walkin814cca72004-12-15 23:23:53 +0000234 fbuf = (char *)realloc(fbuf, suggested_bufsize);
Lev Walkin22b54552004-10-28 13:22:54 +0000235 if(!fbuf) {
236 perror("realloc()");
237 exit(EX_OSERR);
238 }
239 fbuf_size = suggested_bufsize;
240 }
241
242 buf_shifted = 0;
243 buf_offset = 0;
244 buf_len = 0;
245
246 while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
247 asn_dec_rval_t rval;
248 int using_local_buf;
249
250 /*
251 * Copy the data over, or use the original buffer.
252 */
253 if(buf_len) {
254 /* Append the new data into the intermediate buffer */
255 buf_extend(rd);
256 memcpy(bufend, fbuf, rd);
257 buf_len += rd;
258
Lev Walkin00949562005-03-10 13:39:03 +0000259 rval = ber_decode(opt_codec_ctx, pduType,
Lev Walkin22b54552004-10-28 13:22:54 +0000260 (void **)&structure, bufptr, buf_len);
261 DEBUG("ber_decode(%ld) consumed %ld, code %d",
262 (long)buf_len, (long)rval.consumed, rval.code);
263
264 /*
265 * Adjust position inside the source buffer.
266 */
267 assert(rval.consumed <= buf_len);
268 buf_offset += rval.consumed;
269 buf_len -= rval.consumed;
270 } else {
271 using_local_buf = 1;
272
Lev Walkin00949562005-03-10 13:39:03 +0000273 /* Feed the chunk of data into a decoder routine */
274 rval = ber_decode(opt_codec_ctx, pduType,
Lev Walkin22b54552004-10-28 13:22:54 +0000275 (void **)&structure, fbuf, rd);
276 DEBUG("ber_decode(%ld) consumed %ld, code %d",
277 (long)rd, (long)rval.consumed, rval.code);
278
279 /*
280 * Switch the remainder into the intermediate buffer.
281 */
282 if(rval.code != RC_FAIL && rval.consumed < rd) {
283 buf_extend(rd - rval.consumed);
284 memcpy(bufend,
285 fbuf + rval.consumed,
286 rd - rval.consumed);
287 buf_len = rd - rval.consumed;
288 }
289 }
290
291 switch(rval.code) {
292 case RC_OK:
293 DEBUG("RC_OK, finishing up");
294 fclose(fp);
295 return structure;
296 case RC_WMORE:
297 DEBUG("RC_WMORE, continuing...");
298 continue;
299 case RC_FAIL:
300 break;
301 }
302 break;
303 }
304
305 fclose(fp);
306
307 /* Clean up partially decoded structure */
Lev Walkin00949562005-03-10 13:39:03 +0000308 pduType->free_struct(pduType, structure, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000309
310 fprintf(stderr, "%s: "
Lev Walkin00949562005-03-10 13:39:03 +0000311 "Decode failed past %lld byte\n",
Lev Walkin22b54552004-10-28 13:22:54 +0000312 fname, (long long)(buf_shifted + buf_offset));
313
314 return 0;
315}
316