Skip to content
Snippets Groups Projects
Commit b45e067b authored by Lev Walkin's avatar Lev Walkin
Browse files

constraint groking code

parent 9095adab
No related branches found
No related tags found
No related merge requests found
AM_CFLAGS = @ADD_CFLAGS@
AM_CPPFLAGS = -I${top_srcdir}/libasn1parser
AM_CPPFLAGS = \
-I$(top_srcdir)/libasn1parser \
-I$(top_srcdir)/libasn1cnst
noinst_LTLIBRARIES = libasn1fix.la
libasn1fix_la_LDFLAGS = -all-static
libasn1fix_la_SOURCES = \
asn1fix.c asn1fix.h \
asn1fix_internal.h \
asn1fix_misc.c asn1fix_misc.h \
asn1fix_value.c asn1fix_value.h \
asn1fix_compat.c asn1fix_compat.h \
asn1fix_constr.c asn1fix_constr.h \
asn1fix_cstring.c asn1fix_cstring.h \
asn1fix_retrieve.c asn1fix_retrieve.h \
asn1fix_bitstring.c asn1fix_bitstring.h \
asn1fix_integer.c asn1fix_integer.h \
asn1fix_dereft.c asn1fix_dereft.h \
asn1fix_derefv.c asn1fix_derefv.h \
asn1fix_export.c asn1fix_export.h \
asn1fix_param.c asn1fix_param.h \
asn1fix_class.c asn1fix_class.h \
asn1fix_tags.c asn1fix_tags.h \
asn1fix_enum.c asn1fix_enum.h
libasn1fix_la_LIBADD = ${top_builddir}/libasn1parser/libasn1parser.la
libasn1fix_la_SOURCES = \
asn1fix.c asn1fix.h \
asn1fix_internal.h \
asn1fix_misc.c asn1fix_misc.h \
asn1fix_value.c asn1fix_value.h \
asn1fix_compat.c asn1fix_compat.h \
asn1fix_constr.c asn1fix_constr.h \
asn1fix_cstring.c asn1fix_cstring.h \
asn1fix_retrieve.c asn1fix_retrieve.h \
asn1fix_bitstring.c asn1fix_bitstring.h \
asn1fix_constraint.c asn1fix_constraint.h \
asn1fix_integer.c asn1fix_integer.h \
asn1fix_crange.c asn1fix_crange.h \
asn1fix_dereft.c asn1fix_dereft.h \
asn1fix_derefv.c asn1fix_derefv.h \
asn1fix_export.c asn1fix_export.h \
asn1fix_param.c asn1fix_param.h \
asn1fix_class.c asn1fix_class.h \
asn1fix_tags.c asn1fix_tags.h \
asn1fix_enum.c asn1fix_enum.h \
asn1fix_constraint_compat.c
check_PROGRAMS = check_fixer
LDADD = ${noinst_LTLIBRARIES} ${libasn1fix_la_LIBADD}
DEPENDENCIES = ${LDADD}
check_fixer_LDADD = $(noinst_LTLIBRARIES) \
$(top_builddir)/libasn1cnst/libasn1cnst.la \
$(top_builddir)/libasn1parser/libasn1parser.la
check_fixer_DEPENDENCIES = $(check_fixer_LDADD)
TESTS_ENVIRONMENT= ./check_fixer
TESTS = ${top_srcdir}/tests/*.asn1
## TESTS = ${check_PROGRAMS} # This is an alternate form of testing
......@@ -50,21 +50,18 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libasn1fix_la_DEPENDENCIES = \
${top_builddir}/libasn1parser/libasn1parser.la
libasn1fix_la_LIBADD =
am_libasn1fix_la_OBJECTS = asn1fix.lo asn1fix_misc.lo asn1fix_value.lo \
asn1fix_compat.lo asn1fix_constr.lo asn1fix_cstring.lo \
asn1fix_retrieve.lo asn1fix_bitstring.lo asn1fix_integer.lo \
asn1fix_dereft.lo asn1fix_derefv.lo asn1fix_export.lo \
asn1fix_param.lo asn1fix_class.lo asn1fix_tags.lo \
asn1fix_enum.lo
asn1fix_retrieve.lo asn1fix_bitstring.lo asn1fix_constraint.lo \
asn1fix_integer.lo asn1fix_crange.lo asn1fix_dereft.lo \
asn1fix_derefv.lo asn1fix_export.lo asn1fix_param.lo \
asn1fix_class.lo asn1fix_tags.lo asn1fix_enum.lo \
asn1fix_constraint_compat.lo
libasn1fix_la_OBJECTS = $(am_libasn1fix_la_OBJECTS)
check_fixer_SOURCES = check_fixer.c
check_fixer_OBJECTS = check_fixer.$(OBJEXT)
check_fixer_LDADD = $(LDADD)
am__DEPENDENCIES_1 = libasn1fix.la
am__DEPENDENCIES_2 = ${top_builddir}/libasn1parser/libasn1parser.la
check_fixer_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
......@@ -73,6 +70,9 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_class.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_compat.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_constr.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_constraint.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_constraint_compat.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_crange.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_cstring.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_dereft.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1fix_derefv.Plo \
......@@ -209,31 +209,39 @@ target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
AM_CFLAGS = @ADD_CFLAGS@
AM_CPPFLAGS = -I${top_srcdir}/libasn1parser
AM_CPPFLAGS = \
-I$(top_srcdir)/libasn1parser \
-I$(top_srcdir)/libasn1cnst
noinst_LTLIBRARIES = libasn1fix.la
libasn1fix_la_LDFLAGS = -all-static
libasn1fix_la_SOURCES = \
asn1fix.c asn1fix.h \
asn1fix_internal.h \
asn1fix_misc.c asn1fix_misc.h \
asn1fix_value.c asn1fix_value.h \
asn1fix_compat.c asn1fix_compat.h \
asn1fix_constr.c asn1fix_constr.h \
asn1fix_cstring.c asn1fix_cstring.h \
asn1fix_retrieve.c asn1fix_retrieve.h \
asn1fix_bitstring.c asn1fix_bitstring.h \
asn1fix_integer.c asn1fix_integer.h \
asn1fix_dereft.c asn1fix_dereft.h \
asn1fix_derefv.c asn1fix_derefv.h \
asn1fix_export.c asn1fix_export.h \
asn1fix_param.c asn1fix_param.h \
asn1fix_class.c asn1fix_class.h \
asn1fix_tags.c asn1fix_tags.h \
asn1fix_enum.c asn1fix_enum.h
libasn1fix_la_LIBADD = ${top_builddir}/libasn1parser/libasn1parser.la
LDADD = ${noinst_LTLIBRARIES} ${libasn1fix_la_LIBADD}
DEPENDENCIES = ${LDADD}
asn1fix.c asn1fix.h \
asn1fix_internal.h \
asn1fix_misc.c asn1fix_misc.h \
asn1fix_value.c asn1fix_value.h \
asn1fix_compat.c asn1fix_compat.h \
asn1fix_constr.c asn1fix_constr.h \
asn1fix_cstring.c asn1fix_cstring.h \
asn1fix_retrieve.c asn1fix_retrieve.h \
asn1fix_bitstring.c asn1fix_bitstring.h \
asn1fix_constraint.c asn1fix_constraint.h \
asn1fix_integer.c asn1fix_integer.h \
asn1fix_crange.c asn1fix_crange.h \
asn1fix_dereft.c asn1fix_dereft.h \
asn1fix_derefv.c asn1fix_derefv.h \
asn1fix_export.c asn1fix_export.h \
asn1fix_param.c asn1fix_param.h \
asn1fix_class.c asn1fix_class.h \
asn1fix_tags.c asn1fix_tags.h \
asn1fix_enum.c asn1fix_enum.h \
asn1fix_constraint_compat.c
check_fixer_LDADD = $(noinst_LTLIBRARIES) \
$(top_builddir)/libasn1cnst/libasn1cnst.la \
$(top_builddir)/libasn1parser/libasn1parser.la
check_fixer_DEPENDENCIES = $(check_fixer_LDADD)
TESTS_ENVIRONMENT = ./check_fixer
TESTS = ${top_srcdir}/tests/*.asn1
all: all-am
......@@ -302,6 +310,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_class.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_compat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_constr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_constraint.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_constraint_compat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_crange.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_cstring.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_dereft.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1fix_derefv.Plo@am__quote@
......
......@@ -17,6 +17,7 @@ static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */
static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */
static int asn1f_fix_constraints(arg_t *arg); /* For subtype constraints */
arg_t a1f_replace_me_with_proper_interface_arg;
/*
* Scan every module defined here in search for inconsistences.
......@@ -53,6 +54,8 @@ asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
flags &= ~A1F_DEBUG;
}
a1f_replace_me_with_proper_interface_arg = arg;
/*
* Check that we haven't missed an unknown flag.
*/
......@@ -74,6 +77,8 @@ asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
if(ret == 1) warnings++;
}
memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
/*
* Compute a return value.
*/
......@@ -88,8 +93,7 @@ asn1f_fix_module(arg_t *arg) {
asn1p_expr_t *expr;
int rvalue = 0;
switch((arg->mod->module_flags
& (MSF_EXPLICIT_TAGS | MSF_IMPLICIT_TAGS | MSF_AUTOMATIC_TAGS))) {
switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
case MSF_NOFLAGS:
case MSF_EXPLICIT_TAGS:
case MSF_IMPLICIT_TAGS:
......@@ -101,6 +105,24 @@ asn1f_fix_module(arg_t *arg) {
RET2RVAL(-1, rvalue);
}
switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
case MSF_NOFLAGS:
//arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
break;
case MSF_unk_INSTRUCTIONS:
WARNING("Module %s defined with unrecognized "
"encoding reference", arg->mod->Identifier);
RET2RVAL(1, rvalue);
/* Fall through */
case MSF_TAG_INSTRUCTIONS:
case MSF_XER_INSTRUCTIONS:
break;
default:
FATAL("Module %s defined with ambiguous encoding reference",
arg->mod->Identifier);
RET2RVAL(-1, rvalue);
}
/*
* Do various non-recursive transformations.
* Order is not important.
......@@ -249,86 +271,34 @@ asn1f_fix_constructed(arg_t *arg) {
}
static int
_constraint_value_resolve(arg_t *arg, asn1p_value_t **value) {
asn1p_expr_t expr;
asn1p_expr_t *tmp_expr;
asn1p_module_t *tmp_mod;
asn1p_module_t *mod_r = NULL;
asn1f_fix_constraints(arg_t *arg) {
asn1p_expr_t *top_parent;
int rvalue = 0;
int ret;
tmp_expr = asn1f_lookup_symbol(arg, (*value)->value.reference, &mod_r);
if(tmp_expr == NULL) {
FATAL("Cannot find symbol %s "
"used in %s subtype constraint at line %d",
asn1f_printable_reference((*value)->value.reference),
arg->expr->Identifier, arg->expr->_lineno);
assert((*value)->type == ATV_REFERENCED);
return -1;
}
memset(&expr, 0, sizeof(expr));
expr.meta_type = tmp_expr->meta_type;
expr.expr_type = tmp_expr->expr_type;
expr.Identifier = tmp_expr->Identifier;
expr.value = *value;
tmp_expr = arg->expr;
tmp_mod = arg->mod;
arg->expr = &expr;
arg->mod = mod_r;
ret = asn1f_fix_dereference_values(arg);
ret = asn1constraint_resolve(arg, arg->expr->constraints);
RET2RVAL(ret, rvalue);
arg->expr = tmp_expr;
arg->mod = tmp_mod;
assert(expr.value);
*value = expr.value;
return rvalue;
}
static int
_resolve_constraints(arg_t *arg, asn1p_constraint_t *ct) {
int rvalue = 0;
int ret;
int el;
/* Don't touch information object classes */
if(ct->type == ACT_CT_WCOMP
|| ct->type == ACT_CT_WCOMPS
|| ct->type == ACT_CA_CRC)
return 0;
if(ct->value && ct->value->type == ATV_REFERENCED) {
ret = _constraint_value_resolve(arg, &ct->value);
RET2RVAL(ret, rvalue);
}
if(ct->range_start && ct->range_start->type == ATV_REFERENCED) {
ret = _constraint_value_resolve(arg, &ct->range_start);
RET2RVAL(ret, rvalue);
}
if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) {
ret = _constraint_value_resolve(arg, &ct->range_stop);
RET2RVAL(ret, rvalue);
}
for(el = 0; el < ct->el_count; el++) {
ret = _resolve_constraints(arg, ct->elements[el]);
RET2RVAL(ret, rvalue);
}
return rvalue;
}
static int
asn1f_fix_constraints(arg_t *arg) {
int rvalue = 0;
int ret;
ret = asn1constraint_pullup(arg);
RET2RVAL(ret, rvalue);
if(arg->expr->constraints) {
ret = _resolve_constraints(arg, arg->expr->constraints);
RET2RVAL(ret, rvalue);
top_parent = asn1f_find_terminal_type(arg, arg->expr, NULL);
if(top_parent) {
static enum asn1p_constraint_type_e test_types[] = {
ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
unsigned int i;
for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
asn1cnst_range_t *range;
range = asn1constraint_compute_PER_range(
top_parent->expr_type,
arg->expr->combined_constraints,
test_types[i], 0, 0);
if(!range && errno == EPERM)
return -1;
asn1constraint_range_free(range);
}
}
return rvalue;
}
......
......@@ -12,7 +12,7 @@
*/
enum asn1f_flags {
A1F_NOFLAGS,
A1F_DEBUG, /* Print debugging output using (_is_fatal = -1) */
A1F_DEBUG = 0x01, /* Print debugging output */
};
/*
......
#include <asn1fix_internal.h>
#include <asn1fix_constraint.h>
#include <asn1fix_crange.h>
static void _remove_exceptions(arg_t *arg, asn1p_constraint_t *ct);
static int _constraint_value_resolve(arg_t *arg, asn1p_value_t **value);
int
asn1constraint_pullup(arg_t *arg) {
asn1p_expr_t *expr = arg->expr;
asn1p_constraint_t *ct_parent;
asn1p_constraint_t *ct_expr;
int ret;
if(expr->combined_constraints)
return 0; /* Operation already performed earlier */
switch(expr->meta_type) {
case AMT_TYPE:
case AMT_TYPEREF:
break;
default:
return 0; /* Nothing to do */
}
if(expr->expr_type == A1TC_REFERENCE) {
asn1p_ref_t *ref = expr->reference;
asn1p_module_t *mod_rw = arg->mod;
asn1p_expr_t *parent_expr;
assert(ref);
parent_expr = asn1f_lookup_symbol(arg, ref, &mod_rw);
if(!parent_expr) {
if(errno != EEXIST) {
DEBUG("\tWhile fetching parent constraints: "
"type \"%s\" not found: %s",
asn1f_printable_reference(ref),
strerror(errno));
return -1;
} else {
/*
* -fknown-extern-type is given.
* Assume there are no constraints there.
*/
WARNING("External type \"%s\": "
"assuming no constraints",
asn1f_printable_reference(ref));
ct_parent = 0;
}
} else {
arg->expr = parent_expr;
ret = asn1constraint_pullup(arg);
arg->expr = expr;
if(ret) return ret;
ct_parent = parent_expr->combined_constraints;
}
} else {
ct_parent = 0;
}
ct_expr = expr->constraints;
if(!ct_parent && !ct_expr)
return 0; /* No constraints to consider */
if(ct_parent) {
ct_parent = asn1p_constraint_clone(ct_parent);
assert(ct_parent);
}
/*
* If the current type does not have constraints, it inherits
* the constraints of a parent.
*/
if(ct_parent && !ct_expr) {
expr->combined_constraints = ct_parent;
return 0;
}
ct_expr = asn1p_constraint_clone(ct_expr);
assert(ct_expr);
/*
* Now we have a set of current expression's constraints,
* and an optional set of the parent expression's constraints.
*/
if(ct_parent) {
/*
* If we have a parent, remove all the extensions (46.4).
*/
_remove_exceptions(arg, ct_parent);
expr->combined_constraints = ct_parent;
if(ct_expr->type == ACT_CA_SET) {
int i;
for(i = 0; i < ct_expr->el_count; i++) {
if(asn1p_constraint_insert(
expr->combined_constraints,
ct_expr->elements[i])) {
expr->combined_constraints = 0;
asn1p_constraint_free(ct_expr);
asn1p_constraint_free(ct_parent);
return -1;
} else {
ct_expr->elements[i] = 0;
}
}
asn1p_constraint_free(ct_expr);
} else {
asn1p_constraint_insert(expr->combined_constraints,
ct_expr);
}
} else {
expr->combined_constraints = ct_expr;
}
return 0;
}
int
asn1constraint_resolve(arg_t *arg, asn1p_constraint_t *ct) {
asn1p_expr_t *top_parent;
int rvalue = 0;
int ret;
int el;
if(!ct) return 0;
/* Don't touch information object classes */
switch(ct->type) {
case ACT_CT_WCOMP:
case ACT_CT_WCOMPS:
case ACT_CA_CRC:
return 0;
default:
break;
}
top_parent = asn1f_find_terminal_type(arg, arg->expr, 0);
if(top_parent) {
ret = asn1constraint_compatible(top_parent->expr_type,
ct->type);
switch(ret) {
case -1: /* If unknown, assume OK. */
case 1:
break;
case 0:
default:
FATAL("%s at line %d: "
"Constraint type %s is not applicable to %s",
arg->expr->Identifier, ct->_lineno,
asn1p_constraint_type2str(ct->type),
ASN_EXPR_TYPE2STR(top_parent->expr_type)
);
rvalue = -1;
break;
}
} else {
WARNING("%s at line %d: "
"Constraints ignored: Unresolved parent type",
arg->expr->Identifier, arg->expr->_lineno);
}
if(ct->value && ct->value->type == ATV_REFERENCED) {
ret = _constraint_value_resolve(arg, &ct->value);
RET2RVAL(ret, rvalue);
}
if(ct->range_start && ct->range_start->type == ATV_REFERENCED) {
ret = _constraint_value_resolve(arg, &ct->range_start);
RET2RVAL(ret, rvalue);
}
if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) {
ret = _constraint_value_resolve(arg, &ct->range_stop);
RET2RVAL(ret, rvalue);
}
for(el = 0; el < ct->el_count; el++) {
ret = asn1constraint_resolve(arg, ct->elements[el]);
RET2RVAL(ret, rvalue);
}
return rvalue;
}
static void
_remove_exceptions(arg_t *arg, asn1p_constraint_t *ct) {
int i;
for(i = 0; i < ct->el_count; i++) {
if(ct->elements[i]->type == ACT_EL_EXT)
break;
_remove_exceptions(arg, ct->elements[i]);
}
/* Remove the elements at and after the extensibility mark */
for(; i < ct->el_count; ct->el_count--) {
asn1p_constraint_t *rm;
rm = ct->elements[ct->el_count-1];
asn1p_constraint_free(rm);
}
if(i < ct->el_size)
ct->elements[i] = 0;
}
static int
_constraint_value_resolve(arg_t *arg, asn1p_value_t **value) {
asn1p_expr_t static_expr;
asn1p_expr_t *tmp_expr;
asn1p_module_t *mod_rw = arg->mod;
arg_t tmp_arg;
int rvalue = 0;
int ret;
tmp_expr = asn1f_lookup_symbol(arg, (*value)->value.reference, &mod_rw);
if(tmp_expr == NULL) {
FATAL("Cannot find symbol %s "
"used in %s subtype constraint at line %d",
asn1f_printable_reference((*value)->value.reference),
arg->expr->Identifier, arg->expr->_lineno);
assert((*value)->type == ATV_REFERENCED);
return -1;
}
static_expr = *tmp_expr;
static_expr.value = *value;
tmp_arg = *arg;
tmp_arg.mod = mod_rw;
tmp_arg.expr = &static_expr;
ret = asn1f_fix_dereference_values(&tmp_arg);
RET2RVAL(ret, rvalue);
assert(static_expr.value);
*value = static_expr.value;
return rvalue;
}
#ifndef _ASN1FIX_CONSTRAINT_H_
#define _ASN1FIX_CONSTRAINT_H_
/*
* Resolve referenced values inside constraints.
*/
int asn1constraint_resolve(arg_t *arg, asn1p_constraint_t *ct);
/*
* Collect all subtype constraints from all parents of this type and
* the type itself, forming a full constraint structure.
* Honors the constraints extensibility rules (46.8)
* and does other useful transformations.
*/
int asn1constraint_pullup(arg_t *arg);
#endif /* _ASN1FIX_CONSTRAINT_H_ */
#include <asn1fix_internal.h>
#include <asn1fix_crange.h>
/*
* Check that a specific constraint is compatible
* with the given expression type.
*/
int
asn1constraint_compatible(asn1p_expr_type_e expr_type,
enum asn1p_constraint_type_e constr_type) {
/*
* X.680-0207, Table 9.
*/
switch(constr_type) {
case ACT_INVALID:
return 0;
case ACT_EL_VALUE:
return 1;
case ACT_EL_RANGE:
case ACT_EL_LLRANGE:
case ACT_EL_RLRANGE:
case ACT_EL_ULRANGE:
switch(expr_type) {
case ASN_BASIC_ENUMERATED:
case ASN_BASIC_BOOLEAN:
/*
* The ValueRange constraint is not formally
* applicable to the above types. However, we
* support it just fine.
*/
/* Fall through */
case ASN_BASIC_INTEGER:
case ASN_BASIC_REAL:
return 1;
default:
if(expr_type & ASN_STRING_MASK)
return 1;
}
return 0;
case ACT_EL_EXT:
return -1;
case ACT_CT_FROM:
if(expr_type & ASN_STRING_MASK)
return 1;
return 0;
case ACT_CT_SIZE:
switch(expr_type) {
case ASN_BASIC_BIT_STRING:
case ASN_BASIC_OCTET_STRING:
case ASN_BASIC_CHARACTER_STRING:
case ASN_CONSTR_SEQUENCE_OF:
case ASN_CONSTR_SET_OF:
return 1;
default:
if(expr_type & ASN_STRING_MASK)
return 1;
}
return 0;
case ACT_CT_WCOMP:
case ACT_CT_WCOMPS:
switch(expr_type) {
case A1TC_INSTANCE:
case ASN_BASIC_EXTERNAL:
case ASN_BASIC_EMBEDDED_PDV:
case ASN_BASIC_REAL:
case ASN_BASIC_CHARACTER_STRING:
case ASN_CONSTR_CHOICE:
case ASN_CONSTR_SEQUENCE:
case ASN_CONSTR_SEQUENCE_OF:
case ASN_CONSTR_SET:
case ASN_CONSTR_SET_OF:
return 1;
default: break;
}
return 0;
case ACT_CA_SET:
case ACT_CA_CRC:
case ACT_CA_CSV:
case ACT_CA_UNI:
case ACT_CA_INT:
case ACT_CA_EXC:
return 1;
}
return -1;
}
#define DECL(foo, val1, val2) \
static asn1cnst_range_t range_ ## foo = { \
{ ARE_VALUE, 0, val1 }, \
{ ARE_VALUE, 0, val2 }, \
0, 0, 0, 0, 0, 0 };
asn1cnst_range_t *
asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) {
DECL(uint7, 0x00, 0x7f);
DECL(uint8, 0x00, 0xff);
DECL(Space, 0x20, 0x20);
DECL(ApostropheAndParens, 0x27, 0x29);
DECL(PlusTillColon, 0x2b, 0x3a);
DECL(Equal, 0x3d, 0x3d);
DECL(QuestionMark, 0x3f, 0x3f);
DECL(Digits, 0x30, 0x39);
DECL(AlphaCap, 0x41, 0x5a);
DECL(AlphaLow, 0x61, 0x7a);
DECL(PlusCommaMinusDot, 0x2b, 0x2e);
DECL(Plus, 0x2b, 0x2b);
DECL(MinusDot, 0x2d, 0x2e);
DECL(Z, 0x5a, 0x5a);
static asn1cnst_range_t *range_NumericString_array[] = {
&range_Space, &range_Digits };
static asn1cnst_range_t *range_PrintableString_array[] = {
&range_Space,
&range_ApostropheAndParens,
&range_PlusTillColon,
&range_Equal,
&range_QuestionMark,
&range_AlphaCap,
&range_AlphaLow
};
static asn1cnst_range_t *range_UTCTime_array[] = {
&range_Plus, &range_MinusDot, &range_Digits, &range_Z };
static asn1cnst_range_t *range_GeneralizedTime_array[] = {
&range_PlusCommaMinusDot, &range_Digits, &range_Z };
static asn1cnst_range_t range_NumericString = {
{ ARE_VALUE, 0, 0x20 },
{ ARE_VALUE, 0, 0x39 },
range_NumericString_array,
sizeof(range_NumericString_array)
/sizeof(range_NumericString_array[0]),
0, 0, 0, 0 };
static asn1cnst_range_t range_PrintableString = {
{ ARE_VALUE, 0, 0x20 },
{ ARE_VALUE, 0, 0x7a },
range_PrintableString_array,
sizeof(range_PrintableString_array)
/sizeof(range_PrintableString_array[0]),
0, 0, 0, 0 };
static asn1cnst_range_t range_VisibleString = {
{ ARE_VALUE, 0, 0x20 },
{ ARE_VALUE, 0, 0x7e },
0, 0, 0, 0, 0, 0 };
static asn1cnst_range_t range_UTCTime = {
{ ARE_VALUE, 0, 0x2b },
{ ARE_VALUE, 0, 0x5a },
range_UTCTime_array,
sizeof(range_UTCTime_array)
/sizeof(range_UTCTime_array[0]),
0, 0, 0, 0 };
static asn1cnst_range_t range_GeneralizedTime = {
{ ARE_VALUE, 0, 0x2b },
{ ARE_VALUE, 0, 0x5a },
range_GeneralizedTime_array,
sizeof(range_GeneralizedTime_array)
/sizeof(range_GeneralizedTime_array[0]),
0, 0, 0, 0 };
switch(expr_type) {
case ASN_STRING_NumericString:
return &range_NumericString;
case ASN_STRING_PrintableString:
return &range_PrintableString;
case ASN_STRING_VisibleString:
return &range_VisibleString;
case ASN_STRING_IA5String:
return &range_uint7;
case ASN_BASIC_OCTET_STRING:
return &range_uint8;
case ASN_BASIC_UTCTime:
return &range_UTCTime;
case ASN_BASIC_GeneralizedTime:
return &range_GeneralizedTime;
default:
break;
}
return NULL;
}
#include <asn1fix_internal.h>
#include <asn1fix_constraint.h>
#include <asn1fix_crange.h>
#undef FATAL
#define FATAL(fmt, args...) do { \
fprintf(stderr, "FATAL: "); \
fprintf(stderr, fmt, ##args); \
fprintf(stderr, "\n"); \
} while(0)
void
asn1constraint_range_free(asn1cnst_range_t *cr) {
if(cr) {
int i;
if(cr->elements) {
for(i = 0; i < cr->el_count; i++)
asn1constraint_range_free(cr->elements[i]);
free(cr->elements);
}
free(cr);
}
}
#define _range_free(foo) asn1constraint_range_free(foo)
static asn1cnst_range_t *_range_new() {
asn1cnst_range_t *r;
r = calloc(1, sizeof(*r));
if(r) {
r->left.type = ARE_MIN;
r->right.type = ARE_MAX;
}
return r;
}
static void _range_remove_element(asn1cnst_range_t *range, int idx) {
assert(idx >= 0 && idx < range->el_count);
assert(!range->elements[idx]->elements);
_range_free(range->elements[idx]);
memmove(&range->elements[idx],
&range->elements[idx + 1],
(range->el_count - idx - 1)
* sizeof(range->elements[0])
);
range->el_count--;
range->elements[range->el_count] = 0; /* JIC */
if(range->el_count == 0) {
range->el_size = 0;
free(range->elements);
range->elements = 0;
}
}
static int _range_insert(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
assert(!cr->elements);
if(into->el_count == into->el_size) {
void *p;
int n = into->el_size?(into->el_size << 1):4;
p = realloc(into->elements, n * sizeof(into->elements[0]));
if(p) {
into->el_size = n;
into->elements = p;
} else {
assert(p);
return -1;
}
}
into->elements[into->el_count++] = cr;
return 0;
}
static asn1cnst_range_t *_range_clone(const asn1cnst_range_t *range) {
asn1cnst_range_t *clone;
int i;
clone = _range_new();
if(!clone) return NULL;
*clone = *range;
clone->elements = 0;
clone->el_count = 0;
clone->el_size = 0;
for(i = 0; i < range->el_count; i++) {
asn1cnst_range_t *r = _range_clone(range->elements[i]);
if(!r || _range_insert(clone, r)) {
_range_free(clone);
_range_free(r);
return NULL;
}
}
return clone;
}
static int
_edge_compare(const asn1cnst_edge_t *el, const asn1cnst_edge_t *er) {
switch(el->type) {
case ARE_MIN:
switch(er->type) {
case ARE_MIN: return 0;
case ARE_MAX: return -1;
case ARE_VALUE: return -1;
}
break;
case ARE_MAX:
switch(er->type) {
case ARE_MIN: return 1;
case ARE_MAX: return 0;
case ARE_VALUE: return 1;
}
break;
case ARE_VALUE:
switch(er->type) {
case ARE_MIN: return 1;
case ARE_MAX: return -1;
case ARE_VALUE:
if(el->value < er->value)
return -1;
if(el->value > er->value)
return 1;
return 0;
}
break;
}
return 0;
}
static int
_range_compare(const void *a, const void *b) {
const asn1cnst_range_t *ra = *(const asn1cnst_range_t * const *)a;
const asn1cnst_range_t *rb = *(const asn1cnst_range_t * const *)b;
int ret;
ret = _edge_compare(&ra->left, &rb->left);
if(!ret) {
ret = _edge_compare(&ra->right, &rb->right);
}
return ret;
}
static char *
_edge_value(const asn1cnst_edge_t *edge) {
static char buf[128];
*buf = '\0';
switch(edge->type) {
case ARE_MIN: strcpy(buf, "MIN"); break;
case ARE_MAX: strcpy(buf, "MAX"); break;
case ARE_VALUE:
snprintf(buf, sizeof(buf), "%lld", (long long)edge->value);
}
return buf;
}
static void
_range_print(const asn1cnst_range_t *range) {
if(_edge_compare(&range->left, &range->right)) {
printf("(%s.", _edge_value(&range->left));
printf(".%s)", _edge_value(&range->right));
} else {
printf("(%s)", _edge_value(&range->left));
}
if(range->el_count) {
int i;
printf("-=>");
for(i = 0; i < range->el_count; i++)
_range_print(range->elements[i]);
}
}
static int
_edge_is_within(const asn1cnst_range_t *range, const asn1cnst_edge_t *edge) {
int i;
for(i = -1; i < range->el_count; i++) {
const asn1cnst_range_t *r;
if(i == -1) {
if(range->el_count) continue;
r = range;
} else {
r = range->elements[i];
}
if(_edge_compare(&r->left, edge) <= 0
&& _edge_compare(&r->right, edge) >= 0)
return 1;
}
return 0;
}
static int
_check_edges_within(const asn1cnst_range_t *range, const asn1cnst_range_t *r) {
if(!_edge_is_within(range, &r->left)) {
FATAL("Constraint value %s at line %d "
"is not within "
"a parent constraint range",
_edge_value(&r->left),
r->left.lineno
);
return -1;
}
if(!_edge_is_within(range, &r->right)) {
FATAL("Constraint value %s at line %d "
"is not within "
"a parent constraint range",
_edge_value(&r->right),
r->right.lineno
);
return -1;
}
return 0;
}
static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
asn1cnst_range_t *r;
int prev_count = into->el_count;
int i;
/*
* Add the element OR all its children "into".
*/
for(i = -1; i < cr->el_count; i++) {
if(i == -1) {
if(cr->el_count) continue;
r = cr;
} else {
r = cr->elements[i];
}
if(_range_insert(into, r)) {
into->el_count = prev_count; /* Undo */
return -1;
}
}
if(cr->el_count) {
cr->el_count = 0;
_range_free(cr);
} else {
/* This range is linked into "into". */
}
return 0;
}
static int _range_fill(asn1p_value_t *val, const asn1cnst_range_t *minmax, asn1cnst_edge_t *edge, asn1cnst_range_t *range, enum asn1p_constraint_type_e type, int lineno) {
unsigned char *p, *pend;
edge->lineno = lineno;
switch(val->type) {
case ATV_INTEGER:
if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
FATAL("Integer %lld value invalid "
"for %s constraint at line %d",
(long long)val->value.v_integer,
asn1p_constraint_type2str(type), lineno);
return -1;
}
edge->type = ARE_VALUE;
edge->value = val->value.v_integer;
return 0;
case ATV_MIN:
if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
FATAL("MIN invalid for %s constraint at line %d",
asn1p_constraint_type2str(type), lineno);
return -1;
}
edge->type = ARE_MIN;
if(minmax) *edge = minmax->left;
edge->lineno = lineno; /* Restore lineno */
return 0;
case ATV_MAX:
if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
FATAL("MAX invalid for %s constraint at line %d",
asn1p_constraint_type2str(type), lineno);
return -1;
}
edge->type = ARE_MAX;
if(minmax) *edge = minmax->right;
edge->lineno = lineno; /* Restore lineno */
return 0;
case ATV_FALSE:
case ATV_TRUE:
if(type != ACT_EL_RANGE) {
FATAL("%s is invalid for %s constraint at line %d",
val->type==ATV_TRUE?"TRUE":"FALSE",
asn1p_constraint_type2str(type),
lineno);
return -1;
}
edge->type = ARE_VALUE;
edge->value = (val->type==ATV_TRUE);
return 0;
case ATV_STRING:
if(type != ACT_CT_FROM)
return 0;
break;
default:
FATAL("Unrecognized constraint element at line %d",
lineno);
return -1;
}
assert(val->type == ATV_STRING);
p = val->value.string.buf;
pend = p + val->value.string.size;
if(p == pend) return 0;
edge->type = ARE_VALUE;
if(val->value.string.size == 1) {
edge->value = *p;
} else {
/*
* Else this is a set:
* (FROM("abcdef"))
* However, (FROM("abc".."def")) is forbidden.
* See also 47.4.4.
*/
asn1_integer_t vmin, vmax;
vmin = vmax = *p;
for(; p < pend; p++) {
asn1cnst_range_t *nr = _range_new();
int ret;
assert(nr);
if(*p < vmin) vmin = *p;
if(*p > vmax) vmax = *p;
ret = _range_insert(range, nr);
assert(ret == 0);
nr->left.type = ARE_VALUE;
nr->left.value = *p;
nr->left.lineno = lineno;
nr->right = nr->left;
}
edge->value = (edge == &range->right) ? vmin : vmax;
}
return 0;
}
/*
* Check if ranges contain common elements.
*/
static int
_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
int lr, rl;
const asn1cnst_edge_t *ra_l = &ra->left;
const asn1cnst_edge_t *ra_r = &ra->right;
const asn1cnst_edge_t *rb_l = &rb->left;
const asn1cnst_edge_t *rb_r = &rb->right;
assert(_edge_compare(ra_l, ra_r) <= 0);
assert(_edge_compare(rb_l, rb_r) <= 0);
lr = _edge_compare(ra_l, rb_r);
rl = _edge_compare(ra_r, rb_l);
/*
* L: |---|
* R: |---|
*/
if(lr > 0) return 0;
/*
* L: |---|
* R: |---|
*/
if(rl < 0) return 0;
return 1;
}
/*
* (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
*/
static asn1cnst_range_t *
_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
asn1cnst_range_t *range, *nr;
int ll, rr;
assert(ra);
assert(rb);
assert(!ra->el_count);
assert(!rb->el_count);
if(!_range_overlap(ra, rb)) {
errno = 0;
return 0;
}
ll = _edge_compare(&ra->left, &rb->left);
rr = _edge_compare(&ra->right, &rb->right);
/*
* L: |---|
* R: |-------|
*/
if(ll >= 0 && rr <= 0) {
errno = 0;
return 0;
}
range = _range_new();
assert(range);
nr = _range_new();
assert(nr);
/*
* L: |---...
* R: |--..
*/
if(ll < 0) {
nr->left = ra->left;
nr->right = rb->left;
if(nr->right.type == ARE_VALUE)
nr->right.value--;
_range_insert(range, nr);
nr = _range_new();
assert(nr);
}
/*
* L: ...---|
* R: ..--|
*/
if(rr > 0) {
nr->left = rb->right;
nr->right = ra->right;
if(nr->left.type == ARE_VALUE)
nr->left.value++;
_range_insert(range, nr);
nr = _range_new();
assert(nr);
}
/*
* L: |---|
* R: |-----|
*/
nr->left = ra->left;
nr->right = ra->right;
if(_edge_compare(&ra->left, &rb->left) < 0)
nr->left = rb->left;
if(_edge_compare(&ra->right, &rb->right) > 0)
nr->right = rb->right;
_range_insert(range, nr);
return range;
}
static int
_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check) {
int ret;
int i, j;
if(with->empty_constraint || range->empty_constraint) {
range->empty_constraint = 1; /* Propagate error */
return 0;
}
/*
* This is an AND operation.
*/
/* If this is the only element, insert it into itself as a child */
if(range->el_count == 0) {
asn1cnst_range_t *r = _range_new();
r->left = range->left;
r->right = range->right;
_range_insert(range, r);
assert(range->el_count == 1);
}
/*
* Make sure we're dealing with sane data.
* G.4.2.3
*/
if(strict_edge_check) {
for(j = -1; j < with->el_count; j++) {
if(j == -1) {
if(with->el_count) continue;
if(_check_edges_within(range, with))
return -1;
} else {
if(_check_edges_within(range,
with->elements[j]))
return -1;
}
}
}
/*
* Split range in pieces.
*/
for(i = 0; i < range->el_count; i++) {
for(j = -1; j < with->el_count; j++) {
const asn1cnst_range_t *wel;
asn1cnst_range_t *r;
if(j == -1) {
if(with->el_count) continue;
wel = with;
} else {
wel = with->elements[j];
}
r = _range_split(range->elements[i], wel);
if(r) {
int ec;
/* Substitute the current element with a split */
_range_remove_element(range, i);
assert(r->el_count);
for(ec = 0; ec < r->el_count; ec++) {
ret = _range_insert(range, r->elements[ec]);
assert(ret == 0);
}
r->el_count = 0;
_range_free(r);
i--;
break; /* Try again from this point */
}
}
}
assert(range->el_count);
/*
* Remove pieces which aren't AND-compatible "with" range.
*/
for(i = 0; i < range->el_count; i++) {
for(j = -1; j < with->el_count; j++) {
const asn1cnst_range_t *wel;
if(j == -1) {
if(with->el_count) continue;
wel = with;
} else {
wel = with->elements[j];
}
if(_range_overlap(range->elements[i], wel))
break;
}
if(j == with->el_count) {
_range_remove_element(range, i);
i--;
}
}
if(range->el_count == 0)
range->empty_constraint = 1;
return 0;
}
static int
_range_union(asn1cnst_range_t *range) {
int i;
qsort(range->elements, range->el_count, sizeof(range->elements[0]),
_range_compare);
/*
* The range is sorted by the start values.
*/
for(i = 1; i < range->el_count; i++) {
asn1cnst_range_t *ra = range->elements[i - 1];
asn1cnst_range_t *rb = range->elements[i];
if(_range_overlap(ra, rb)) {
if(_edge_compare(&ra->left, &rb->left) < 0)
rb->left = ra->left;
if(_edge_compare(&ra->right, &rb->right) > 0)
rb->right = ra->right;
} else {
/*
* Still, range may be joined: (1..4)(5..10).
* This logic is valid only for whole numbers
* (i.e., not REAL type, but REAL constraints
* are not PER-visible (X.691, 9.3.12).
*/
if(ra->right.type == ARE_VALUE
&& rb->left.type == ARE_VALUE
&& (rb->left.value - ra->right.value) == 1) {
/* (1..10) */
rb->left = ra->left;
} else {
continue;
}
}
/*
* Squeeze the array by removing the ra.
*/
_range_remove_element(range, i - 1);
i--; /* Retry from the current point */
}
return 0;
}
static int
_range_canonicalize(asn1cnst_range_t *range) {
if(range->el_count == 0) {
/*
* Switch left and right edges, make them sorted.
* It might be a mild warning though.
*/
if(_edge_compare(&range->left, &range->right) > 0) {
asn1cnst_edge_t tmp = range->left;
range->left = range->right;
range->right = tmp;
}
if(range->elements) {
free(range->elements);
range->elements = 0;
}
range->el_size = 0;
return 0;
}
/*
* Remove duplicates and overlaps by merging them in.
*/
_range_union(range);
/* Refine the left edge of a parent */
range->left = range->elements[0]->left;
/* Refine the right edge of a parent */
range->right = range->elements[range->el_count - 1]->right;
/* Remove the child, if it's a single one */
if(range->el_count == 1) {
_range_remove_element(range, 0);
}
return 0;
}
asn1cnst_range_t *
asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e type, const asn1cnst_range_t *minmax, int *exmet) {
asn1cnst_range_t *range;
asn1cnst_range_t *tmp;
asn1p_value_t *vmin;
asn1p_value_t *vmax;
int expectation_met;
int ret;
int i;
if(!exmet) {
exmet = &expectation_met;
*exmet = 0;
}
/*
* Check if the requested constraint is compatible with expression type.
*/
if(asn1constraint_compatible(expr_type, type) != 1) {
errno = EINVAL;
return 0;
}
/* Check arguments' validity. */
switch(type) {
case ACT_EL_RANGE:
if(exmet == &expectation_met)
*exmet = 1;
break;
case ACT_CT_FROM:
if(!minmax) {
minmax = asn1constraint_default_alphabet(expr_type);
if(minmax) {
break;
}
}
/* Fall through */
case ACT_CT_SIZE:
if(!minmax) {
static asn1cnst_range_t mm;
mm.left.type = ARE_VALUE;
mm.left.value = 0;
mm.right.type = ARE_MAX;
minmax = &mm;
}
break;
default:
errno = EINVAL;
return 0;
}
if(minmax) {
range = _range_clone(minmax);
} else {
range = _range_new();
}
if(!ct || range->not_PER_visible)
return range;
switch(ct->type) {
case ACT_EL_VALUE:
vmin = vmax = ct->value;
break;
case ACT_EL_RANGE:
case ACT_EL_LLRANGE:
case ACT_EL_RLRANGE:
case ACT_EL_ULRANGE:
vmin = ct->range_start;
vmax = ct->range_stop;
break;
case ACT_EL_EXT:
if(!*exmet) {
range->not_PER_visible = 1;
} else {
range->extensible = 1;
}
return range;
case ACT_CT_SIZE:
case ACT_CT_FROM:
if(type == ct->type) {
*exmet = 1;
} else {
range->not_PER_visible = 1;
return range;
}
assert(ct->el_count == 1);
return asn1constraint_compute_PER_range(expr_type,
ct->elements[0], type, minmax, exmet);
case ACT_CA_SET: /* (10..20)(15..17) */
case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
/* AND constraints, one after another. */
for(i = 0; i < ct->el_count; i++) {
tmp = asn1constraint_compute_PER_range(expr_type,
ct->elements[i], type,
ct->type==ACT_CA_SET?range:minmax, exmet);
if(!tmp) {
_range_free(range);
return NULL;
}
if(tmp->not_PER_visible) {
if(ct->type == ACT_CA_SET) {
/*
* X.691, #9.3.18:
* Ignore this separate component.
*/
} else {
/*
* X.691, #9.3.19:
* Ignore not PER-visible INTERSECTION
*/
}
_range_free(tmp);
continue;
}
range->extensible |= tmp->extensible;
if(tmp->extensible && type == ACT_CT_FROM) {
/*
* X.691, #9.3.10:
* Extensible permitted alphabet constraints
* are not PER-visible.
*/
range->not_PER_visible = 1;
}
ret = _range_intersection(range, tmp,
ct->type == ACT_CA_SET);
_range_free(tmp);
if(ret) {
_range_free(range);
errno = EPERM;
return NULL;
}
_range_canonicalize(range);
}
return range;
case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
/* Merge everything. Canonicalizator will do union magic */
for(i = 0; i < ct->el_count; i++) {
tmp = asn1constraint_compute_PER_range(expr_type,
ct->elements[i], type, minmax, exmet);
if(!tmp) {
_range_free(range);
return NULL;
}
if(tmp->empty_constraint) {
/* Ignore empty constraints */
_range_free(tmp);
continue;
}
range->not_PER_visible |= tmp->not_PER_visible;
range->extensible |= tmp->extensible;
_range_merge_in(range, tmp);
}
_range_canonicalize(range);
if(range->not_PER_visible) {
/*
* X.691, #9.3.19:
* If not PER-visible constraint is part of UNION,
* the resulting constraint is not PER-visible.
*/
_range_free(range);
if(minmax)
range = _range_clone(minmax);
else
range = _range_new();
}
return range;
case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
/*
* X.691, #9.3.19:
* EXCEPT and the following value set is completely ignored.
*/
assert(ct->el_count >= 1);
_range_free(range);
range = asn1constraint_compute_PER_range(expr_type,
ct->elements[0], type, minmax, exmet);
return range;
default:
range->not_PER_visible = 1;
return range;
}
if(!*exmet) {
/*
* Expectation is not met. Return the default range.
*/
range->not_PER_visible = 1;
return range;
}
_range_free(range);
range = _range_new();
ret = _range_fill(vmin, minmax, &range->left,
range, type, ct->_lineno);
ret |= _range_fill(vmax, minmax, &range->right,
range, type, ct->_lineno);
if(ret) {
_range_free(range);
errno = EPERM;
return NULL;
}
if(minmax) {
asn1cnst_range_t *clone;
clone = _range_clone(minmax);
/* Constrain parent type with given data. */
ret = _range_intersection(clone, range, 1);
_range_free(range);
if(ret) {
_range_free(clone);
errno = EPERM;
return NULL;
}
range = clone;
}
/*
* Recompute elements's min/max, remove duplicates, etc.
*/
_range_canonicalize(range);
return range;
}
#ifndef ASN1FIX_CRANGE_H
#define ASN1FIX_CRANGE_H
typedef struct asn1cnst_edge_s {
enum asn1cnst_range_edge {
ARE_MIN,
ARE_MAX,
ARE_VALUE,
} type;
int lineno; /* Line where the corresponding token was found */
asn1_integer_t value; /* Value when type is ARE_VALUE */
} asn1cnst_edge_t;
typedef struct asn1cnst_range_s {
asn1cnst_edge_t left; /* MIN from (MIN..10) */
asn1cnst_edge_t right; /* 10 from (MIN..10) */
/* If range is split in parts, these are the parts */
struct asn1cnst_range_s **elements;
int el_count;
int el_size;
int empty_constraint; /* If yes, too bad. */
int extensible; /* Extension marker (...) present. */
int not_PER_visible; /* Contains non PER-visible components */
} asn1cnst_range_t;
/*
* Compute the PER-visible constraint range.
*
* (expr_type) must have the type of the top-level parent ASN.1 type.
* (required_type) must be one of ACT_EL_RANGE, ACT_CT_SIZE or ACT_CT_FROM.
* (minmax) and (expectation_met) should be 0.
* ERRORS:
* EINVAL: Mandatory arguments missing.
* ENOMEM: Memory allocation failure.
* EPERM: Invalid constraint reference.
*/
asn1cnst_range_t *asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type,
const asn1p_constraint_t *ct,
enum asn1p_constraint_type_e required_type,
const asn1cnst_range_t *minmax,
int *expectation_met);
void asn1constraint_range_free(asn1cnst_range_t *);
/*
* Check that a specific constraint is compatible
* with the given expression type.
*/
int asn1constraint_compatible(asn1p_expr_type_e expr_type,
enum asn1p_constraint_type_e constr_type);
/*
* Fetch a default alphabet for this type.
*/
asn1cnst_range_t *asn1constraint_default_alphabet(asn1p_expr_type_e expr_type);
#endif /* ASN1FIX_CRANGE_H */
#include "asn1fix_internal.h"
#include "asn1fix_export.h"
extern arg_t a1f_replace_me_with_proper_interface_arg;
asn1p_expr_t *
asn1f_lookup_symbol_ex(
asn1p_t *asn,
......@@ -14,6 +17,9 @@ asn1f_lookup_symbol_ex(
arg.asn = asn;
arg.mod = *module_rw;
arg.expr = expr;
arg.eh = a1f_replace_me_with_proper_interface_arg.eh;
arg.debug = a1f_replace_me_with_proper_interface_arg.debug;
return asn1f_lookup_symbol(&arg, ref, module_rw);
}
......@@ -24,11 +30,15 @@ asn1f_class_access_ex(asn1p_t *asn,
asn1p_expr_t *expr,
asn1p_ref_t *ref,
asn1p_module_t **mod_r) {
static arg_t arg;
arg_t arg;
memset(&arg, 0, sizeof(arg));
arg.asn = asn;
arg.mod = mod;
arg.expr = expr;
arg.eh = a1f_replace_me_with_proper_interface_arg.eh;
arg.debug = a1f_replace_me_with_proper_interface_arg.debug;
return asn1f_class_access(&arg, ref, mod_r);
}
......@@ -38,11 +48,32 @@ asn1f_find_terminal_type_ex(asn1p_t *asn,
asn1p_module_t *mod,
asn1p_expr_t *expr,
asn1p_module_t **mod_r) {
static arg_t arg;
arg_t arg;
memset(&arg, 0, sizeof(arg));
arg.asn = asn;
arg.mod = mod;
arg.expr = expr;
arg.eh = a1f_replace_me_with_proper_interface_arg.eh;
arg.debug = a1f_replace_me_with_proper_interface_arg.debug;
return asn1f_find_terminal_type(&arg, expr, mod_r);
}
int
asn1f_fix_dereference_values_ex(asn1p_t *asn, asn1p_module_t *mod,
asn1p_expr_t *expr) {
arg_t arg;
memset(&arg, 0, sizeof(arg));
arg.asn = asn;
arg.mod = mod;
arg.expr = expr;
arg.eh = a1f_replace_me_with_proper_interface_arg.eh;
arg.debug = a1f_replace_me_with_proper_interface_arg.debug;
return asn1f_fix_dereference_values(&arg);
}
......@@ -7,6 +7,12 @@
#include <asn1fix_tags.h>
/*
* Create a human-readable representation of a reference and value.
*/
char const *asn1f_printable_reference(asn1p_ref_t *ref);
char const *asn1f_printable_value(asn1p_value_t *value);
/*
* Exportable version of an asn1f_lookup_symbol().
*/
......@@ -28,5 +34,10 @@ asn1p_expr_t *asn1f_class_access_ex(asn1p_t *asn, asn1p_module_t *mod,
asn1p_expr_t *asn1f_find_terminal_type_ex(asn1p_t *asn, asn1p_module_t *mod,
asn1p_expr_t *tc, asn1p_module_t **opt_module_r);
#endif /* _ASN1FIX_EXPORT_H_ */
/*
* Exportable version of asn1f_fix_dereference_values();
*/
int asn1f_fix_dereference_values_ex(asn1p_t *asn, asn1p_module_t *mod,
asn1p_expr_t *expr);
#endif /* _ASN1FIX_EXPORT_H_ */
......@@ -16,6 +16,7 @@
#include <assert.h>
#include <asn1parser.h> /* Our lovely ASN.1 parser module */
#include <asn1fix.h>
/*
* A definition of a function that will log error messages.
......@@ -32,6 +33,7 @@ typedef struct arg_s {
error_logger_f eh;
error_logger_f debug;
void *key; /* The next level key */
enum asn1f_flags flags;
} arg_t;
/*
......@@ -51,6 +53,9 @@ typedef struct arg_s {
#include "asn1fix_dereft.h" /* Dereference types */
#include "asn1fix_derefv.h" /* Dereference values */
#include "asn1fix_tags.h" /* Tags-related stuff */
#include "asn1fix_constraint.h" /* Constraint manipulation */
#include "asn1fix_crange.h" /* Constraint groking, exportable */
#include "asn1fix_export.h" /* Exported functions */
/*
......
......@@ -4,18 +4,6 @@
#ifndef _ASN1FIX_MISC_H_
#define _ASN1FIX_MISC_H_
/*
* Return a pointer to the locally held string with human-readable
* definition of the value.
*/
char const *asn1f_printable_value(asn1p_value_t *);
/*
* Return a pointer to the locally held string with human-readable
* definition of the reference.
*/
char const *asn1f_printable_reference(asn1p_ref_t *);
/*
* Recursively invoke a given function over the given expr and all its
* children.
......
......@@ -21,6 +21,7 @@ asn1f_value_resolve(arg_t *arg, asn1p_expr_t *expr) {
* 1. Find the terminal type for this assignment.
*/
type_expr = asn1f_find_terminal_type(arg, expr, 0);
DEBUG("%s(): terminal type %p", __func__, type_expr);
if(type_expr == 0) {
DEBUG("\tTerminal type for %s not found", expr->Identifier);
return -1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment