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