aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-08-18 05:42:05 +0000
committerLev Walkin <vlm@lionet.info>2004-08-18 05:42:05 +0000
commitb45e067b9162664df7c4f23fe57becd93bd5d0ed (patch)
tree674a95235cb7a3f822b29fb654c23a839b02c037
parent9095adab51d10b977d3ad8e64505150ad8c418bb (diff)
constraint groking code
-rw-r--r--libasn1fix/Makefile.am52
-rw-r--r--libasn1fix/Makefile.in73
-rw-r--r--libasn1fix/asn1fix.c120
-rw-r--r--libasn1fix/asn1fix.h2
-rw-r--r--libasn1fix/asn1fix_constraint.c239
-rw-r--r--libasn1fix/asn1fix_constraint.h17
-rw-r--r--libasn1fix/asn1fix_constraint_compat.c181
-rw-r--r--libasn1fix/asn1fix_crange.c912
-rw-r--r--libasn1fix/asn1fix_crange.h59
-rw-r--r--libasn1fix/asn1fix_export.c35
-rw-r--r--libasn1fix/asn1fix_export.h13
-rw-r--r--libasn1fix/asn1fix_internal.h5
-rw-r--r--libasn1fix/asn1fix_misc.h12
-rw-r--r--libasn1fix/asn1fix_value.c1
14 files changed, 1576 insertions, 145 deletions
diff --git a/libasn1fix/Makefile.am b/libasn1fix/Makefile.am
index 0e52b4f3..93732542 100644
--- a/libasn1fix/Makefile.am
+++ b/libasn1fix/Makefile.am
@@ -1,36 +1,42 @@
-
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
+
diff --git a/libasn1fix/Makefile.in b/libasn1fix/Makefile.in
index 91b9428f..80a91c0e 100644
--- a/libasn1fix/Makefile.in
+++ b/libasn1fix/Makefile.in
@@ -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@
diff --git a/libasn1fix/asn1fix.c b/libasn1fix/asn1fix.c
index af110999..dd0d5e73 100644
--- a/libasn1fix/asn1fix.c
+++ b/libasn1fix/asn1fix.c
@@ -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;
}
diff --git a/libasn1fix/asn1fix.h b/libasn1fix/asn1fix.h
index 58ca537c..1bed8581 100644
--- a/libasn1fix/asn1fix.h
+++ b/libasn1fix/asn1fix.h
@@ -12,7 +12,7 @@
*/
enum asn1f_flags {
A1F_NOFLAGS,
- A1F_DEBUG, /* Print debugging output using (_is_fatal = -1) */
+ A1F_DEBUG = 0x01, /* Print debugging output */
};
/*
diff --git a/libasn1fix/asn1fix_constraint.c b/libasn1fix/asn1fix_constraint.c
new file mode 100644
index 00000000..b7b66c44
--- /dev/null
+++ b/libasn1fix/asn1fix_constraint.c
@@ -0,0 +1,239 @@
+#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;
+}
diff --git a/libasn1fix/asn1fix_constraint.h b/libasn1fix/asn1fix_constraint.h
new file mode 100644
index 00000000..a04e6a50
--- /dev/null
+++ b/libasn1fix/asn1fix_constraint.h
@@ -0,0 +1,17 @@
+#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_ */
diff --git a/libasn1fix/asn1fix_constraint_compat.c b/libasn1fix/asn1fix_constraint_compat.c
new file mode 100644
index 00000000..28ebf92e
--- /dev/null
+++ b/libasn1fix/asn1fix_constraint_compat.c
@@ -0,0 +1,181 @@
+#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;
+}
diff --git a/libasn1fix/asn1fix_crange.c b/libasn1fix/asn1fix_crange.c
new file mode 100644
index 00000000..17618caf
--- /dev/null
+++ b/libasn1fix/asn1fix_crange.c
@@ -0,0 +1,912 @@
+#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;
+}
+
diff --git a/libasn1fix/asn1fix_crange.h b/libasn1fix/asn1fix_crange.h
new file mode 100644
index 00000000..9873e3b2
--- /dev/null
+++ b/libasn1fix/asn1fix_crange.h
@@ -0,0 +1,59 @@
+#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 */
diff --git a/libasn1fix/asn1fix_export.c b/libasn1fix/asn1fix_export.c
index d6bb37b4..cdae6505 100644
--- a/libasn1fix/asn1fix_export.c
+++ b/libasn1fix/asn1fix_export.c
@@ -1,6 +1,9 @@
#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);
+}
+
diff --git a/libasn1fix/asn1fix_export.h b/libasn1fix/asn1fix_export.h
index 2ade0c9a..7fd9ce11 100644
--- a/libasn1fix/asn1fix_export.h
+++ b/libasn1fix/asn1fix_export.h
@@ -8,6 +8,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().
*/
asn1p_expr_t *asn1f_lookup_symbol_ex(
@@ -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_ */
diff --git a/libasn1fix/asn1fix_internal.h b/libasn1fix/asn1fix_internal.h
index ac543cbb..c3739633 100644
--- a/libasn1fix/asn1fix_internal.h
+++ b/libasn1fix/asn1fix_internal.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 */
/*
diff --git a/libasn1fix/asn1fix_misc.h b/libasn1fix/asn1fix_misc.h
index a586faa8..a90c5bed 100644
--- a/libasn1fix/asn1fix_misc.h
+++ b/libasn1fix/asn1fix_misc.h
@@ -5,18 +5,6 @@
#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.
*/
diff --git a/libasn1fix/asn1fix_value.c b/libasn1fix/asn1fix_value.c
index a22fd3dc..a0560edb 100644
--- a/libasn1fix/asn1fix_value.c
+++ b/libasn1fix/asn1fix_value.c
@@ -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;