2004-06-03 03:38:44 +00:00
|
|
|
#include "asn1fix_internal.h"
|
2004-06-28 21:21:24 +00:00
|
|
|
#include "asn1fix.h"
|
2004-06-03 03:38:44 +00:00
|
|
|
|
|
|
|
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;
|
2005-02-25 14:20:30 +00:00
|
|
|
static size_t managedptr_len;
|
2004-06-03 03:38:44 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
#define ENSURE(len) do { \
|
2005-02-25 14:20:30 +00:00
|
|
|
size_t __len = (len); \
|
2004-09-15 11:46:28 +00:00
|
|
|
if(__len >= managedptr_len) { \
|
2004-06-03 03:38:44 +00:00
|
|
|
if(managedptr) \
|
|
|
|
free(managedptr); \
|
2004-09-15 11:46:28 +00:00
|
|
|
managedptr = malloc(__len + 1); \
|
2004-06-03 03:38:44 +00:00
|
|
|
if(managedptr) { \
|
2004-09-15 11:46:28 +00:00
|
|
|
managedptr_len = __len; \
|
2004-06-03 03:38:44 +00:00
|
|
|
} 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>";
|
2004-09-15 11:46:28 +00:00
|
|
|
case ATV_NULL:
|
|
|
|
return "NULL";
|
2004-06-03 03:38:44 +00:00
|
|
|
case ATV_REAL:
|
|
|
|
ret = snprintf(buf, sizeof(buf), "%f", v->value.v_double);
|
2004-06-05 08:17:50 +00:00
|
|
|
if(ret >= (ssize_t)sizeof(buf))
|
2004-06-03 03:38:44 +00:00
|
|
|
memcpy(buf + sizeof(buf) - 4, "...", 4);
|
|
|
|
return buf;
|
|
|
|
case ATV_INTEGER:
|
2004-09-24 21:01:43 +00:00
|
|
|
ret = snprintf(buf, sizeof(buf), "%" PRIdASN,
|
|
|
|
v->value.v_integer);
|
2004-06-05 08:17:50 +00:00
|
|
|
if(ret >= (ssize_t)sizeof(buf))
|
2004-06-03 03:38:44 +00:00
|
|
|
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";
|
2005-03-24 14:40:22 +00:00
|
|
|
case ATV_TUPLE:
|
|
|
|
ret = snprintf(buf, sizeof(buf), "{%d, %d}",
|
|
|
|
(int)(v->value.v_integer >> 4),
|
|
|
|
(int)(v->value.v_integer & 0xff));
|
|
|
|
if(ret >= (ssize_t)sizeof(buf))
|
|
|
|
memcpy(buf + sizeof(buf) - 4, "...", 4);
|
|
|
|
return buf;
|
|
|
|
case ATV_QUADRUPLE:
|
|
|
|
ret = snprintf(buf, sizeof(buf), "{%d, %d, %d, %d}",
|
|
|
|
(int)((v->value.v_integer >> 24) & 0xff),
|
|
|
|
(int)((v->value.v_integer >> 16) & 0xff),
|
|
|
|
(int)((v->value.v_integer >> 8) & 0xff),
|
|
|
|
(int)(v->value.v_integer & 0xff));
|
|
|
|
if(ret >= (ssize_t)sizeof(buf))
|
|
|
|
memcpy(buf + sizeof(buf) - 4, "...", 4);
|
|
|
|
return buf;
|
2004-06-03 03:38:44 +00:00
|
|
|
case ATV_STRING:
|
|
|
|
case ATV_UNPARSED:
|
|
|
|
/* Buffer is guaranteed to be null-terminated */
|
|
|
|
assert(v->value.string.buf[v->value.string.size] == '\0');
|
2005-06-15 18:41:50 +00:00
|
|
|
return (char *)v->value.string.buf;
|
2004-06-03 03:38:44 +00:00
|
|
|
case ATV_BITVECTOR:
|
|
|
|
{
|
|
|
|
uint8_t *bitvector;
|
|
|
|
char *ptr;
|
2005-02-25 14:20:30 +00:00
|
|
|
size_t len;
|
2004-06-03 03:38:44 +00:00
|
|
|
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 {
|
2004-06-05 08:17:50 +00:00
|
|
|
static const char *hextable="0123456789ABCDEF";
|
2004-06-03 03:38:44 +00:00
|
|
|
/*
|
|
|
|
* 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';
|
2005-02-25 14:20:30 +00:00
|
|
|
assert(len == (size_t)(ptr - managedptr));
|
2004-06-03 03:38:44 +00:00
|
|
|
return managedptr;
|
|
|
|
}
|
2004-09-15 11:46:28 +00:00
|
|
|
case ATV_REFERENCED:
|
|
|
|
{
|
|
|
|
asn1p_ref_t *ref;
|
2005-02-25 14:20:30 +00:00
|
|
|
size_t reflen;
|
2004-09-15 11:46:28 +00:00
|
|
|
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';
|
2005-02-25 14:20:30 +00:00
|
|
|
assert(reflen == (size_t)(ptr - managedptr));
|
2004-09-15 11:46:28 +00:00
|
|
|
return managedptr;
|
|
|
|
}
|
|
|
|
case ATV_CHOICE_IDENTIFIER:
|
|
|
|
{
|
|
|
|
char *cid = v->value.choice_identifier.identifier;
|
|
|
|
char const *vptr = asn1f_printable_value(
|
|
|
|
v->value.choice_identifier.value);
|
|
|
|
char *val;
|
|
|
|
|
|
|
|
val = strdup(vptr);
|
|
|
|
if(!val) return "<memory allocation error>";
|
|
|
|
|
|
|
|
ENSURE(strlen(cid) + sizeof(": ") + strlen(val));
|
|
|
|
|
|
|
|
ret = snprintf(managedptr, managedptr_len + 1,
|
|
|
|
"%s: %s", cid, val);
|
2005-02-25 14:20:30 +00:00
|
|
|
assert(ret >= 0 && (size_t)ret <= managedptr_len);
|
2004-09-15 11:46:28 +00:00
|
|
|
free(val);
|
|
|
|
return managedptr;
|
|
|
|
}
|
2004-06-03 03:38:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2004-09-08 00:28:11 +00:00
|
|
|
assert(arg->expr->parent_expr == expr);
|
2004-06-03 03:38:44 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-06-28 21:21:24 +00:00
|
|
|
|
|
|
|
static char **known_types;
|
|
|
|
static int known_types_count;
|
|
|
|
static int known_types_size;
|
|
|
|
|
|
|
|
static int _known_types_cmp(const void *ap, const void *bp) {
|
|
|
|
const char *a = *(const char * const *)ap;
|
|
|
|
const char *b = *(const char * const *)bp;
|
|
|
|
return strcmp(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
asn1f_make_known_external_type(const char *type_name) {
|
|
|
|
char *tname;
|
|
|
|
|
|
|
|
/* Check for duplicates */
|
|
|
|
if(asn1f_check_known_external_type(type_name) == 0) {
|
|
|
|
errno = EEXIST;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure enough space */
|
|
|
|
if(known_types_count <= known_types_size) {
|
|
|
|
int n = known_types_size ? known_types_size << 1 : 4;
|
|
|
|
void *p;
|
|
|
|
p = realloc(known_types, n * sizeof(known_types[0]));
|
|
|
|
if(!p) return -1;
|
|
|
|
known_types = p;
|
|
|
|
known_types_size = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
tname = strdup(type_name);
|
|
|
|
if(!tname) return -1;
|
|
|
|
|
|
|
|
known_types[known_types_count++] = tname;
|
|
|
|
|
|
|
|
#ifdef HAVE_MERGESORT
|
|
|
|
mergesort
|
|
|
|
#else
|
|
|
|
qsort
|
|
|
|
#endif
|
|
|
|
(known_types, known_types_count, sizeof(known_types[0]),
|
|
|
|
_known_types_cmp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
asn1f_check_known_external_type(const char *type_name) {
|
2004-10-20 15:40:04 +00:00
|
|
|
if(known_types_count) {
|
|
|
|
void *p = bsearch(&type_name, known_types, known_types_count,
|
|
|
|
sizeof(known_types[0]), _known_types_cmp);
|
|
|
|
if(p) return 0;
|
|
|
|
}
|
2004-06-28 21:21:24 +00:00
|
|
|
errno = ESRCH;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|