mirror of https://gerrit.osmocom.org/asn1c
299 lines
7.3 KiB
C
299 lines
7.3 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
#include "asn1parser.h"
|
|
|
|
static asn1p_expr_t *asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*)(asn1p_expr_t *, void *), void *);
|
|
static asn1p_value_t *value_resolver(asn1p_value_t *, void *arg);
|
|
|
|
/*
|
|
* Construct a new empty types collection.
|
|
*/
|
|
asn1p_expr_t *
|
|
asn1p_expr_new(int _lineno) {
|
|
asn1p_expr_t *expr;
|
|
|
|
expr = calloc(1, sizeof *expr);
|
|
if(expr) {
|
|
TQ_INIT(&(expr->members));
|
|
expr->spec_index = -1;
|
|
expr->_lineno = _lineno;
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
asn1p_expr_t *
|
|
asn1p_expr_clone(asn1p_expr_t *expr, int skip_extensions) {
|
|
return asn1p_expr_clone_impl(expr, skip_extensions, 0, 0);
|
|
}
|
|
|
|
asn1p_expr_t *
|
|
asn1p_expr_clone_with_resolver(asn1p_expr_t *expr, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) {
|
|
return asn1p_expr_clone_impl(expr, 0, r, rarg);
|
|
}
|
|
|
|
static asn1p_expr_t *
|
|
asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) {
|
|
asn1p_value_t *(*vr)(asn1p_value_t *, void *) = 0;
|
|
asn1p_expr_t *clone = 0;
|
|
asn1p_expr_t *tcmemb; /* Child of tc */
|
|
int hit_ext = 0;
|
|
|
|
#define CLCOPY(field) do { clone->field = expr->field; } while(0)
|
|
#define CLCLONE(field, func) do { if(expr->field) { \
|
|
clone->field = func(expr->field); \
|
|
if(clone->field == NULL) { \
|
|
asn1p_expr_free(clone); \
|
|
return NULL; \
|
|
} \
|
|
} } while(0)
|
|
#define CLVRCLONE(field, func) do { if(expr->field) { \
|
|
clone->field = func(expr->field, vr, rarg); \
|
|
if(clone->field == NULL) { \
|
|
asn1p_expr_free(clone); \
|
|
return NULL; \
|
|
} \
|
|
} } while(0)
|
|
|
|
if(r) {
|
|
vr = value_resolver;
|
|
clone = r(expr, rarg);
|
|
if(clone) {
|
|
/* Merge constraints */
|
|
if(expr->constraints) {
|
|
asn1p_constraint_t *tmpct = asn1p_constraint_clone_with_resolver(expr->constraints, vr, rarg);
|
|
if(clone->constraints) {
|
|
if(asn1p_constraint_insert(clone->constraints, tmpct)) {
|
|
asn1p_constraint_free(tmpct);
|
|
asn1p_expr_free(clone);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
clone->constraints = tmpct;
|
|
}
|
|
assert(expr->combined_constraints == 0);
|
|
}
|
|
/* Merge defaults */
|
|
CLCOPY(marker.flags);
|
|
CLVRCLONE(marker.default_value,
|
|
asn1p_value_clone_with_resolver);
|
|
if(clone->tag.tag_class == TC_NOCLASS) {
|
|
CLCOPY(tag);
|
|
} else if(expr->tag.tag_class != TC_NOCLASS) {
|
|
fprintf(stderr, "asn1c does not support "
|
|
"nested tagging in parameterization, "
|
|
"necessary at line %d\n",
|
|
expr->_lineno);
|
|
asn1p_expr_free(clone);
|
|
return NULL;
|
|
}
|
|
return clone;
|
|
} else if(errno != ESRCH) {
|
|
return NULL; /* Hard error */
|
|
}
|
|
}
|
|
if(!clone) clone = asn1p_expr_new(expr->_lineno);
|
|
if(!clone) return NULL;
|
|
|
|
/*
|
|
* Copy simple fields.
|
|
*/
|
|
CLCOPY(meta_type);
|
|
CLCOPY(expr_type);
|
|
CLCOPY(tag);
|
|
CLCOPY(marker.flags); /* OPTIONAL/DEFAULT */
|
|
CLCOPY(module);
|
|
CLCOPY(_mark);
|
|
|
|
clone->data = 0; /* Do not clone this */
|
|
clone->data_free = 0; /* Do not clone this */
|
|
|
|
/*
|
|
* Clone complex fields.
|
|
*/
|
|
CLCLONE(Identifier, strdup);
|
|
CLCLONE(reference, asn1p_ref_clone);
|
|
CLVRCLONE(constraints, asn1p_constraint_clone_with_resolver);
|
|
CLVRCLONE(combined_constraints, asn1p_constraint_clone_with_resolver);
|
|
CLCLONE(lhs_params, asn1p_paramlist_clone);
|
|
CLVRCLONE(value, asn1p_value_clone_with_resolver);
|
|
CLVRCLONE(marker.default_value, asn1p_value_clone_with_resolver);
|
|
CLCLONE(with_syntax, asn1p_wsyntx_clone);
|
|
|
|
/*
|
|
* Copy all the children of this expr.
|
|
*/
|
|
TQ_FOR(tcmemb, &(expr->members), next) {
|
|
asn1p_expr_t *cmemb;
|
|
|
|
if(skip_extensions
|
|
&& tcmemb->expr_type == A1TC_EXTENSIBLE) {
|
|
hit_ext++; /* Even if hit_ext wraps around, we're OK. */
|
|
continue;
|
|
}
|
|
if(hit_ext == 1) continue; /* Skip between ...'s */
|
|
|
|
cmemb = asn1p_expr_clone_impl(tcmemb, skip_extensions, r, rarg);
|
|
if(cmemb == NULL) {
|
|
asn1p_expr_free(clone);
|
|
return NULL;
|
|
}
|
|
asn1p_expr_add(clone, cmemb);
|
|
}
|
|
|
|
return clone;
|
|
}
|
|
|
|
|
|
static asn1p_value_t *
|
|
value_resolver(asn1p_value_t *value, void *rarg) {
|
|
asn1p_value_t *cval;
|
|
asn1p_expr_t *tmpexpr;
|
|
asn1p_expr_t *target;
|
|
asn1p_ref_t *ref;
|
|
struct {
|
|
asn1p_expr_t *(*expr_resolve)(asn1p_expr_t *, void *arg);
|
|
} *varg = rarg;
|
|
|
|
if(!value || value->type != ATV_REFERENCED) {
|
|
errno = ESRCH;
|
|
return NULL;
|
|
}
|
|
|
|
ref = value->value.reference;
|
|
tmpexpr = asn1p_expr_new(ref->_lineno);
|
|
tmpexpr->meta_type = AMT_TYPEREF;
|
|
tmpexpr->expr_type = A1TC_REFERENCE;
|
|
tmpexpr->reference = ref;
|
|
target = varg->expr_resolve(tmpexpr, rarg);
|
|
tmpexpr->reference = 0;
|
|
asn1p_expr_free(tmpexpr);
|
|
|
|
if(!target)
|
|
return NULL; /* errno's are compatible */
|
|
|
|
if(target->meta_type == AMT_VALUE) {
|
|
if(!target->value) {
|
|
fprintf(stderr,
|
|
"FATAL: Parameterization did not resolve "
|
|
"value reference at line %d\n", ref->_lineno);
|
|
asn1p_expr_free(target);
|
|
errno = EPERM;
|
|
return NULL;
|
|
}
|
|
cval = asn1p_value_clone(target->value);
|
|
} else if(target->meta_type == AMT_VALUESET) {
|
|
if(!target->constraints) {
|
|
fprintf(stderr,
|
|
"FATAL: Parameterization did not resolve "
|
|
"value set reference at line %d\n", ref->_lineno);
|
|
asn1p_expr_free(target);
|
|
errno = EPERM;
|
|
return NULL;
|
|
}
|
|
cval = asn1p_value_fromconstr(target->constraints, 1);
|
|
} else {
|
|
errno = EPERM;
|
|
cval = NULL;
|
|
}
|
|
|
|
asn1p_expr_free(target);
|
|
return cval;
|
|
}
|
|
|
|
/*
|
|
* Add expression as a member of another.
|
|
*/
|
|
void
|
|
asn1p_expr_add(asn1p_expr_t *to, asn1p_expr_t *what) {
|
|
TQ_ADD(&(to->members), what, next);
|
|
what->parent_expr = to;
|
|
}
|
|
|
|
|
|
/*
|
|
* Destruct the types collection structure.
|
|
*/
|
|
void
|
|
asn1p_expr_free(asn1p_expr_t *expr) {
|
|
if(expr) {
|
|
asn1p_expr_t *tm;
|
|
|
|
/* Remove all children */
|
|
while((tm = TQ_REMOVE(&(expr->members), next))) {
|
|
if(tm->parent_expr != expr)
|
|
printf("<%s:%p !-> %s:%p>\n",
|
|
tm->Identifier, tm->parent_expr,
|
|
expr->Identifier, expr);
|
|
assert(tm->parent_expr == expr);
|
|
asn1p_expr_free(tm);
|
|
}
|
|
|
|
if(expr->Identifier)
|
|
free(expr->Identifier);
|
|
if(expr->reference)
|
|
asn1p_ref_free(expr->reference);
|
|
if(expr->constraints)
|
|
asn1p_constraint_free(expr->constraints);
|
|
if(expr->combined_constraints)
|
|
asn1p_constraint_free(expr->combined_constraints);
|
|
if(expr->lhs_params)
|
|
asn1p_paramlist_free(expr->lhs_params);
|
|
if(expr->value)
|
|
asn1p_value_free(expr->value);
|
|
if(expr->marker.default_value)
|
|
asn1p_value_free(expr->marker.default_value);
|
|
if(expr->with_syntax)
|
|
asn1p_wsyntx_free(expr->with_syntax);
|
|
|
|
if(expr->data && expr->data_free)
|
|
expr->data_free(expr->data);
|
|
|
|
memset(expr, 0, sizeof(*expr));
|
|
free(expr);
|
|
}
|
|
}
|
|
|
|
|
|
char *asn1p_tag2string(struct asn1p_type_tag_s *tag, char *buf) {
|
|
static char buf_stat[TAG2STRING_BUFFER_SIZE];
|
|
char *start;
|
|
char *end;
|
|
|
|
if(!buf) buf = buf_stat;
|
|
start = buf;
|
|
end = buf + TAG2STRING_BUFFER_SIZE;
|
|
|
|
if(tag->tag_class == TC_NOCLASS) {
|
|
*buf = 0;
|
|
return buf;
|
|
}
|
|
|
|
strcpy(buf, "[");
|
|
switch(tag->tag_class) {
|
|
case TC_NOCLASS:
|
|
assert(tag->tag_class != TC_NOCLASS);
|
|
break;
|
|
case TC_UNIVERSAL: strcat(buf, "UNIVERSAL "); break;
|
|
case TC_PRIVATE: strcat(buf, "PRIVATE "); break;
|
|
case TC_APPLICATION: strcat(buf, "APPLICATION "); break;
|
|
case TC_CONTEXT_SPECIFIC:
|
|
break;
|
|
}
|
|
buf += snprintf(buf + strlen(buf), end - buf,
|
|
"%" PRIdASN "]", tag->tag_value);
|
|
assert((unsigned int)(buf - end) > sizeof(" IMPLICIT "));
|
|
|
|
switch(tag->tag_mode) {
|
|
case TM_DEFAULT: break;
|
|
case TM_IMPLICIT: strcat(buf, " IMPLICIT"); break;
|
|
case TM_EXPLICIT: strcat(buf, " EXPLICIT"); break;
|
|
}
|
|
|
|
return start;
|
|
}
|