mirror of https://gerrit.osmocom.org/asn1c
373 lines
9.1 KiB
C
373 lines
9.1 KiB
C
#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_object_resolve(arg_t *arg, asn1p_value_t *value);
|
|
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->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);
|
|
}
|
|
if (ct->value && ct->value->type == ATV_UNPARSED && etype == A1TC_CLASSDEF) {
|
|
ret = constraint_object_resolve(arg, ct->value);
|
|
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->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 tmparg;
|
|
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;
|
|
tmparg = *arg;
|
|
tmparg.mod = arg->expr->module;
|
|
tmparg.expr = &static_expr;
|
|
ret = asn1f_value_resolve(&tmparg, &static_expr, &real_ctype);
|
|
RET2RVAL(ret, rvalue);
|
|
assert(static_expr.value);
|
|
*value = static_expr.value;
|
|
|
|
return rvalue;
|
|
}
|
|
|
|
static int
|
|
constraint_object_resolve(arg_t *arg, asn1p_value_t *value) {
|
|
asn1p_expr_t tmp_expr = *arg->expr;
|
|
asn1p_expr_t *saved_expr = arg->expr;
|
|
|
|
tmp_expr.meta_type = AMT_VALUESET;
|
|
tmp_expr.expr_type = A1TC_REFERENCE;
|
|
tmp_expr.value = value;
|
|
arg->expr = &tmp_expr;
|
|
|
|
if (asn1f_check_class_object(arg)) {
|
|
arg->expr = saved_expr;
|
|
FATAL("Parsing ObjectSet %s failed at %d", arg->expr->Identifier,
|
|
arg->expr->_lineno);
|
|
return -1;
|
|
}
|
|
|
|
arg->expr = saved_expr;
|
|
return 0;
|
|
}
|
|
|