1 #include "asn1fix_internal.h"
4 /* Print everything to stderr */
5 static void _default_error_logger(int _severity, const char *fmt, ...);
8 * Internal check functions.
10 static int asn1f_fix_module__phase_1(arg_t *arg);
11 static int asn1f_fix_module__phase_2(arg_t *arg);
12 static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */
13 static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */
14 static int asn1f_resolve_constraints(arg_t *arg); /* For subtype constraints */
15 static int asn1f_check_constraints(arg_t *arg); /* For subtype constraints */
16 static int asn1f_check_duplicate(arg_t *arg);
17 static int asn1f_apply_unique_index(arg_t *arg);
18 static int phase_1_1(arg_t *arg, int prm2);
20 arg_t a1f_replace_me_with_proper_interface_arg;
23 * Scan every module defined here in search for inconsistences.
26 asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
27 error_logger_f error_logger) {
34 * Check validity of arguments.
42 * If errors handler is not specified, default to internal one.
44 if(error_logger == 0) {
45 error_logger = _default_error_logger;
48 memset(&arg, 0, sizeof(arg));
50 arg.eh = error_logger;
52 if(flags & A1F_DEBUG) {
54 arg.debug(-1, "Called %s() with flags %d", __func__, flags);
58 /* Allow SIZE() constraint for INTEGER and other types */
59 if(flags & A1F_EXTENDED_SizeConstraint) {
60 arg.flags |= A1F_EXTENDED_SizeConstraint;
61 flags &= ~A1F_EXTENDED_SizeConstraint;
64 "Extended SizeConstraint support enabled");
68 a1f_replace_me_with_proper_interface_arg = arg;
71 * Check that we haven't missed an unknown flag.
79 * Process each module in the list.
82 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
83 arg.ns = asn1_namespace_new_from_module(arg.mod, 0);
84 ret = asn1f_fix_module__phase_1(&arg);
86 * These lines are used for illustration purposes.
87 * RET2RVAL() is used everywhere else.
89 if(ret == -1) fatals++;
90 if(ret == 1) warnings++;
91 asn1_namespace_free(arg.ns);
95 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
96 arg.ns = asn1_namespace_new_from_module(arg.mod, 0);
97 ret = asn1f_fix_module__phase_2(&arg);
98 if(ret == -1) fatals++;
99 if(ret == 1) warnings++;
100 asn1_namespace_free(arg.ns);
104 memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
107 * Compute a return value.
109 return fatals?-1:warnings?1:0;
113 * Check the internals of a single module.
116 asn1f_fix_module__phase_1(arg_t *arg) {
120 asn1p_module_t *omod;
123 * Check that we don't have a similarly named module.
125 TQ_FOR(omod, &arg->asn->modules, mod_next) {
127 if(omod == arg->mod) break;
128 sameNames = strcmp(omod->ModuleName, arg->mod->ModuleName)?0:1;
129 if(omod->module_oid && arg->mod->module_oid) {
130 /* Compare only the OID. */
131 if(asn1p_oid_compare(omod->module_oid,
132 arg->mod->module_oid) == 0) {
133 FATAL("ASN.1 module %s in %s "
134 "has the same OBJECT IDENTIFIER"
137 omod->source_file_name,
140 RET2RVAL(-1, rvalue);
141 } else if(sameNames) {
142 WARNING("ASN.1 module %s is defined more than once, with different OIDs", omod->ModuleName);
145 } else if(sameNames) {
146 FATAL("ASN.1 module %s is defined more than once",
148 RET2RVAL(-1, rvalue);
152 switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
154 case MSF_EXPLICIT_TAGS:
155 case MSF_IMPLICIT_TAGS:
156 case MSF_AUTOMATIC_TAGS:
159 FATAL("Module %s defined with ambiguous global tagging mode",
160 arg->mod->ModuleName);
161 RET2RVAL(-1, rvalue);
164 switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
167 * arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
170 case MSF_unk_INSTRUCTIONS:
171 WARNING("Module %s defined with unrecognized "
172 "encoding reference", arg->mod->ModuleName);
175 case MSF_TAG_INSTRUCTIONS:
176 case MSF_XER_INSTRUCTIONS:
179 FATAL("Module %s defined with ambiguous encoding reference",
180 arg->mod->ModuleName);
181 RET2RVAL(-1, rvalue);
185 * Do various non-recursive transformations.
187 TQ_FOR(expr, &(arg->mod->members), next) {
189 ret = phase_1_1(arg, 0);
190 RET2RVAL(ret, rvalue);
192 * Make sure everybody's behaving well.
194 assert(arg->expr == expr);
196 TQ_FOR(expr, &(arg->mod->members), next) {
198 ret = phase_1_1(arg, 1);
199 RET2RVAL(ret, rvalue);
200 assert(arg->expr == expr);
206 * 5. Automatic tagging
208 TQ_FOR(expr, &(arg->mod->members), next) {
212 ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
213 RET2RVAL(ret, rvalue);
215 assert(arg->expr == expr);
220 * 9. fix spaces in cstrings
222 TQ_FOR(expr, &(arg->mod->members), next) {
225 ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
226 RET2RVAL(ret, rvalue);
228 ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
229 RET2RVAL(ret, rvalue);
231 assert(arg->expr == expr);
235 * ... Check for tags distinctness.
237 TQ_FOR(expr, &(arg->mod->members), next) {
240 ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
241 RET2RVAL(ret, rvalue);
243 assert(arg->expr == expr);
250 asn1f_fix_module__phase_2(arg_t *arg) {
255 TQ_FOR(expr, &(arg->mod->members), next) {
260 * Dereference DEFAULT values.
262 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_defaults);
263 RET2RVAL(ret, rvalue);
266 * Resolve references in constraints (the second pass).
268 ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
269 RET2RVAL(ret, rvalue);
272 * Check semantic validity of constraints.
274 ret = asn1f_recurse_expr(arg, asn1f_check_constraints);
275 RET2RVAL(ret, rvalue);
278 * Uniquely tag each inner type.
280 asn1f_apply_unique_index(0);
281 ret = asn1f_recurse_expr(arg, asn1f_apply_unique_index);
282 RET2RVAL(ret, rvalue);
284 assert(arg->expr == expr);
291 phase_1_1(arg_t *arg, int prm2) {
292 asn1p_expr_t *expr = arg->expr;
296 if(expr->lhs_params && expr->spec_index == -1) {
299 /* Do not process the parameterized type just yet */
301 for(i = 0; i < expr->specializations.pspecs_count; i++) {
302 arg->expr = expr->specializations.pspec[i].my_clone;
303 ret = phase_1_1(arg, 0);
304 RET2RVAL(ret, rvalue);
306 arg->expr = expr; /* revert */
309 return 0; /* Already done! */
312 /* Check whether this type is a duplicate */
313 if(!expr->lhs_params) {
314 ret = asn1f_check_duplicate(arg);
315 RET2RVAL(ret, rvalue);
318 DEBUG("=== Now processing \"%s\" (%d/0x%x) at line %d ===",
319 expr->Identifier, expr->meta_type, expr->expr_type,
321 assert(expr->meta_type != AMT_INVALID);
324 * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
326 ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
327 RET2RVAL(ret, rvalue);
332 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
333 RET2RVAL(ret, rvalue);
336 * Fix tagging of top-level types.
338 ret = asn1f_fix_constr_tag(arg, 1);
339 RET2RVAL(ret, rvalue);
342 * 2.[234] Process SEQUENCE/SET/CHOICE types.
344 ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
345 RET2RVAL(ret, rvalue);
350 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
351 RET2RVAL(ret, rvalue);
354 * Resolve references in constraints.
356 ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
357 RET2RVAL(ret, rvalue);
360 * Parse class information object sets.
362 ret = asn1f_parse_class_object(arg);
363 RET2RVAL(ret, rvalue);
366 * 6. INTEGER value processed at 2.5.4.
373 asn1f_fix_simple(arg_t *arg) {
377 ret = asn1f_fix_enum(arg);
378 RET2RVAL(ret, rvalue);
380 ret = asn1f_fix_integer(arg);
381 RET2RVAL(ret, rvalue);
387 asn1f_fix_constructed(arg_t *arg) {
391 switch(arg->expr->expr_type) {
392 case ASN_CONSTR_SEQUENCE:
394 case ASN_CONSTR_CHOICE:
400 /* Check identifier distinctness */
401 ret = asn1f_check_unique_expr(arg);
402 RET2RVAL(ret, rvalue);
404 /* Fix extensibility */
405 ret = asn1f_fix_constr_ext(arg);
406 RET2RVAL(ret, rvalue);
409 ret = asn1f_fix_constr_tag(arg, 0);
410 RET2RVAL(ret, rvalue);
412 /* Import COMPONENTS OF stuff */
413 ret = asn1f_pull_components_of(arg);
414 RET2RVAL(ret, rvalue);
420 asn1f_resolve_constraints(arg_t *arg) {
421 asn1p_expr_t *top_parent;
422 asn1p_expr_type_e etype;
426 top_parent = asn1f_find_terminal_type(arg, arg->expr);
428 etype = top_parent->expr_type;
429 else etype = A1TC_INVALID;
431 DEBUG("(%s)", arg->expr->Identifier);
433 ret = asn1constraint_resolve(arg, arg->expr->constraints, etype, 0);
434 RET2RVAL(ret, rvalue);
440 asn1f_check_constraints(arg_t *arg) {
441 static enum asn1p_constraint_type_e test_types[] = {
442 ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
443 asn1p_expr_t *top_parent;
444 asn1cnst_range_t *range;
445 asn1p_expr_type_e etype;
451 arg->expr->Identifier,
452 arg->expr->meta_type, arg->expr->expr_type);
454 top_parent = asn1f_find_terminal_type(arg, arg->expr);
457 etype = top_parent->expr_type;
459 ret = asn1constraint_pullup(arg);
460 RET2RVAL(ret, rvalue);
462 for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
463 range = asn1constraint_compute_constraint_range(
464 arg->expr->Identifier,
466 arg->expr->combined_constraints,
468 CPR_noflags /* ignore -fbless-SIZE */);
469 if(!range && errno == EPERM) {
470 FATAL("This error happened for \"%s\" (meta %d) "
472 arg->expr->Identifier,
473 arg->expr->meta_type,
477 asn1constraint_range_free(range);
484 asn1f_check_duplicate(arg_t *arg) {
489 * This is a linear scan in search of a similar type.
490 * The linear scan is just fine for the task, no need to over-optimize.
492 TQ_FOR(tmparg.mod, &arg->asn->modules, mod_next) {
493 int critical = 1; /* FATAL */
495 if((arg->mod->_tags & MT_STANDARD_MODULE)
496 != (tmparg.mod->_tags & MT_STANDARD_MODULE)) {
497 /* Ignore clashes with standard module */
498 critical = 0; /* WARNING */
501 TQ_FOR(tmparg.expr, &(tmparg.mod->members), next) {
502 int diff_files; /* different files */
504 assert(tmparg.expr->Identifier);
505 assert(arg->expr->Identifier);
507 if(arg->expr->spec_index != -1)
510 if(tmparg.expr == arg->expr) break;
512 if(strcmp(tmparg.expr->Identifier,
513 arg->expr->Identifier))
516 /* resolve clash of Identifier in different modules */
517 int oid_exist = (tmparg.expr->module->module_oid && arg->expr->module->module_oid);
518 if ((!oid_exist && strcmp(tmparg.expr->module->ModuleName, arg->expr->module->ModuleName)) ||
519 (oid_exist && !asn1p_oid_compare(tmparg.expr->module->module_oid, arg->expr->module->module_oid))) {
521 tmparg.expr->_mark |= TM_NAMECLASH;
522 arg->expr->_mark |= TM_NAMECLASH;
526 diff_files = strcmp(arg->mod->source_file_name,
527 tmparg.mod->source_file_name) ? 1 : 0;
530 "ASN.1 expression \"%s\" at line %d of module %s\n"
531 "clashes with expression \"%s\" at line %d of module %s"
533 "Rename or remove either instance "
534 "to resolve the conflict",
535 arg->expr->Identifier,
537 arg->mod->ModuleName,
538 tmparg.expr->Identifier,
539 tmparg.expr->_lineno,
540 tmparg.mod->ModuleName,
541 diff_files ? " (" : "",
542 diff_files ? tmparg.mod->source_file_name : "",
543 diff_files ? ")" : "");
548 if(tmparg.mod == arg->mod) break;
555 asn1f_apply_unique_index(arg_t *arg) {
556 static int unique_index;
557 if(!arg) { unique_index = 0; return 0; }
559 arg->expr->_type_unique_index = ++unique_index;
565 * Print everything to stderr
568 _default_error_logger(int _severity, const char *fmt, ...) {
573 case -1: pfx = "DEBUG: "; break;
574 case 0: pfx = "WARNING: "; break;
575 case 1: pfx = "FATAL: "; break;
578 fprintf(stderr, "%s", pfx);
580 vfprintf(stderr, fmt, ap);
582 fprintf(stderr, "\n");