#include "asn1fix_internal.h" #include "asn1fix_constraint.h" #include "asn1fix_crange.h" static void _remove_extensions(arg_t *arg, asn1p_constraint_t *ct, int flast); static int constraint_type_resolve(arg_t *arg, asn1p_constraint_t *ct); static int constraint_value_resolve(arg_t *arg, asn1p_value_t **value, enum asn1p_constraint_type_e real_ctype); int asn1constraint_pullup(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *top_parent; asn1p_constraint_t *ct_parent; asn1p_constraint_t *ct_expr; int ret; if(expr->combined_constraints) return 0; /* Operation already performed earlier */ switch(expr->meta_type) { case AMT_TYPE: case AMT_TYPEREF: break; default: return 0; /* Nothing to do */ } if(expr->expr_type == A1TC_REFERENCE) { asn1p_ref_t *ref = expr->reference; asn1p_expr_t *parent_expr; assert(ref); parent_expr = asn1f_lookup_symbol(arg, expr->module, expr->rhs_pspecs, ref); if(!parent_expr) { if(errno != EEXIST) { DEBUG("\tWhile fetching parent constraints: " "type \"%s\" not found: %s", asn1f_printable_reference(ref), strerror(errno)); return -1; } else { /* * -fknown-extern-type is given. * Assume there are no constraints there. */ WARNING("External type \"%s\": " "assuming no constraints", asn1f_printable_reference(ref)); ct_parent = 0; } } else { arg->expr = parent_expr; ret = asn1constraint_pullup(arg); arg->expr = expr; if(ret) return ret; ct_parent = parent_expr->combined_constraints; } } else { ct_parent = 0; } ct_expr = expr->constraints; if(!ct_parent && !ct_expr) return 0; /* No constraints to consider */ /* * Resolve constraints, if not already resolved. */ top_parent = asn1f_find_terminal_type(arg, arg->expr); ret = asn1constraint_resolve(arg, ct_expr, top_parent ? top_parent->expr_type : A1TC_INVALID, 0); if(ret) return ret; /* * Copy parent type constraints. */ if(ct_parent) { ct_parent = asn1p_constraint_clone(ct_parent); assert(ct_parent); } /* * If the current type does not have constraints, it inherits * the constraints of a parent. */ if(ct_parent && !ct_expr) { expr->combined_constraints = ct_parent; return 0; } ct_expr = asn1p_constraint_clone(ct_expr); assert(ct_expr); /* * Now we have a set of current expression's constraints, * and an optional set of the parent expression's constraints. */ if(ct_parent) { /* * If we have a parent, remove all the extensions (46.4). */ _remove_extensions(arg, ct_parent, 0); expr->combined_constraints = ct_parent; if(ct_expr->type == ACT_CA_SET) { unsigned int i; for(i = 0; i < ct_expr->el_count; i++) { if(asn1p_constraint_insert( expr->combined_constraints, ct_expr->elements[i])) { expr->combined_constraints = 0; asn1p_constraint_free(ct_expr); asn1p_constraint_free(ct_parent); return -1; } else { ct_expr->elements[i] = 0; } } asn1p_constraint_free(ct_expr); } else { asn1p_constraint_insert(expr->combined_constraints, ct_expr); } } else { _remove_extensions(arg, ct_expr, 1); expr->combined_constraints = ct_expr; } return 0; } int asn1constraint_resolve(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_type_e etype, enum asn1p_constraint_type_e effective_type) { enum asn1p_constraint_type_e real_constraint_type; unsigned int el; int rvalue = 0; int ret; DEBUG("(\"%s\")", arg->expr->Identifier); if(!ct) return 0; /* Don't touch information object classes */ switch(ct->type) { case ACT_CT_SIZE: case ACT_CT_FROM: if(effective_type && effective_type != ct->type) { FATAL("%s at line %d: " "Incompatible nested %s within %s", arg->expr->Identifier, ct->_lineno, asn1p_constraint_type2str(ct->type), asn1p_constraint_type2str(effective_type) ); } effective_type = ct->type; break; case ACT_CT_WCOMP: case ACT_CT_WCOMPS: case ACT_CA_CRC: return 0; default: break; } real_constraint_type = effective_type ? effective_type : ct->type; if(etype != A1TC_INVALID) { ret = asn1constraint_compatible(etype, real_constraint_type, arg->flags & A1F_EXTENDED_SizeConstraint); switch(ret) { case -1: /* If unknown, assume OK. */ case 1: break; case 0: default: FATAL("%s at line %d: " "Constraint type %s is not applicable to %s", arg->expr->Identifier, ct->_lineno, asn1p_constraint_type2str(real_constraint_type), ASN_EXPR_TYPE2STR(etype) ); rvalue = -1; break; } } else { WARNING("%s at line %d: " "Constraints ignored: Unresolved parent type", arg->expr->Identifier, arg->expr->_lineno); } /* * Resolve all possible references, wherever they occur. */ if(ct->containedSubtype) { ret = constraint_type_resolve(arg, ct); RET2RVAL(ret, rvalue); } if(ct->value && ct->value->type == ATV_REFERENCED) { ret = constraint_value_resolve(arg, &ct->value, real_constraint_type); RET2RVAL(ret, rvalue); } if(ct->range_start && ct->range_start->type == ATV_REFERENCED) { ret = constraint_value_resolve(arg, &ct->range_start, real_constraint_type); RET2RVAL(ret, rvalue); } if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) { ret = constraint_value_resolve(arg, &ct->range_stop, real_constraint_type); RET2RVAL(ret, rvalue); } /* * Proceed recursively. */ for(el = 0; el < ct->el_count; el++) { ret = asn1constraint_resolve(arg, ct->elements[el], etype, effective_type); RET2RVAL(ret, rvalue); } return rvalue; } static void _remove_extensions(arg_t *arg, asn1p_constraint_t *ct, int forgive_last) { unsigned int i; if(!ct) return; for(i = 0; i < ct->el_count; i++) { if(ct->elements[i]->type == ACT_EL_EXT) break; if(forgive_last && ct->type == ACT_CA_SET && i + 1 == ct->el_count) return; _remove_extensions(arg, ct->elements[i], 0); } /* Remove the elements at and after the extensibility mark */ for(; i < ct->el_count; ct->el_count--) { asn1p_constraint_t *rm; rm = ct->elements[ct->el_count-1]; asn1p_constraint_free(rm); } if(i < ct->el_size) ct->elements[i] = 0; } static int constraint_type_resolve(arg_t *arg, asn1p_constraint_t *ct) { asn1p_constraint_t *ct_expr; int ret; DEBUG("(\"%s\")", asn1f_printable_value(ct->containedSubtype)); if(ct->containedSubtype->type == ATV_VALUESET) { ct_expr = ct->containedSubtype->value.constraint; DEBUG("Found %s in constraints", "ValueSet"); } else if(ct->containedSubtype->type == ATV_REFERENCED) { asn1p_expr_t *rtype; arg_t tmparg; rtype = asn1f_lookup_symbol(arg, arg->expr->module, arg->expr->rhs_pspecs, ct->containedSubtype->value.reference); if(!rtype) { FATAL("Cannot find type \"%s\" in constraints " "at line %d", asn1f_printable_value(ct->containedSubtype), ct->_lineno); return -1; } tmparg = *arg; tmparg.expr = rtype; tmparg.mod = rtype->module; ret = asn1constraint_pullup(&tmparg); if(ret) return ret; ct_expr = rtype->combined_constraints; if(!ct_expr) return 0; } else { FATAL("Unsupported feature at line %d", ct->_lineno); return -1; } ct_expr = asn1p_constraint_clone(ct_expr); assert(ct_expr); _remove_extensions(arg, ct_expr, 0); if(ct_expr->type == ACT_CA_SET) { unsigned int i; for(i = 0; i < ct_expr->el_count; i++) { if(asn1p_constraint_insert( ct, ct_expr->elements[i])) { asn1p_constraint_free(ct_expr); return -1; } else { ct_expr->elements[i] = 0; } } asn1p_constraint_free(ct_expr); } else { ret = asn1p_constraint_insert(ct, ct_expr); assert(ret == 0); } ct->type = ACT_CA_SET; asn1p_value_free(ct->containedSubtype); ct->containedSubtype = NULL; return 0; } static int constraint_value_resolve(arg_t *arg, asn1p_value_t **value, enum asn1p_constraint_type_e real_ctype) { asn1p_expr_t static_expr; arg_t tmp_arg; int rvalue = 0; int ret; DEBUG("(\"%s\", within <%s>)", asn1f_printable_value(*value), asn1p_constraint_type2str(real_ctype)); static_expr = *arg->expr; static_expr.value = *value; static_expr.meta_type = AMT_VALUE; tmp_arg = *arg; tmp_arg.mod = arg->expr->module; tmp_arg.expr = &static_expr; ret = asn1f_value_resolve(&tmp_arg, &static_expr, &real_ctype); RET2RVAL(ret, rvalue); assert(static_expr.value); *value = static_expr.value; return rvalue; }