mirror of https://gerrit.osmocom.org/asn1c
210 lines
5.4 KiB
C
210 lines
5.4 KiB
C
#include "asn1fix_internal.h"
|
|
|
|
static int _asn1f_copy_value(arg_t *arg, asn1p_expr_t *to,asn1p_expr_t *from);
|
|
|
|
int
|
|
asn1f_value_resolve(arg_t *arg, asn1p_expr_t *expr, const enum asn1p_constraint_type_e *opt_constr_type) {
|
|
asn1p_expr_t *val_type_expr;
|
|
asn1p_expr_t *value_expr;
|
|
asn1p_expr_t *type_expr;
|
|
int ret;
|
|
|
|
/* Make sure this IS a value assignment */
|
|
assert(expr->meta_type == AMT_VALUE);
|
|
assert(expr->value);
|
|
|
|
if(expr->value->type != ATV_REFERENCED)
|
|
return 0;
|
|
|
|
DEBUG("(=\"%s\", %x%s%s)",
|
|
asn1f_printable_value(expr->value), expr->expr_type,
|
|
opt_constr_type ? ", " : "",
|
|
opt_constr_type
|
|
? asn1p_constraint_type2str(*opt_constr_type) : ""
|
|
);
|
|
|
|
/*
|
|
* 1. Find the terminal type for this assignment.
|
|
*/
|
|
type_expr = asn1f_find_terminal_type(arg, expr);
|
|
if(type_expr == 0) {
|
|
if(errno == EEXIST) {
|
|
DEBUG("External type for %s at line %d",
|
|
expr->Identifier, expr->_lineno);
|
|
return 0;
|
|
} else {
|
|
FATAL("Terminal type for %s at line %d not found",
|
|
expr->Identifier, expr->_lineno);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(asn1f_look_value_in_type(arg, type_expr, expr) == -1) {
|
|
FATAL("Value not found in type for %s at line %d",
|
|
expr->Identifier, expr->_lineno);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* 2. Find the terminal value also.
|
|
*/
|
|
value_expr = asn1f_find_terminal_value(arg, expr);
|
|
if(value_expr) {
|
|
DEBUG("Terminal value for %s->%s is %s at line %d",
|
|
expr->Identifier, asn1f_printable_value(expr->value),
|
|
value_expr->Identifier, value_expr->_lineno);
|
|
} else {
|
|
FATAL("Terminal value for %s->%s not found",
|
|
expr->Identifier, asn1f_printable_value(expr->value));
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* 3. Find the _type_ of a _terminal value_.
|
|
*/
|
|
WITH_MODULE(value_expr->module,
|
|
val_type_expr = asn1f_find_terminal_type(arg, value_expr));
|
|
if(val_type_expr) {
|
|
DEBUG("Terminal type of value %s->%s is %s at line %d",
|
|
expr->Identifier, asn1f_printable_value(expr->value),
|
|
val_type_expr->Identifier, val_type_expr->_lineno);
|
|
} else {
|
|
FATAL("Terminal type of value %s->%s not found",
|
|
expr->Identifier, asn1f_printable_value(expr->value));
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* 4. Check compatibility between the type of the current expression
|
|
* and the type of the discovered value.
|
|
*/
|
|
if(opt_constr_type)
|
|
ret = asn1constraint_compatible(val_type_expr->expr_type,
|
|
*opt_constr_type, 0 /* must not matter here */);
|
|
else
|
|
ret = asn1f_check_type_compatibility(arg,
|
|
type_expr, val_type_expr);
|
|
if(ret == -1) {
|
|
switch(type_expr->expr_type) {
|
|
default:
|
|
if(!(type_expr->expr_type & ASN_STRING_MASK))
|
|
break;
|
|
/* Compatibility rules are not defined */
|
|
/* Fall through */
|
|
case ASN_BASIC_INTEGER:
|
|
case ASN_BASIC_ENUMERATED:
|
|
FATAL("Incompatible type of \"%s\" (%s) at line %d "
|
|
"with \"%s\" (%s) at line %d",
|
|
type_expr->Identifier,
|
|
ASN_EXPR_TYPE2STR(type_expr->expr_type),
|
|
type_expr->_lineno,
|
|
val_type_expr->Identifier,
|
|
ASN_EXPR_TYPE2STR(val_type_expr->expr_type),
|
|
val_type_expr->_lineno);
|
|
return -1;
|
|
case ASN_BASIC_OBJECT_IDENTIFIER:
|
|
/*
|
|
* Ignore this for now.
|
|
* We can't deal with OIDs inheritance properly yet.
|
|
*/
|
|
return 0;
|
|
}
|
|
WARNING("Possibly incompatible type of \"%s\" (%s) at line %d "
|
|
"with \"%s\" (%s) at line %d",
|
|
type_expr->Identifier,
|
|
ASN_EXPR_TYPE2STR(type_expr->expr_type),
|
|
type_expr->_lineno,
|
|
val_type_expr->Identifier,
|
|
ASN_EXPR_TYPE2STR(val_type_expr->expr_type),
|
|
val_type_expr->_lineno);
|
|
return 1;
|
|
}
|
|
|
|
if(asn1f_look_value_in_type(arg, val_type_expr, expr) == -1)
|
|
return -1;
|
|
|
|
/*
|
|
* 5. Copy value from the terminal value into the current expression.
|
|
*/
|
|
ret = _asn1f_copy_value(arg, expr, value_expr);
|
|
if(ret == -1) {
|
|
FATAL("Value %s cannot be copied from line %d to line %d",
|
|
asn1f_printable_value(value_expr->value),
|
|
value_expr->_lineno, expr->_lineno);
|
|
return -1;
|
|
}
|
|
|
|
DEBUG("Final value for \"%s\" at line %d is %s",
|
|
expr->Identifier, expr->_lineno,
|
|
asn1f_printable_value(expr->value));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_asn1f_copy_value(arg_t *arg, asn1p_expr_t *to, asn1p_expr_t *from) {
|
|
asn1p_value_t *v;
|
|
|
|
v = asn1p_value_clone(from->value);
|
|
if(v) {
|
|
asn1p_value_free(to->value);
|
|
to->value = v;
|
|
DEBUG("Copied value %s from \"%s\" on line %d "
|
|
"to \"%s\" on line %d",
|
|
asn1f_printable_value(v),
|
|
from->Identifier,
|
|
from->_lineno,
|
|
to->Identifier,
|
|
to->_lineno
|
|
);
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int
|
|
asn1f_look_value_in_type(arg_t *arg,
|
|
asn1p_expr_t *type_expr,
|
|
asn1p_expr_t *value_expr) {
|
|
asn1p_expr_t *child_expr;
|
|
char *identifier;
|
|
|
|
if(value_expr->value->type != ATV_REFERENCED
|
|
|| value_expr->value->value.reference->comp_count != 1)
|
|
return 0;
|
|
if(type_expr->expr_type != ASN_BASIC_INTEGER
|
|
&& type_expr->expr_type != ASN_BASIC_ENUMERATED)
|
|
return 0;
|
|
|
|
DEBUG("(for %s in %s %x) for line %d",
|
|
asn1f_printable_value(value_expr->value),
|
|
type_expr->Identifier,
|
|
type_expr->expr_type,
|
|
value_expr->_lineno);
|
|
|
|
/*
|
|
* Look into the definitions of the type itself:
|
|
* Type1 ::= INTEGER { a(1), b(2) }
|
|
* value Type1 = b -- will assign 2
|
|
*/
|
|
identifier = value_expr->value->value.reference->components[0].name;
|
|
|
|
child_expr = asn1f_lookup_child(type_expr, identifier);
|
|
DEBUG("Looking into a type %s at line %d for %s at line %d: %s",
|
|
type_expr->Identifier, type_expr->_lineno,
|
|
identifier, value_expr->_lineno,
|
|
child_expr
|
|
? asn1f_printable_value(child_expr->value)
|
|
: "<not found>"
|
|
);
|
|
|
|
if(child_expr && child_expr->value) {
|
|
if(_asn1f_copy_value(arg, value_expr, child_expr))
|
|
return -1;
|
|
/* Fall through */
|
|
}
|
|
|
|
return 0;
|
|
}
|