diff options
Diffstat (limited to 'libasn1fix/asn1fix_value.c')
-rw-r--r-- | libasn1fix/asn1fix_value.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/libasn1fix/asn1fix_value.c b/libasn1fix/asn1fix_value.c new file mode 100644 index 00000000..a22fd3dc --- /dev/null +++ b/libasn1fix/asn1fix_value.c @@ -0,0 +1,159 @@ +#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) { + asn1p_module_t *val_mod; + 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); + + DEBUG("%s(=\"%s\", %x)", __func__, + asn1f_printable_value(expr->value), expr->expr_type); + + /* + * 1. Find the terminal type for this assignment. + */ + type_expr = asn1f_find_terminal_type(arg, expr, 0); + if(type_expr == 0) { + DEBUG("\tTerminal type for %s not found", expr->Identifier); + return -1; + } + + if(asn1f_look_value_in_type(arg, type_expr, expr) == -1) + return -1; + + /* + * 2. Find the terminal value also. + */ + value_expr = asn1f_find_terminal_value(arg, expr, &val_mod); + if(value_expr) { + DEBUG("\tTerminal value for %s->%s is %s at line %d", + expr->Identifier, asn1f_printable_value(expr->value), + value_expr->Identifier, value_expr->_lineno); + } else { + DEBUG("\tTerminal 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(val_mod, + val_type_expr = asn1f_find_terminal_type(arg, value_expr, 0)); + if(val_type_expr) { + DEBUG("\tTerminal 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 { + DEBUG("\tTerminal 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. + */ + ret = asn1f_check_type_compatibility(arg, type_expr, val_type_expr); + if(ret == -1) { + DEBUG("\tIncompatible type of %s at %d with %s at %d", + type_expr->Identifier, type_expr->_lineno, + val_type_expr->Identifier, 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) { + DEBUG("\tValue %s cannot be copied from line %d to line %d", + asn1f_printable_value(value_expr->value), + value_expr->_lineno, expr->_lineno); + return -1; + } + + DEBUG("\tFinal 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("%s(for %s in %s %x) for line %d", __func__, + 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("\tLooking 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; +} |