mirror of https://gerrit.osmocom.org/asn1c
347 lines
8.0 KiB
C
347 lines
8.0 KiB
C
#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);
|
|
}
|
|
}
|
|
|