#include #include #include #include #include "asn1fix.h" #include "asn1fix_internal.h" /* Print everything to stderr */ static void _default_error_logger(int _severity, const char *fmt, ...); /* * Internal check functions. */ static int asn1f_fix_module(arg_t *arg); static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */ static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */ static int asn1f_fix_constraints(arg_t *arg); /* For subtype constraints */ /* * Scan every module defined here in search for inconsistences. */ int asn1f_process(asn1p_t *asn, enum asn1f_flags flags, error_logger_f error_logger) { arg_t arg; int fatals = 0; int warnings = 0; /* * Check validity of arguments. */ if(asn == NULL) { errno = EINVAL; return -1; } /* * If errors handler is not specified, default to internal one. */ if(error_logger == 0) { error_logger = _default_error_logger; } memset(&arg, 0, sizeof(arg)); arg.asn = asn; arg.eh = error_logger; if(flags & A1F_DEBUG) { arg.debug = arg.eh; arg.debug(-1, "Called %s() with flags %d", __func__, flags); flags &= ~A1F_DEBUG; } /* * Check that we haven't missed an unknown flag. */ if(flags) { errno = EINVAL; return -1; } /* * Process each module in the list. */ TQ_FOR(arg.mod, &(asn->modules), mod_next) { int ret = asn1f_fix_module(&arg); /* * These lines are used for illustration purposes. * RET2RVAL() is used everywhere else. */ if(ret == -1) fatals++; if(ret == 1) warnings++; } /* * Compute a return value. */ return fatals?-1:warnings?1:0; } /* * Check the internals of a single module. */ static int asn1f_fix_module(arg_t *arg) { asn1p_expr_t *expr; int rvalue = 0; switch((arg->mod->module_flags & (MSF_EXPLICIT_TAGS | MSF_IMPLICIT_TAGS | MSF_AUTOMATIC_TAGS))) { case MSF_NOFLAGS: case MSF_EXPLICIT_TAGS: case MSF_IMPLICIT_TAGS: case MSF_AUTOMATIC_TAGS: break; default: FATAL("Module %s defined with ambiguous global tagging mode", arg->mod->Identifier); RET2RVAL(-1, rvalue); } /* * Do various non-recursive transformations. * Order is not important. */ TQ_FOR(expr, &(arg->mod->members), next) { int ret; arg->expr = expr; if(expr->meta_type == AMT_PARAMTYPE) /* Do not process the parametrized type just yet */ continue; DEBUG("=== Now processing \"%s\" at line %d ===", expr->Identifier, expr->_lineno); assert(expr->meta_type != AMT_INVALID); /* * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc). */ ret = asn1f_recurse_expr(arg, asn1f_fix_simple); RET2RVAL(ret, rvalue); /* * 2.[234] Process SEQUENCE/SET/CHOICE types. */ ret = asn1f_recurse_expr(arg, asn1f_fix_constructed); RET2RVAL(ret, rvalue); /* * 2.5.4 */ ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types); RET2RVAL(ret, rvalue); /* * 2.5.5 */ ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values); RET2RVAL(ret, rvalue); /* * Resolve references in constraints. */ ret = asn1f_recurse_expr(arg, asn1f_fix_constraints); RET2RVAL(ret, rvalue); /* * 6. INTEGER value processed at 2.5.4. */ /* * Make sure everybody's behaving well. */ assert(arg->expr == expr); } /* * 5. Automatic tagging */ TQ_FOR(expr, &(arg->mod->members), next) { int ret; arg->expr = expr; ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag); RET2RVAL(ret, rvalue); assert(arg->expr == expr); } /* * 8. fix BIT STRING * 9. fix spaces in cstrings */ TQ_FOR(expr, &(arg->mod->members), next) { int ret; arg->expr = expr; ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string); RET2RVAL(ret, rvalue); ret = asn1f_recurse_expr(arg, asn1f_fix_cstring); RET2RVAL(ret, rvalue); assert(arg->expr == expr); } /* * ... Check for tags distinctness. */ TQ_FOR(expr, &(arg->mod->members), next) { int ret; arg->expr = expr; ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct); RET2RVAL(ret, rvalue); assert(arg->expr == expr); } return rvalue; } static int asn1f_fix_simple(arg_t *arg) { int rvalue = 0; int ret; ret = asn1f_fix_enum(arg); RET2RVAL(ret, rvalue); ret = asn1f_fix_integer(arg); RET2RVAL(ret, rvalue); return rvalue; } static int asn1f_fix_constructed(arg_t *arg) { int rvalue = 0; int ret; switch(arg->expr->expr_type) { case ASN_CONSTR_SEQUENCE: case ASN_CONSTR_SET: case ASN_CONSTR_CHOICE: break; default: return 0; } /* Check identifier distinctness */ ret = asn1f_check_unique_expr(arg, NULL); RET2RVAL(ret, rvalue); /* Fix extensibility */ ret = asn1f_fix_constr_ext(arg); RET2RVAL(ret, rvalue); /* Fix tagging */ ret = asn1f_fix_constr_tag(arg); RET2RVAL(ret, rvalue); return rvalue; } static int _constraint_value_resolve(arg_t *arg, asn1p_value_t **value) { asn1p_expr_t expr; asn1p_expr_t *tmp_expr; asn1p_module_t *tmp_mod; asn1p_module_t *mod_r = NULL; int rvalue = 0; int ret; tmp_expr = asn1f_lookup_symbol(arg, (*value)->value.reference, &mod_r); if(tmp_expr == NULL) { FATAL("Cannot find symbol %s " "used in %s subtype constraint at line %d", asn1f_printable_reference((*value)->value.reference), arg->expr->Identifier, arg->expr->_lineno); assert((*value)->type == ATV_REFERENCED); return -1; } memset(&expr, 0, sizeof(expr)); expr.meta_type = tmp_expr->meta_type; expr.expr_type = tmp_expr->expr_type; expr.Identifier = tmp_expr->Identifier; expr.value = *value; tmp_expr = arg->expr; tmp_mod = arg->mod; arg->expr = &expr; arg->mod = mod_r; ret = asn1f_fix_dereference_values(arg); RET2RVAL(ret, rvalue); arg->expr = tmp_expr; arg->mod = tmp_mod; assert(expr.value); *value = expr.value; return rvalue; } static int _resolve_constraints(arg_t *arg, asn1p_constraint_t *ct) { int rvalue = 0; int ret; int el; /* Don't touch information object classes */ if(ct->type == ACT_CT_WCOMP || ct->type == ACT_CT_WCOMPS || ct->type == ACT_CA_CRC) return 0; if(ct->value && ct->value->type == ATV_REFERENCED) { ret = _constraint_value_resolve(arg, &ct->value); RET2RVAL(ret, rvalue); } if(ct->range_start && ct->range_start->type == ATV_REFERENCED) { ret = _constraint_value_resolve(arg, &ct->range_start); RET2RVAL(ret, rvalue); } if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) { ret = _constraint_value_resolve(arg, &ct->range_stop); RET2RVAL(ret, rvalue); } for(el = 0; el < ct->el_count; el++) { ret = _resolve_constraints(arg, ct->elements[el]); RET2RVAL(ret, rvalue); } return rvalue; } static int asn1f_fix_constraints(arg_t *arg) { int rvalue = 0; int ret; if(arg->expr->constraints) { ret = _resolve_constraints(arg, arg->expr->constraints); RET2RVAL(ret, rvalue); } return rvalue; } /* * Print everything to stderr */ static void _default_error_logger(int _severity, const char *fmt, ...) { va_list ap; char *pfx = ""; switch(_severity) { case -1: pfx = "DEBUG: "; break; case 0: pfx = "WARNING: "; break; case 1: pfx = "FATAL: "; break; } fprintf(stderr, "%s", pfx); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); }