aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1fix/asn1fix_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libasn1fix/asn1fix_misc.c')
-rw-r--r--libasn1fix/asn1fix_misc.c276
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;
+}
+