Initial version of asn1c
[com/asn1c.git] / libasn1parser / asn1p_value.c
diff --git a/libasn1parser/asn1p_value.c b/libasn1parser/asn1p_value.c
new file mode 100644 (file)
index 0000000..957b9e4
--- /dev/null
@@ -0,0 +1,346 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "asn1parser.h"
+#include "asn1p_expr.h"
+
+void
+asn1p_value_set_source(asn1p_value_t *value, asn1p_module_t *module,
+                       int lineno) {
+    if(value) {
+        switch(value->type) {
+        case ATV_TYPE:
+            asn1p_expr_set_source(value->value.v_type, module, lineno);
+            break;
+        case ATV_REFERENCED:
+            asn1p_ref_set_source(value->value.reference, module, lineno);
+            break;
+        case ATV_VALUESET:
+            asn1p_constraint_set_source(value->value.constraint, module,
+                                        lineno);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+int
+asn1p_value_compare(const asn1p_value_t *a, const asn1p_value_t *b) {
+    if(a->type != b->type) {
+        return -1;
+    }
+
+    switch(a->type) {
+    case ATV_NULL:
+    case ATV_NOVALUE:
+    case ATV_MAX:
+    case ATV_MIN:
+    case ATV_FALSE:
+    case ATV_TRUE:
+        break;
+    case ATV_TYPE:
+        return asn1p_expr_compare(a->value.v_type, b->value.v_type);
+    case ATV_REAL:
+        return (a->value.v_double == b->value.v_double) ? 0 : -1;
+    case ATV_INTEGER:
+    case ATV_TUPLE:
+    case ATV_QUADRUPLE:
+        return (a->value.v_integer == b->value.v_integer) ? 0 : -1;
+    case ATV_STRING:
+    case ATV_UNPARSED:
+        if(a->value.string.size != b->value.string.size
+           || memcmp(a->value.string.buf, b->value.string.buf,
+                     a->value.string.size)
+                  != 0) {
+            return -1;
+        }
+        return 0;
+    case ATV_BITVECTOR:
+        if(a->value.binary_vector.size_in_bits
+               != b->value.binary_vector.size_in_bits
+           || memcmp(a->value.binary_vector.bits, b->value.binary_vector.bits,
+                     (a->value.binary_vector.size_in_bits+7) >> 3)
+                  != 0) {
+            return -1;
+        }
+        return 0;
+    case ATV_VALUESET:
+        return asn1p_constraint_compare(a->value.constraint,
+                                        b->value.constraint);
+    case ATV_REFERENCED:
+        return asn1p_ref_compare(a->value.reference, b->value.reference);
+    case ATV_CHOICE_IDENTIFIER:
+        if(strcmp(a->value.choice_identifier.identifier,
+                  b->value.choice_identifier.identifier)
+           != 0) {
+            return -1;
+        }
+        return asn1p_value_compare(a->value.choice_identifier.value,
+                                   b->value.choice_identifier.value);
+    }
+
+    return 0;
+}
+
+asn1p_value_t *
+asn1p_value_fromref(asn1p_ref_t *ref, int do_copy) {
+       if(ref) {
+               asn1p_value_t *v = calloc(1, sizeof *v);
+               if(v) {
+                       if(do_copy) {
+                               v->value.reference = asn1p_ref_clone(ref);
+                               if(v->value.reference == NULL) {
+                                       free(v);
+                                       return NULL;
+                               }
+                       } else {
+                               v->value.reference = ref;
+                       }
+                       v->type = ATV_REFERENCED;
+               }
+               return v;
+       } else {
+               errno = EINVAL;
+               return NULL;
+       }
+}
+
+asn1p_value_t *
+asn1p_value_fromconstr(asn1p_constraint_t *ct, int do_copy) {
+       if(ct) {
+               asn1p_value_t *v = calloc(1, sizeof *v);
+               if(v) {
+                       if(do_copy) {
+                               v->value.constraint
+                                       = asn1p_constraint_clone(ct);
+                               if(v->value.constraint == NULL) {
+                                       free(v);
+                                       return NULL;
+                               }
+                       } else {
+                               v->value.constraint = ct;
+                       }
+                       v->type = ATV_VALUESET;
+               }
+               return v;
+       } else {
+               errno = EINVAL;
+               return NULL;
+       }
+}
+
+asn1p_value_t *
+asn1p_value_frombits(uint8_t *bits, int size_in_bits, int do_copy) {
+       if(bits) {
+               asn1p_value_t *v = calloc(1, sizeof *v);
+               assert(size_in_bits >= 0);
+               if(v) {
+                       if(do_copy) {
+                               int size = ((size_in_bits + 7) >> 3);
+                               void *p;
+                               p = malloc(size + 1);
+                               if(p) {
+                                       memcpy(p, bits, size);
+                                       ((char *)p)[size] = '\0'; /* JIC */
+                               } else {
+                                       free(v);
+                                       return NULL;
+                               }
+                               v->value.binary_vector.bits = p;
+                       } else {
+                               v->value.binary_vector.bits = (void *)bits;
+                       }
+                       v->value.binary_vector.size_in_bits = size_in_bits;
+                       v->type = ATV_BITVECTOR;
+               }
+               return v;
+       } else {
+               errno = EINVAL;
+               return NULL;
+       }
+}
+
+asn1p_value_t *
+asn1p_value_frombuf(char *buffer, int size, int do_copy) {
+       if(buffer) {
+               asn1p_value_t *v = calloc(1, sizeof *v);
+               assert(size >= 0);
+               if(v) {
+                       if(do_copy) {
+                               void *p = malloc(size + 1);
+                               if(p) {
+                                       memcpy(p, buffer, size);
+                                       ((char *)p)[size] = '\0'; /* JIC */
+                               } else {
+                                       free(v);
+                                       return NULL;
+                               }
+                               v->value.string.buf = p;
+                       } else {
+                               v->value.string.buf = (uint8_t *)buffer;
+                       }
+                       v->value.string.size = size;
+                       v->type = ATV_STRING;
+               }
+               return v;
+       } else {
+               errno = EINVAL;
+               return NULL;
+       }
+}
+
+asn1p_value_t *
+asn1p_value_fromdouble(double d) {
+       asn1p_value_t *v = calloc(1, sizeof *v);
+       if(v) {
+               v->value.v_double = d;
+               v->type = ATV_REAL;
+       }
+       return v;
+}
+
+asn1p_value_t *
+asn1p_value_fromint(asn1c_integer_t i) {
+       asn1p_value_t *v = calloc(1, sizeof *v);
+       if(v) {
+               v->value.v_integer = i;
+               v->type = ATV_INTEGER;
+       }
+       return v;
+}
+
+asn1p_value_t *
+asn1p_value_fromtype(asn1p_expr_t *expr) {
+       asn1p_value_t *v = calloc(1, sizeof *v);
+       if(v) {
+               v->value.v_type = expr;
+               v->type = ATV_TYPE;
+               expr->ref_cnt++;
+       }
+       return v;
+}
+
+asn1p_value_t *
+asn1p_value_clone(asn1p_value_t *v) {
+       return asn1p_value_clone_with_resolver(v, 0, 0);
+}
+
+asn1p_value_t *
+asn1p_value_clone_with_resolver(asn1p_value_t *v,
+               asn1p_value_t *(*resolver)(asn1p_value_t *, void *rarg),
+               void *rarg) {
+       asn1p_value_t *clone = NULL;
+       if(v) {
+               switch(v->type) {
+               case ATV_NOVALUE:
+               case ATV_NULL:
+                       return calloc(1, sizeof(*clone));
+               case ATV_REAL:
+                       return asn1p_value_fromdouble(v->value.v_double);
+               case ATV_TYPE:
+                       return asn1p_value_fromtype(v->value.v_type);
+               case ATV_INTEGER:
+               case ATV_MIN:
+               case ATV_MAX:
+               case ATV_FALSE:
+               case ATV_TRUE:
+               case ATV_TUPLE:
+               case ATV_QUADRUPLE:
+                       clone = asn1p_value_fromint(v->value.v_integer);
+                       if(clone) clone->type = v->type;
+                       return clone;
+               case ATV_STRING:
+                       clone = asn1p_value_frombuf((char *)v->value.string.buf,
+                               v->value.string.size, 1);
+                       if(clone) clone->type = v->type;
+                       return clone;
+               case ATV_UNPARSED:
+                       clone = asn1p_value_frombuf((char *)v->value.string.buf,
+                               v->value.string.size, 1);
+                       if(clone) clone->type = ATV_UNPARSED;
+                       return clone;
+               case ATV_BITVECTOR:
+                       return asn1p_value_frombits(v->value.binary_vector.bits,
+                               v->value.binary_vector.size_in_bits, 1);
+               case ATV_REFERENCED:
+                       if(resolver) {
+                               clone = resolver(v, rarg);
+                               if(clone) return clone;
+                               else if(errno != ESRCH) return NULL;
+                       }
+                       return asn1p_value_fromref(v->value.reference, 1);
+               case ATV_VALUESET:
+                       if(resolver) {
+                               clone = resolver(v, rarg);
+                               if(clone) return clone;
+                               else if(errno != ESRCH) return NULL;
+                       }
+                       return asn1p_value_fromconstr(v->value.constraint, 1);
+               case ATV_CHOICE_IDENTIFIER: {
+                       char *id = v->value.choice_identifier.identifier;
+                       clone = calloc(1, sizeof(*clone));
+                       if(!clone) return NULL;
+                       clone->type = v->type;
+                       id = strdup(id);
+                       if(!id) { asn1p_value_free(clone); return NULL; }
+                       clone->value.choice_identifier.identifier = id;
+                       v = asn1p_value_clone(v->value.choice_identifier.value);
+                       if(!v) { asn1p_value_free(clone); return NULL; }
+                       clone->value.choice_identifier.value = v;
+                       return clone;
+                   }
+               }
+
+               assert(!"UNREACHABLE");
+       }
+       return v;
+}
+
+void
+asn1p_value_free(asn1p_value_t *v) {
+       if(v) {
+               switch(v->type) {
+               case ATV_NOVALUE:
+               case ATV_NULL:
+                       break;
+               case ATV_TYPE:
+                       asn1p_expr_free(v->value.v_type);
+                       break;
+               case ATV_REAL:
+               case ATV_INTEGER:
+               case ATV_MIN:
+               case ATV_MAX:
+               case ATV_FALSE:
+               case ATV_TRUE:
+               case ATV_TUPLE:
+               case ATV_QUADRUPLE:
+                       /* No freeing necessary */
+                       break;
+               case ATV_STRING:
+               case ATV_UNPARSED:
+                       assert(v->value.string.buf);
+                       free(v->value.string.buf);
+                       break;
+               case ATV_BITVECTOR:
+                       assert(v->value.binary_vector.bits);
+                       free(v->value.binary_vector.bits);
+                       break;
+               case ATV_REFERENCED:
+                       asn1p_ref_free(v->value.reference);
+                       break;
+               case ATV_VALUESET:
+                       asn1p_constraint_free(v->value.constraint);
+                       break;
+               case ATV_CHOICE_IDENTIFIER:
+                       free(v->value.choice_identifier.identifier);
+                       asn1p_value_free(v->value.choice_identifier.value);
+                       break;
+               }
+               memset(v, 0, sizeof(*v));
+               free(v);
+       }
+}
+