diff options
Diffstat (limited to 'libasn1fix/asn1fix_misc.c')
-rw-r--r-- | libasn1fix/asn1fix_misc.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/libasn1fix/asn1fix_misc.c b/libasn1fix/asn1fix_misc.c new file mode 100644 index 00000000..5fe69034 --- /dev/null +++ b/libasn1fix/asn1fix_misc.c @@ -0,0 +1,276 @@ +#include "asn1fix_internal.h" + + +char const * +asn1f_printable_reference(asn1p_ref_t *ref) { + if(ref) { + asn1p_value_t v; + + v.type = ATV_REFERENCED; + v.value.reference = ref; + + return asn1f_printable_value(&v); + } else { + return "<no ref>"; + } +} + +char const * +asn1f_printable_value(asn1p_value_t *v) { + static char buf[128]; + static char *managedptr; + static int managedptr_len; + int ret; + +#define ENSURE(len) do { \ + if(len >= managedptr_len) { \ + if(managedptr) \ + free(managedptr); \ + managedptr = malloc(len + 1); \ + if(managedptr) { \ + managedptr_len = len; \ + } else { \ + managedptr_len = 0; \ + return "<memory allocation error>"; \ + } \ + } \ + } while(0) + + if(v == NULL) + return "<no value>"; + + switch(v->type) { + case ATV_NOVALUE: + return "<NO VALUE>"; + case ATV_REFERENCED: + { + asn1p_ref_t *ref; + char reflen; + char *ptr; + int i; + + assert(v->value.reference); + ref = v->value.reference; + reflen = ref->comp_count; /* Number of dots */ + for(i = 0; i < ref->comp_count; i++) + reflen += strlen(ref->components[i].name); + /* + * Make sure we have a buffer of this size. + */ + ENSURE(reflen); + + /* + * Fill-up the buffer. + */ + ptr = managedptr; + for(i = 0; i < ref->comp_count; i++) { + char *nc; + if(i) *ptr++ = '.'; + for(nc = ref->components[i].name; *nc; nc++) + *ptr++ = *nc; + } + *ptr++ = '\0'; + assert(reflen == (ptr - managedptr)); + return managedptr; + } + case ATV_REAL: + ret = snprintf(buf, sizeof(buf), "%f", v->value.v_double); + if(ret >= sizeof(buf)) + memcpy(buf + sizeof(buf) - 4, "...", 4); + return buf; + case ATV_INTEGER: + ret = snprintf(buf, sizeof(buf), "%lld", + (long long)v->value.v_integer); + if(ret >= sizeof(buf)) + memcpy(buf + sizeof(buf) - 4, "...", 4); + return buf; + case ATV_MIN: return "MIN"; + case ATV_MAX: return "MAX"; + case ATV_FALSE: return "FALSE"; + case ATV_TRUE: return "TRUE"; + case ATV_STRING: + case ATV_UNPARSED: + /* Buffer is guaranteed to be null-terminated */ + assert(v->value.string.buf[v->value.string.size] == '\0'); + return v->value.string.buf; + case ATV_BITVECTOR: + { + uint8_t *bitvector; + char *ptr; + int len; + int i; + /* + * Compute number of bytes necessary + * to represend the binary value. + */ + int bits = v->value.binary_vector.size_in_bits; + len = ((bits%8)?bits:(bits >> 2)) + sizeof("''H"); + /* + * Reallocate managed buffer + */ + ENSURE(len); + + /* + * Fill the buffer. + */ + ptr = managedptr; + bitvector = v->value.binary_vector.bits; + *ptr++ = '\''; + if(bits%8) { + /* + * Dump bit by bit. + */ + for(i = 0; i < bits; i++) { + uint8_t uc; + uc = bitvector[i>>3]; + *ptr++ = ((uc >> (7-(i%8)))&1)?'1':'0'; + } + } else { + char hextable[16] = "0123456789ABCDEF"; + /* + * Dump byte by byte. + */ + for(i = 0; i < (bits >> 3); i++) { + *ptr++ = hextable[bitvector[i] >> 4]; + *ptr++ = hextable[bitvector[i] & 0x0f]; + } + } + *ptr++ = '\''; + *ptr++ = (bits%8)?'B':'H'; + *ptr++ = 'H'; + assert((ptr - managedptr) == len); + return managedptr; + } + } + + return "<some complex value>"; +} + + +/* + * Recursively invoke a given function over the given expr and all its + * children. + */ +int +asn1f_recurse_expr(arg_t *arg, int (*callback)(arg_t *arg)) { + asn1p_expr_t *expr = arg->expr; + int rvalue = 0; + int ret; + + assert(expr); + + /* + * Invoke the callback at this very level. + */ + ret = callback(arg); + RET2RVAL(ret, rvalue); + + /* + * Recursively invoke myself + * to iterate over each element in the tree. + */ + TQ_FOR(arg->expr, &(expr->members), next) { + assert(arg->expr->expr_type != A1TC_INVALID); + ret = asn1f_recurse_expr(arg, callback); + RET2RVAL(ret, rvalue); + } + + arg->expr = expr; /* Restore original position */ + + return rvalue; +} + + +/* + * Check that every child of a given expr has unique name or does not have any. + */ +int +asn1f_check_unique_expr(arg_t *arg, + int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) { + asn1p_expr_t *expr; + int rvalue = 0; + + TQ_FOR(expr, &(arg->expr->members), next) { + if(expr->Identifier) { + int ret = asn1f_check_unique_expr_child(arg, expr, + opt_compare); + if(ret) rvalue = -1; + } else { + /* + * No point of comparing this child with any other: + * this one does not have a name. + */ + } + } + + return rvalue; +} + +/* + * Check that every preceeding child of the given expr is not + * having the name of the given one. + */ +int +asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child, + int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) { + asn1p_expr_t *expr; + int rvalue = 0; + + assert(child); + assert(opt_compare || child->Identifier); + + TQ_FOR(expr, &(arg->expr->members), next) { + int ret; + + if(expr == child) + break; + + /* + * Compare according to the custom rule or default + * names comparisons. + */ + if(opt_compare) { + ret = opt_compare(expr, child); + } else { + if(expr->Identifier == NULL + || expr->expr_type == A1TC_EXTENSIBLE) + continue; + ret = strcasecmp(expr->Identifier, child->Identifier); + } + + if(ret == 0) { + char *msg; + msg = opt_compare + ?"Expressions clash" + :"Identifiers name clash"; + arg->eh(1, + "%s: " + "\"%s\" at line %d has similar %s with " + "\"%s\" at line %d", + msg, + expr->Identifier, + expr->_lineno, + opt_compare?"property":"name", + child->Identifier, + child->_lineno + ); + + rvalue = -1; + } + } + + return rvalue; +} + +int +asn1f_count_children(asn1p_expr_t *expr) { + asn1p_expr_t *child; + int count = 0; + + TQ_FOR(child, &(expr->members), next) { + count++; + } + + return count; +} + |