diff options
Diffstat (limited to 'libasn1fix/asn1fix_enum.c')
-rw-r--r-- | libasn1fix/asn1fix_enum.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/libasn1fix/asn1fix_enum.c b/libasn1fix/asn1fix_enum.c new file mode 100644 index 00000000..8a90a435 --- /dev/null +++ b/libasn1fix/asn1fix_enum.c @@ -0,0 +1,136 @@ +#include "asn1fix_internal.h" + +/* + * Check the validity of an enumeration. + */ +int +asn1f_fix_enum(arg_t *arg) { + asn1p_expr_t *expr = arg->expr; + asn1p_expr_t *ev; + asn1_integer_t max_value = -1; + int rvalue = 0; + asn1p_expr_t *ext_marker = NULL; /* "..." position */ + int ret; + + if(expr->expr_type != ASN_BASIC_ENUMERATED) + return 0; /* Just ignore it */ + + DEBUG("%s(%s)", __func__, expr->Identifier); + + /* + * 1. Scan the enumeration values in search for inconsistencies. + */ + TQ_FOR(ev, &(expr->members), next) { + asn1_integer_t eval; + + if(ev->value) + DEBUG("\tItem %s(%s)", ev->Identifier, + asn1f_printable_value(ev->value)); + else + DEBUG("\tItem %s", ev->Identifier); + + /* + * 1.1 Found an extension mark "...", check correctness. + */ + if(ev->expr_type == A1TC_EXTENSIBLE) { + if(ext_marker) { + arg->eh(1, + "Enumeration %s at line %d: " + "Second extension marker is not allowed", + expr->Identifier, + ev->_lineno); + rvalue = -1; + } else { + /* + * Remember the marker's position. + */ + ext_marker = ev; + } + continue; + } else if(ev->Identifier == NULL + || ev->expr_type != A1TC_UNIVERVAL) { + FATAL( + "Enumeration %s at line %d: " + "Unsupported enumeration element %s", + expr->Identifier, + ev->_lineno, + ev->Identifier?ev->Identifier:"<anonymous>"); + rvalue = -1; + continue; + } + + /* + * 1.2 Compute the value of the enumeration element. + */ + if(ev->value) { + switch(ev->value->type) { + case ATV_INTEGER: + eval = ev->value->value.v_integer; + break; + case ATV_REFERENCED: + FATAL("HERE HERE HERE", 1); + rvalue = -1; + continue; + break; + default: + FATAL("ENUMERATED type %s at line %d " + "contain element %s(%s) at line %d", + expr->Identifier, expr->_lineno, + ev->Identifier, + asn1f_printable_value(ev->value), + ev->_lineno); + rvalue = -1; + continue; + } + } else { + eval = max_value + 1; + ev->value = asn1p_value_fromint(eval); + if(ev->value == NULL) { + rvalue = -1; + continue; + } + } + + /* + * 1.3 Check the applicability of this value. + */ + if(eval <= max_value) { + if(ext_marker) { + /* + * Enumeration is allowed to be unordered + * before the first marker. + */ + FATAL( + "Enumeration %s at line %d: " + "Explicit value \"%s(%lld)\" " + "is not greater " + "than previous values (max %lld)", + expr->Identifier, + ev->_lineno, + ev->Identifier, + eval, + max_value); + rvalue = -1; + } + } else if(eval > max_value) { + max_value = eval; + } + + /* + * 1.4 Check that all identifiers before the current one + * differs from it. + */ + ret = asn1f_check_unique_expr_child(arg, ev, NULL); + RET2RVAL(ret, rvalue); + } + + + /* + * 2. Reorder the first half (before optional "...") of the + * identifiers alphabetically. + */ + // TODO + + return rvalue; +} + |