#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; asn1c_integer_t max_value = -1; asn1c_integer_t max_value_ext = -1; int rvalue = 0; asn1p_expr_t *ext_marker = NULL; /* "..." position */ int ret; /* Keep track of value collisions */ asn1c_integer_t *used_vals; int used_vals_sz = 50; int used_vals_next = 0; if(expr->expr_type != ASN_BASIC_ENUMERATED) return 0; /* Just ignore it */ DEBUG("(%s)", expr->Identifier); used_vals = (asn1c_integer_t *) malloc(sizeof(asn1c_integer_t) * used_vals_sz); if (!used_vals) { FATAL("Out of memory"); return -1; } /* * 1. Scan the enumeration values in search for inconsistencies. */ TQ_FOR(ev, &(expr->members), next) { asn1c_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) { FATAL("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:""); 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. */ /* * Enumeration is allowed to be unordered * before the first marker, but after the marker * the values must be ordered. */ if (ext_marker) { if (eval > max_value_ext) { max_value_ext = eval; } else { FATAL( "Enumeration %s at line %d: " "Explicit value \"%s(%" PRIdASN ")\" " "is not greater " "than previous values (max %" PRIdASN ")", expr->Identifier, ev->_lineno, ev->Identifier, eval, max_value_ext); rvalue = -1; } } if (eval > max_value) { max_value = eval; } /* * 1.4 Check that all identifiers are unique */ int unique = 1; int uv_idx; for (uv_idx = 0; uv_idx < used_vals_next; uv_idx++) { if (used_vals[uv_idx] == eval) { FATAL( "Enumeration %s at line %d: " "Explicit value \"%s(%" PRIdASN ")\" " "collides with previous values", expr->Identifier, ev->_lineno, ev->Identifier, eval); rvalue = -1; unique = 0; } } if (unique) { /* Grow the array if needed */ if (used_vals_next >= used_vals_sz) { asn1c_integer_t *temp; int new_sz = used_vals_sz + 50; temp = (asn1c_integer_t *) realloc(used_vals, sizeof(asn1c_integer_t) * new_sz); if (!temp) return -1; used_vals = temp; used_vals_sz = new_sz; } used_vals[used_vals_next++] = eval; } /* * 1.5 Check that all identifiers before the current one * differs from it. */ ret = asn1f_check_unique_expr_child(arg, ev, 0, "identifier"); RET2RVAL(ret, rvalue); } free(used_vals); /* * 2. Reorder the first half (before optional "...") of the * identifiers alphabetically. */ // TODO return rvalue; }