blob: f120853ce48c8c82aef99ea4f45006cf6fb7d14a [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include <stdlib.h>
2#include <string.h>
3#include <errno.h>
4#include <stdarg.h>
5
6#include "asn1fix.h"
7#include "asn1fix_internal.h"
8
9/* Print everything to stderr */
10static void _default_error_logger(int _severity, const char *fmt, ...);
11
12/*
13 * Internal check functions.
14 */
Lev Walkind24c62d2004-09-15 11:47:23 +000015static int asn1f_fix_module__phase_1(arg_t *arg);
16static int asn1f_fix_module__phase_2(arg_t *arg);
Lev Walkinf15320b2004-06-03 03:38:44 +000017static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */
18static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */
Lev Walkin1ef05162004-08-25 00:42:25 +000019static int asn1f_resolve_constraints(arg_t *arg); /* For subtype constraints */
20static int asn1f_check_constraints(arg_t *arg); /* For subtype constraints */
Lev Walkinf593f102005-02-22 07:59:59 +000021static int asn1f_check_duplicate(arg_t *arg);
Lev Walkinf15320b2004-06-03 03:38:44 +000022
Lev Walkinb45e0672004-08-18 05:42:05 +000023arg_t a1f_replace_me_with_proper_interface_arg;
Lev Walkinf15320b2004-06-03 03:38:44 +000024
25/*
26 * Scan every module defined here in search for inconsistences.
27 */
28int
29asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
30 error_logger_f error_logger) {
31 arg_t arg;
32 int fatals = 0;
33 int warnings = 0;
34
35 /*
36 * Check validity of arguments.
37 */
38 if(asn == NULL) {
39 errno = EINVAL;
40 return -1;
41 }
42
43 /*
44 * If errors handler is not specified, default to internal one.
45 */
46 if(error_logger == 0) {
47 error_logger = _default_error_logger;
48 }
49
50 memset(&arg, 0, sizeof(arg));
51 arg.asn = asn;
52 arg.eh = error_logger;
53
54 if(flags & A1F_DEBUG) {
55 arg.debug = arg.eh;
56 arg.debug(-1, "Called %s() with flags %d", __func__, flags);
57 flags &= ~A1F_DEBUG;
58 }
59
Lev Walkin5253da42004-08-20 13:25:56 +000060 /* Allow SIZE() constraint for INTEGER and other types */
61 if(flags & A1F_EXTENDED_SizeConstraint) {
62 arg.flags |= A1F_EXTENDED_SizeConstraint;
63 flags &= ~A1F_EXTENDED_SizeConstraint;
64 if(arg.debug) {
65 arg.debug(-1,
66 "Extended SizeConstraint support enabled");
67 }
68 }
69
Lev Walkinb45e0672004-08-18 05:42:05 +000070 a1f_replace_me_with_proper_interface_arg = arg;
71
Lev Walkinf15320b2004-06-03 03:38:44 +000072 /*
73 * Check that we haven't missed an unknown flag.
74 */
75 if(flags) {
76 errno = EINVAL;
77 return -1;
78 }
79
80 /*
81 * Process each module in the list.
Lev Walkinf593f102005-02-22 07:59:59 +000082 * PHASE I.
Lev Walkinf15320b2004-06-03 03:38:44 +000083 */
84 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
Lev Walkind24c62d2004-09-15 11:47:23 +000085 int ret = asn1f_fix_module__phase_1(&arg);
Lev Walkinf15320b2004-06-03 03:38:44 +000086 /*
87 * These lines are used for illustration purposes.
88 * RET2RVAL() is used everywhere else.
89 */
90 if(ret == -1) fatals++;
91 if(ret == 1) warnings++;
92 }
Lev Walkinf593f102005-02-22 07:59:59 +000093 /* PHASE II. */
Lev Walkind24c62d2004-09-15 11:47:23 +000094 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
95 int ret = asn1f_fix_module__phase_2(&arg);
96 if(ret == -1) fatals++;
97 if(ret == 1) warnings++;
98 }
99
100 memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
Lev Walkinf15320b2004-06-03 03:38:44 +0000101
102 /*
103 * Compute a return value.
104 */
105 return fatals?-1:warnings?1:0;
106}
107
108/*
109 * Check the internals of a single module.
110 */
111static int
Lev Walkind24c62d2004-09-15 11:47:23 +0000112asn1f_fix_module__phase_1(arg_t *arg) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000113 asn1p_expr_t *expr;
114 int rvalue = 0;
Lev Walkin1ef05162004-08-25 00:42:25 +0000115 int ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000116
Lev Walkinb45e0672004-08-18 05:42:05 +0000117 switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000118 case MSF_NOFLAGS:
119 case MSF_EXPLICIT_TAGS:
120 case MSF_IMPLICIT_TAGS:
121 case MSF_AUTOMATIC_TAGS:
122 break;
123 default:
124 FATAL("Module %s defined with ambiguous global tagging mode",
125 arg->mod->Identifier);
126 RET2RVAL(-1, rvalue);
127 }
128
Lev Walkinb45e0672004-08-18 05:42:05 +0000129 switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
130 case MSF_NOFLAGS:
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000131 /*
132 * arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
133 */
Lev Walkinb45e0672004-08-18 05:42:05 +0000134 break;
135 case MSF_unk_INSTRUCTIONS:
136 WARNING("Module %s defined with unrecognized "
137 "encoding reference", arg->mod->Identifier);
138 RET2RVAL(1, rvalue);
139 /* Fall through */
140 case MSF_TAG_INSTRUCTIONS:
141 case MSF_XER_INSTRUCTIONS:
142 break;
143 default:
144 FATAL("Module %s defined with ambiguous encoding reference",
145 arg->mod->Identifier);
146 RET2RVAL(-1, rvalue);
147 }
148
Lev Walkinf15320b2004-06-03 03:38:44 +0000149 /*
150 * Do various non-recursive transformations.
Lev Walkinf15320b2004-06-03 03:38:44 +0000151 */
152 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000153 arg->expr = expr;
154
Lev Walkinf593f102005-02-22 07:59:59 +0000155 /* Check whether this type is a duplicate */
156 ret = asn1f_check_duplicate(arg);
157 RET2RVAL(ret, rvalue);
158
Lev Walkinf15320b2004-06-03 03:38:44 +0000159 if(expr->meta_type == AMT_PARAMTYPE)
160 /* Do not process the parametrized type just yet */
161 continue;
162
163 DEBUG("=== Now processing \"%s\" at line %d ===",
164 expr->Identifier, expr->_lineno);
165 assert(expr->meta_type != AMT_INVALID);
166
167 /*
168 * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
169 */
170 ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
171 RET2RVAL(ret, rvalue);
172
173 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000174 * 2.5.4
175 */
176 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
177 RET2RVAL(ret, rvalue);
178
179 /*
Lev Walkind541c252004-09-05 10:36:22 +0000180 * Fix tagging of top-level types.
181 */
182 ret = asn1f_fix_constr_tag(arg, 1);
183 RET2RVAL(ret, rvalue);
184
185 /*
186 * 2.[234] Process SEQUENCE/SET/CHOICE types.
187 */
188 ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
189 RET2RVAL(ret, rvalue);
190
191 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000192 * 2.5.5
193 */
194 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
195 RET2RVAL(ret, rvalue);
196
197 /*
198 * Resolve references in constraints.
199 */
Lev Walkin1ef05162004-08-25 00:42:25 +0000200 ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 RET2RVAL(ret, rvalue);
202
203 /*
204 * 6. INTEGER value processed at 2.5.4.
205 */
206
207 /*
208 * Make sure everybody's behaving well.
209 */
210 assert(arg->expr == expr);
211 }
212
213 /*
214 * 5. Automatic tagging
215 */
216 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000217
218 arg->expr = expr;
219
220 ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
221 RET2RVAL(ret, rvalue);
222
223 assert(arg->expr == expr);
224 }
225
226 /*
227 * 8. fix BIT STRING
228 * 9. fix spaces in cstrings
229 */
230 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000231 arg->expr = expr;
232
233 ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
234 RET2RVAL(ret, rvalue);
235
236 ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
237 RET2RVAL(ret, rvalue);
238
239 assert(arg->expr == expr);
240 }
241
242 /*
243 * ... Check for tags distinctness.
244 */
245 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000246 arg->expr = expr;
247
248 ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
249 RET2RVAL(ret, rvalue);
250
251 assert(arg->expr == expr);
252 }
253
Lev Walkind24c62d2004-09-15 11:47:23 +0000254 return rvalue;
255}
256
257static int
258asn1f_fix_module__phase_2(arg_t *arg) {
259 asn1p_expr_t *expr;
260 int rvalue = 0;
261 int ret;
262
Lev Walkin1ef05162004-08-25 00:42:25 +0000263 TQ_FOR(expr, &(arg->mod->members), next) {
264 arg->expr = expr;
265
Lev Walkinf593f102005-02-22 07:59:59 +0000266 if(expr->meta_type == AMT_PARAMTYPE)
Lev Walkind541c252004-09-05 10:36:22 +0000267 /* Do not process the parametrized types here */
268 continue;
269
Lev Walkinb25fa062004-09-29 13:17:06 +0000270 /*
Lev Walkin3645c1c2004-10-31 00:11:50 +0000271 * Dereference DEFAULT values.
272 */
273 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_defaults);
274 RET2RVAL(ret, rvalue);
275
276 /*
Lev Walkinb25fa062004-09-29 13:17:06 +0000277 * Check semantic validity of constraints.
278 */
Lev Walkin1ef05162004-08-25 00:42:25 +0000279 ret = asn1f_recurse_expr(arg, asn1f_check_constraints);
280 RET2RVAL(ret, rvalue);
281
282 assert(arg->expr == expr);
283 }
284
Lev Walkinf15320b2004-06-03 03:38:44 +0000285 return rvalue;
286}
287
Lev Walkinf15320b2004-06-03 03:38:44 +0000288static int
289asn1f_fix_simple(arg_t *arg) {
290 int rvalue = 0;
291 int ret;
292
293 ret = asn1f_fix_enum(arg);
294 RET2RVAL(ret, rvalue);
295
296 ret = asn1f_fix_integer(arg);
297 RET2RVAL(ret, rvalue);
298
299 return rvalue;
300}
301
302static int
303asn1f_fix_constructed(arg_t *arg) {
304 int rvalue = 0;
305 int ret;
306
307 switch(arg->expr->expr_type) {
308 case ASN_CONSTR_SEQUENCE:
309 case ASN_CONSTR_SET:
310 case ASN_CONSTR_CHOICE:
311 break;
312 default:
313 return 0;
314 }
315
316 /* Check identifier distinctness */
317 ret = asn1f_check_unique_expr(arg, NULL);
318 RET2RVAL(ret, rvalue);
319
320 /* Fix extensibility */
321 ret = asn1f_fix_constr_ext(arg);
322 RET2RVAL(ret, rvalue);
323
324 /* Fix tagging */
Lev Walkind541c252004-09-05 10:36:22 +0000325 ret = asn1f_fix_constr_tag(arg, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000326 RET2RVAL(ret, rvalue);
327
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000328 /* Import COMPONENTS OF stuff */
329 ret = asn1f_pull_components_of(arg);
330 RET2RVAL(ret, rvalue);
331
Lev Walkinf15320b2004-06-03 03:38:44 +0000332 return rvalue;
333}
334
335static int
Lev Walkin1ef05162004-08-25 00:42:25 +0000336asn1f_resolve_constraints(arg_t *arg) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000337 asn1p_expr_t *top_parent;
Lev Walkin5253da42004-08-20 13:25:56 +0000338 asn1p_expr_type_e etype;
Lev Walkinf15320b2004-06-03 03:38:44 +0000339 int rvalue = 0;
340 int ret;
341
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000342 top_parent = asn1f_find_terminal_type(arg, arg->expr);
Lev Walkin5253da42004-08-20 13:25:56 +0000343 if(top_parent)
344 etype = top_parent->expr_type;
345 else etype = A1TC_INVALID;
346
Lev Walkind541c252004-09-05 10:36:22 +0000347 DEBUG("asn1f_resolve_constraints(%s)", arg->expr->Identifier);
348
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000349 ret = asn1constraint_resolve(arg, arg->expr->module,
350 arg->expr->constraints, etype, 0);
Lev Walkinb45e0672004-08-18 05:42:05 +0000351 RET2RVAL(ret, rvalue);
Lev Walkinf15320b2004-06-03 03:38:44 +0000352
Lev Walkin1ef05162004-08-25 00:42:25 +0000353 return rvalue;
354}
355
356static int
357asn1f_check_constraints(arg_t *arg) {
358 static enum asn1p_constraint_type_e test_types[] = {
359 ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
360 asn1p_expr_t *top_parent;
361 asn1cnst_range_t *range;
362 asn1p_expr_type_e etype;
363 unsigned int i;
364 int rvalue = 0;
365 int ret;
366
Lev Walkind541c252004-09-05 10:36:22 +0000367 DEBUG("asn1f_check_constraints(%s{%d/%d})",
368 arg->expr->Identifier,
369 arg->expr->meta_type, arg->expr->expr_type);
370
Lev Walkin1ef05162004-08-25 00:42:25 +0000371 top_parent = asn1f_find_terminal_type(arg, arg->expr);
372 if(!top_parent)
373 return 0;
374 etype = top_parent->expr_type;
375
Lev Walkinb45e0672004-08-18 05:42:05 +0000376 ret = asn1constraint_pullup(arg);
377 RET2RVAL(ret, rvalue);
378
Lev Walkin1ef05162004-08-25 00:42:25 +0000379 for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
380 range = asn1constraint_compute_PER_range(
Lev Walkinb9fa7802004-08-25 02:04:39 +0000381 etype,
Lev Walkin1ef05162004-08-25 00:42:25 +0000382 arg->expr->combined_constraints,
Lev Walkinb9fa7802004-08-25 02:04:39 +0000383 test_types[i], 0, 0, 0);
Lev Walkind541c252004-09-05 10:36:22 +0000384 if(!range && errno == EPERM) {
385 FATAL("This error happened for %s (%d) at line %d",
386 arg->expr->Identifier,
387 arg->expr->meta_type,
388 arg->expr->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +0000389 return -1;
Lev Walkind541c252004-09-05 10:36:22 +0000390 }
Lev Walkin1ef05162004-08-25 00:42:25 +0000391 asn1constraint_range_free(range);
Lev Walkinb45e0672004-08-18 05:42:05 +0000392 }
Lev Walkin1ef05162004-08-25 00:42:25 +0000393
Lev Walkinf15320b2004-06-03 03:38:44 +0000394 return rvalue;
395}
396
Lev Walkinf593f102005-02-22 07:59:59 +0000397static int
398asn1f_check_duplicate(arg_t *arg) {
399 arg_t tmparg = *arg;
400
401 /*
402 * This is a linear scan in search of a similar type.
403 * The linear scan is just fine for the task, no need to over-optimize.
404 */
405 TQ_FOR(tmparg.mod, &arg->asn->modules, mod_next) {
406 TQ_FOR(tmparg.expr, &(tmparg.mod->members), next) {
407 assert(tmparg.expr->Identifier);
408 assert(arg->expr->Identifier);
409 if(tmparg.expr == arg->expr) break;
410
411 if(strcmp(tmparg.expr->Identifier,
412 arg->expr->Identifier) == 0) {
413 int diff_files = strcmp(arg->mod->source_file_name, tmparg.mod->source_file_name) ? 1 : 0;
414 FATAL("ASN.1 expression \"%s\" at line %d of module %s\n"
415 "clashes with expression \"%s\" at line %d of module %s"
416 "%s%s%s.\n"
417 "Please rename either instance to resolve the conflict",
418 arg->expr->Identifier,
419 arg->expr->_lineno,
420 arg->mod->Identifier,
421 tmparg.expr->Identifier,
422 tmparg.expr->_lineno,
423 tmparg.mod->Identifier,
424 diff_files ? " (" : "",
425 diff_files ? tmparg.mod->source_file_name : "",
426 diff_files ? ")" : ""
427 );
428 return -1;
429 }
430 }
431 if(tmparg.mod == arg->mod) break;
432 }
433
434 return 0;
435}
436
Lev Walkinf15320b2004-06-03 03:38:44 +0000437/*
438 * Print everything to stderr
439 */
440static void
441_default_error_logger(int _severity, const char *fmt, ...) {
442 va_list ap;
443 char *pfx = "";
444
445 switch(_severity) {
446 case -1: pfx = "DEBUG: "; break;
447 case 0: pfx = "WARNING: "; break;
448 case 1: pfx = "FATAL: "; break;
449 }
450
451 fprintf(stderr, "%s", pfx);
452 va_start(ap, fmt);
453 vfprintf(stderr, fmt, ap);
454 va_end(ap);
455 fprintf(stderr, "\n");
456}