oer constraints (incomplete)
diff --git a/libasn1fix/asn1fix_crange.c b/libasn1fix/asn1fix_crange.c
index b38befe..5b85464 100644
--- a/libasn1fix/asn1fix_crange.c
+++ b/libasn1fix/asn1fix_crange.c
@@ -216,8 +216,11 @@
 	int prev_count = into->el_count;
 	int i;
 
+	into->not_OER_visible |= cr->not_OER_visible;
 	into->not_PER_visible |= cr->not_PER_visible;
 	into->extensible |= cr->extensible;
+	if(into->extensible)
+		into->not_OER_visible = 1;
 
 	/*
 	 * Add the element OR all its children "into".
@@ -496,15 +499,44 @@
 }
 
 static int
-_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check) {
+_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check, int is_oer) {
 	int ret;
 	int i, j;
 
 	assert(!range->incompatible);
 
-	/* Propagate errors */
-	range->extensible |= with->extensible;
-	range->not_PER_visible |= with->not_PER_visible;
+    if(is_oer) {
+        assert(range->extensible == 0);
+        assert(range->not_OER_visible == 0);
+        assert(with->extensible == 0);
+        assert(with->not_OER_visible == 0);
+        if(range->extensible) {
+            assert(range->not_OER_visible);
+        }
+        if(range->extensible || range->not_OER_visible) {
+            /* X.696 #8.2.4 Completely ignore the extensible constraints */
+            /* (XXX)(YYY,...) Retain the first one (XXX). */
+            asn1cnst_range_t *tmp = _range_new();
+            *tmp = *range;
+            *range = *with;
+            _range_free(tmp);
+            return 0;
+        }
+
+        if(with->extensible) {
+            assert(with->not_OER_visible);
+        }
+        if(with->extensible || with->not_OER_visible) {
+            /* X.696 #8.2.4 Completely ignore the extensible constraints */
+            return 0;
+        }
+    } else {
+        /* Propagate errors */
+        range->extensible |= with->extensible;
+        if(with->extensible)
+            range->not_OER_visible = 1;
+        range->not_PER_visible |= with->not_PER_visible;
+    }
 	range->empty_constraint |= with->empty_constraint;
 
 	if(range->empty_constraint) {
@@ -699,22 +731,24 @@
 }
 
 asn1cnst_range_t *
-asn1constraint_compute_OER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type
-, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
+asn1constraint_compute_OER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
     return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_OER_visibility);
 }
 
 asn1cnst_range_t *
-asn1constraint_compute_PER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type
-, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
+asn1constraint_compute_PER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
     if(0) return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_PER_visibility);
     /* Due to pecularities of PER constraint handling, we don't enable strict PER visibility upfront here. */
     return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags);
 }
 
 asn1cnst_range_t *
-asn1constraint_compute_constraint_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
-	asn1cnst_range_t *range;
+asn1constraint_compute_constraint_range(
+    const char *dbg_name, asn1p_expr_type_e expr_type,
+    const asn1p_constraint_t *ct,
+    enum asn1p_constraint_type_e requested_ct_type,
+    const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
+    asn1cnst_range_t *range;
 	asn1cnst_range_t *tmp;
 	asn1p_value_t *vmin;
 	asn1p_value_t *vmax;
@@ -731,14 +765,16 @@
 	 * Check if the requested constraint is theoretically compatible
 	 * with the given expression type.
 	 */
-	if(asn1constraint_compatible(expr_type, type,
+	if(asn1constraint_compatible(expr_type, requested_ct_type,
 			cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
 		errno = EINVAL;
 		return 0;
 	}
 
-	/* Check arguments' validity. */
-	switch(type) {
+	/*
+	 * Check arguments' validity.
+	 */
+	switch(requested_ct_type) {
 	case ACT_EL_RANGE:
 		if(exmet == &expectation_met)
 			*exmet = 1;
@@ -792,7 +828,7 @@
      * SIZE constraints on restricted character string types
      * which are not known-multiplier are not OER-visible.
      */
-	if(type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
+	if(requested_ct_type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
 		range->not_OER_visible = 1;
 
     if(!ct
@@ -813,6 +849,8 @@
 	case ACT_EL_EXT:
 		if(!*exmet) {
 			range->incompatible = 1;
+			range->extensible = 1;
+			range->not_OER_visible = 1;
 		} else {
 			_range_free(range);
 			errno = ERANGE;
@@ -821,21 +859,27 @@
 		return range;
 	case ACT_CT_SIZE:
 	case ACT_CT_FROM:
-		if(type == ct->type) {
+		if(requested_ct_type == ct->type) {
+			/*
+			 * Specifically requested to process SIZE() or FROM() constraint.
+			 */
 			*exmet = 1;
 		} else {
 			range->incompatible = 1;
 			return range;
 		}
 		assert(ct->el_count == 1);
-		tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
-			ct->elements[0], type, minmax, exmet, cpr_flags);
+		tmp = asn1constraint_compute_constraint_range(
+			dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax,
+			exmet, cpr_flags);
 		if(tmp) {
 			_range_free(range);
 		} else {
 			if(errno == ERANGE) {
 				range->empty_constraint = 1;
 				range->extensible = 1;
+				if(range->extensible)
+					range->not_OER_visible = 1;
 				tmp = range;
 			} else {
 				_range_free(range);
@@ -848,11 +892,14 @@
 		/* AND constraints, one after another. */
 		for(i = 0; i < ct->el_count; i++) {
 			tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
-				ct->elements[i], type,
+				ct->elements[i], requested_ct_type,
 				ct->type==ACT_CA_SET?range:minmax, exmet,
 				cpr_flags);
 			if(!tmp) {
 				if(errno == ERANGE) {
+					range->extensible = 1;
+					if(range->extensible)
+						range->not_OER_visible = 1;
 					continue;
 				} else {
 					_range_free(range);
@@ -898,13 +945,14 @@
 			}
 
 			ret = _range_intersection(range, tmp,
-				ct->type == ACT_CA_SET);
+				ct->type == ACT_CA_SET, cpr_flags & CPR_strict_OER_visibility);
 			_range_free(tmp);
 			if(ret) {
 				_range_free(range);
 				errno = EPERM;
 				return NULL;
 			}
+
 			_range_canonicalize(range);
 		}
 
@@ -918,11 +966,12 @@
 		tmp = 0;
 		for(i = 0; i < ct->el_count; i++) {
 			tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
-				ct->elements[i], type, minmax, exmet,
+				ct->elements[i], requested_ct_type, minmax, exmet,
 				cpr_flags);
 			if(!tmp) {
 				if(errno == ERANGE) {
 					range->extensible = 1;
+					range->not_OER_visible = 1;
 					continue;
 				} else {
 					_range_free(range);
@@ -937,6 +986,7 @@
 		}
 		if(tmp) {
 			tmp->extensible |= range->extensible;
+			tmp->not_OER_visible |= range->not_OER_visible;
 			tmp->empty_constraint |= range->empty_constraint;
 			_range_free(range);
 			range = tmp;
@@ -951,11 +1001,12 @@
 		 */
 		for(; i < ct->el_count; i++) {
 			tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
-				ct->elements[i], type, minmax, exmet,
+				ct->elements[i], requested_ct_type, minmax, exmet,
 				cpr_flags);
 			if(!tmp) {
 				if(errno == ERANGE) {
 					range->extensible = 1;
+					range->not_OER_visible = 1;
 					continue;
 				} else {
 					_range_free(range);
@@ -975,6 +1026,7 @@
 				 * Ignore empty constraints in OR logic.
 				 */
 				range->extensible |= tmp->extensible;
+				range->not_OER_visible |= tmp->not_OER_visible;
 				_range_free(tmp);
 				continue;
 			}
@@ -984,7 +1036,7 @@
 
 		_range_canonicalize(range);
 
-        if(type == ACT_CT_FROM) {
+        if(requested_ct_type == ACT_CT_FROM) {
             /*
              * X.696 permitted alphabet constraints are not OER-visible.
              */
@@ -1026,7 +1078,7 @@
 		assert(ct->el_count >= 1);
 		_range_free(range);
 		range = asn1constraint_compute_constraint_range(dbg_name, expr_type,
-			ct->elements[0], type, minmax, exmet, cpr_flags);
+			ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags);
 		return range;
 	default:
 		range->incompatible = 1;
@@ -1046,10 +1098,10 @@
 	range = _range_new();
 
 	ret  = _range_fill(vmin, minmax, &range->left,
-				range, type, ct->_lineno);
+				range, requested_ct_type, ct->_lineno);
 	if(!ret)
 	ret = _range_fill(vmax, minmax, &range->right,
-				range, type, ct->_lineno);
+				range, requested_ct_type, ct->_lineno);
 	if(ret) {
 		_range_free(range);
 		errno = EPERM;
@@ -1062,7 +1114,8 @@
 		clone = _range_clone(minmax);
 
 		/* Constrain parent type with given data. */
-		ret = _range_intersection(clone, range, 1);
+		ret = _range_intersection(clone, range, 1,
+		                          cpr_flags & CPR_strict_OER_visibility);
 		_range_free(range);
 		if(ret) {
 			_range_free(clone);