using ioc constraints in run time
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index f5f94e9..e2aece0 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -33,7 +33,8 @@
 	ONC_force_compound_name	= 0x02,
 };
 static int out_name_chain(arg_t *arg, enum onc_flags);
-static int asn1c_lang_C_type_SEQUENCE_def(arg_t *arg);
+static int asn1c_lang_C_type_SEQUENCE_def(
+    arg_t *arg, asn1c_ioc_table_and_objset_t *);
 static int asn1c_lang_C_type_SET_def(arg_t *arg);
 static int asn1c_lang_C_type_CHOICE_def(arg_t *arg);
 static int asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of);
@@ -47,7 +48,8 @@
 static int emit_single_member_PER_constraint(arg_t *arg, asn1cnst_range_t *range, int juscountvalues, const char *type);
 static int emit_member_OER_constraints(arg_t *arg, asn1p_expr_t *expr, const char *pfx);
 static int emit_member_PER_constraints(arg_t *arg, asn1p_expr_t *expr, const char *pfx);
-static int emit_member_table(arg_t *arg, asn1p_expr_t *expr);
+static int emit_member_table(arg_t *arg, asn1p_expr_t *expr,
+                             asn1c_ioc_table_and_objset_t *);
 static int emit_tag2member_map(arg_t *arg, tag2el_t *tag2el, int tag2el_count, const char *opt_modifier);
 static int emit_include_dependencies(arg_t *arg);
 static asn1p_expr_t *terminal_structable(arg_t *arg, asn1p_expr_t *expr);
@@ -341,7 +343,7 @@
 		if(comp_mode == 1)
 			v->marker.flags |= EM_OMITABLE | EM_INDIRECT;
 		try_inline_default(arg, v, 1);
-		EMBED(v);
+		EMBED_WITH_IOCT(v, ioc_tao);
 	}
 
 	PCTX_DEF;
@@ -364,11 +366,11 @@
 		arg->embed ? "" : "_t");
 	}
 
-	return asn1c_lang_C_type_SEQUENCE_def(arg);
+	return asn1c_lang_C_type_SEQUENCE_def(arg, ioc_tao.ioct ? &ioc_tao : 0);
 }
 
 static int
-asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) {
+asn1c_lang_C_type_SEQUENCE_def(arg_t *arg, asn1c_ioc_table_and_objset_t *opt_ioc) {
 	asn1p_expr_t *expr = arg->expr;
 	asn1p_expr_t *v;
 	int elements;	/* Number of elements */
@@ -420,7 +422,7 @@
 			}
 			if(v->marker.flags & EM_OMITABLE)
 			    comp_mode == 1 ? ++aoms_count : ++roms_count;
-			emit_member_table(arg, v);
+			emit_member_table(arg, v, opt_ioc);
 			elements++;
 		});
 		OUT("};\n");
@@ -675,7 +677,7 @@
 			if(v->expr_type == A1TC_EXTENSIBLE) {
 				if(comp_mode < 3) comp_mode++;
 			} else {
-				emit_member_table(arg, v);
+				emit_member_table(arg, v, NULL);
 				elements++;
 			}
 		});
@@ -824,7 +826,7 @@
 						expr, "Member", 0));
 				assert(tmp_memb.Identifier);
 			}
-			tmp.default_cb(&tmp);
+			tmp.default_cb(&tmp, NULL);
 			if(tmp_memb.Identifier != memb->Identifier)
 				if(0) free(tmp_memb.Identifier);
 		arg->embed--;
@@ -901,7 +903,7 @@
 		}
 		v->_anonymous_type = 1;
 		arg->embed++;
-		emit_member_table(arg, v);
+		emit_member_table(arg, v, NULL);
 		arg->embed--;
 		free(v->Identifier);
 		v->Identifier = (char *)NULL;
@@ -1070,7 +1072,7 @@
 		INDENTED(TQ_FOR(v, &(expr->members), next) {
 			if(v->expr_type == A1TC_EXTENSIBLE)
 				continue;
-			emit_member_table(arg, v);
+			emit_member_table(arg, v, NULL);
 			elements++;
 		});
 		OUT("};\n");
@@ -1184,7 +1186,7 @@
 		tmp.asn = arg->asn;
 		tmp.expr = extract;
 
-		ret = arg->default_cb(&tmp);
+		ret = arg->default_cb(&tmp, NULL);
 
 		asn1p_expr_free(extract);
 
@@ -2586,7 +2588,210 @@
 }
 
 static int
-emit_member_table(arg_t *arg, asn1p_expr_t *expr) {
+emit_member_type_selector(arg_t *arg, asn1p_expr_t *expr, asn1c_ioc_table_and_objset_t *opt_ioc) {
+	int save_target = arg->target->target;
+    asn1p_expr_t *parent_expr = arg->expr;
+
+    const asn1p_constraint_t *crc =
+        asn1p_get_component_relation_constraint(expr->combined_constraints);
+    if(!crc || crc->el_count <= 1) {
+        /* Not an Open Type, it seems. */
+        OUT("0");
+        return 0;
+    }
+
+    if(crc->el_count <= 1 || crc->elements[0]->type != ACT_EL_VALUE
+       || crc->elements[0]->value->type != ATV_REFERENCED
+       || crc->elements[0]->value->value.reference->comp_count != 1) {
+        FATAL(
+            "Reference does not look like an object set");
+        return -1;
+    }
+
+    const char *objset_name =
+        crc->elements[0]->value->value.reference->components[0].name;
+    if(strcmp(objset_name, opt_ioc->objset->Identifier) != 0) {
+        FATAL("Object Set references do not match: %s != %s", objset_name,
+              opt_ioc->objset->Identifier);
+        return -1;
+    }
+
+    if(crc->el_count != 2 || crc->elements[1]->type != ACT_EL_VALUE
+       || crc->elements[1]->value->type != ATV_REFERENCED
+       || crc->elements[1]->value->value.reference->comp_count != 1) {
+        FATAL(
+            "Do not know how to handle complex IoS constraints (%d components "
+            "of constraint, %d components of reference %s) for %s at line "
+            "%d",
+            crc->el_count,
+            crc->el_count >= 2 && crc->elements[1]->type == ACT_EL_VALUE
+                    && crc->elements[1]->value->type == ATV_REFERENCED
+                ? crc->elements[1]->value->value.reference->comp_count
+                : -1,
+            crc->el_count >= 2 && crc->elements[1]->type == ACT_EL_VALUE
+                    && crc->elements[1]->value->type == ATV_REFERENCED
+                ? asn1p_ref_string(crc->elements[1]->value->value.reference)
+                : "?",
+            MKID(parent_expr), parent_expr->_lineno);
+        OUT("0");
+        return -1;
+    }
+
+    const asn1p_ref_t *cref = crc->elements[1]->value->value.reference;
+    const char *cname = cref->components[0].name;
+    if(cname[0] == '@' && cname[1] != '.') {
+        cname += 1;
+    } else if(cname[0] == '@' && cname[1] == '.' && cname[2] != '.') {
+        cname += 2;
+    } else {
+        FATAL("Complex IoS reference %s can not be processed",
+              asn1p_ref_string(cref));
+        OUT("0");
+        return -1;
+    }
+
+    assert(opt_ioc != NULL);
+
+	asn1p_expr_t *constraining_memb = NULL;
+	TQ_FOR(constraining_memb, &(parent_expr->members), next) {
+        if(strcmp(constraining_memb->Identifier, cname) == 0)
+            break;
+    }
+    if(!constraining_memb) {
+        FATAL("Can not find \"%s\" in %s at line %d", cname, MKID(parent_expr),
+              parent_expr->_lineno);
+        return -1;
+    }
+
+    if(constraining_memb->meta_type != AMT_TYPEREF
+       || constraining_memb->expr_type != A1TC_REFERENCE
+       || constraining_memb->reference->comp_count != 2
+       || constraining_memb->reference->components[1].lex_type
+              != RLT_Amplowercase) {
+        FATAL(
+            "Does not look like %s is a CLASS field reference (%s) on line "
+            "%d",
+            MKID(constraining_memb),
+            constraining_memb->reference
+                ? asn1p_ref_string(constraining_memb->reference)
+                : "<no reference>",
+            constraining_memb->_lineno);
+        return -1;
+    }
+    const char *cfield = constraining_memb->reference->components[1].name;
+
+    ssize_t constraining_column = -1;
+    for(size_t cn = 0; cn < opt_ioc->ioct->rows ? opt_ioc->ioct->row[0]->columns : 0;
+        cn++) {
+        if(strcmp(cfield, opt_ioc->ioct->row[0]->column[cn].field->Identifier)
+           == 0) {
+            constraining_column = cn;
+            break;
+        }
+    }
+    if(constraining_column < 0) {
+        FATAL("Can not find referenced object class column %s\n", cfield);
+        return -1;
+    }
+
+    if(expr->meta_type != AMT_TYPEREF
+       || expr->expr_type != A1TC_REFERENCE
+       || expr->reference->comp_count != 2
+       || expr->reference->components[1].lex_type
+              != RLT_AmpUppercase) {
+        FATAL(
+            "Does not look like %s is a CLASS field reference (%s) denoting a type on line "
+            "%d",
+            MKID(expr),
+            expr->reference
+                ? asn1p_ref_string(expr->reference)
+                : "<no reference>",
+            expr->_lineno);
+        return -1;
+    }
+    const char *for_field = expr->reference->components[1].name;
+
+    ssize_t for_column = -1;
+    for(size_t cn = 0; cn < opt_ioc->ioct->rows ? opt_ioc->ioct->row[0]->columns : 0;
+        cn++) {
+        if(strcmp(for_field,
+                  opt_ioc->ioct->row[0]->column[cn].field->Identifier)
+           == 0) {
+            for_column = cn;
+            break;
+        }
+    }
+    if(for_column < 0) {
+        FATAL("Can not find referenced object class column %s\n", for_field);
+        return -1;
+    }
+
+
+    REDIR(OT_CODE);
+    OUT("static asn_TYPE_descriptor_t *\n");
+    OUT("select_%s_type(const asn_TYPE_descriptor_t *parent_type, const void *parent_sptr) {\n", MKID_safe(expr));
+    INDENT(+1);
+
+    OUT("asn_ioc_set_t *itable = asn_IOS_%s_%d;\n", MKID(opt_ioc->objset),
+        opt_ioc->objset->_type_unique_index);
+    OUT("size_t constraining_column = %zu; /* %s */\n", constraining_column, cfield);
+    OUT("size_t for_column = %zu; /* %s */\n", for_column, for_field);
+    OUT("size_t row;\n");
+
+    const char *tname = asn1c_type_name(arg, constraining_memb, TNF_SAFE);
+    if(constraining_memb->marker.flags & EM_INDIRECT) {
+        OUT("void *memb_ptr = *(const void **)");
+        OUT("((const char *)parent_sptr + offsetof(struct ");
+            out_name_chain(arg, ONC_avoid_keywords);
+        OUT(", %s));", MKID_safe(constraining_memb));
+        OUT("if(!memb_ptr) return NULL;\n");
+        OUT("\n");
+    }
+
+    switch(asn1c_type_fits_long(arg, constraining_memb)) {
+    case FL_NOTFIT:
+        OUT("const %s_t *constraining_value = (const %s_t *)", tname, tname);
+        break;
+    case FL_PRESUMED:
+    case FL_FITS_SIGNED:
+        OUT("const long *constraining_value = (const long *)");
+        break;
+    case FL_FITS_UNSIGN:
+        OUT("const unsigned long *constraining_value = (const unsigned long *)");
+        break;
+    }
+    if(constraining_memb->marker.flags & EM_INDIRECT) {
+        OUT("memb_ptr;\n");
+    } else {
+        OUT("((const char *)parent_sptr + offsetof(struct ");
+            out_name_chain(arg, ONC_avoid_keywords);
+        OUT(", %s));\n", MKID_safe(constraining_memb));
+    }
+    OUT("\n");
+
+    OUT("for(row=0; row < itable->rows_count; row++) {\n");
+    OUT("    asn_ioc_cell_s *constraining_cell = itable->rows[row * itable->columns_count + constraining_column];\n");
+    OUT("    asn_ioc_cell_s *type_cell = itable->rows[row * itable->columns_count + for_column];\n");
+    OUT("    if(constraining_cell->type_descriptor->struct_compare(constraining_cell->type_descriptor, constraining_value, constraining_cell->value_sptr) == 0) {\n");
+    OUT("        return type_cell->type_descriptor;\n");
+    OUT("    }\n");
+    OUT("}\n");
+
+
+    OUT("\n");
+    OUT("return NULL;\n");
+    INDENT(-1);
+    OUT("}\n");
+    OUT("\n");
+
+    REDIR(save_target);
+    OUT("select_%s_type", MKID_safe(expr));
+
+    return 0;
+}
+
+static int
+emit_member_table(arg_t *arg, asn1p_expr_t *expr, asn1c_ioc_table_and_objset_t *opt_ioc) {
 	int save_target;
 	arg_t tmp_arg;
 	struct asn1p_type_tag_s outmost_tag_s;
@@ -2675,6 +2880,16 @@
 		OUT("%s", asn1c_type_name(arg, expr, TNF_SAFE));
 	}
 	OUT(",\n");
+
+
+    if(C99_MODE) OUT(".type_selector = ");
+    if(opt_ioc) {
+        emit_member_type_selector(arg, expr, opt_ioc);
+    } else {
+        OUT("0");
+    }
+	OUT(",\n");
+
 	if(C99_MODE) OUT(".memb_constraints = ");
 	if(expr->constraints) {
 		if(arg->flags & A1C_NO_CONSTRAINTS) {
diff --git a/libasn1compiler/asn1c_internal.h b/libasn1compiler/asn1c_internal.h
index c86d75e..c732a04 100644
--- a/libasn1compiler/asn1c_internal.h
+++ b/libasn1compiler/asn1c_internal.h
@@ -41,13 +41,15 @@
 
 #include "asn1compiler.h"
 
+struct asn1c_ioc_table_and_objset_s;
+
 typedef struct arg_s {
 
 	enum asn1c_flags flags;
 
 	void (*logger_cb)(int _severity, const char *fmt, ...);
 
-	int (*default_cb)(struct arg_s *);
+	int (*default_cb)(struct arg_s *, const struct asn1c_ioc_table_and_objset_s *opt);
 
 	struct compiler_streams *target;
 
diff --git a/libasn1compiler/asn1c_ioc.c b/libasn1compiler/asn1c_ioc.c
index 76d02d9..af32041 100644
--- a/libasn1compiler/asn1c_ioc.c
+++ b/libasn1compiler/asn1c_ioc.c
@@ -223,7 +223,7 @@
     (void)context;
     GEN_INCLUDE_STD("asn_ioc");
 
-    REDIR(OT_STAT_DEFS);
+    REDIR(OT_IOC_TABLES);
 
     /* Emit values that are used in the Information Object Set table first */
     for(size_t rn = 0; rn < ioc_tao.ioct->rows; rn++) {
diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h
index 0330dbf..47762a8 100644
--- a/libasn1compiler/asn1c_out.h
+++ b/libasn1compiler/asn1c_out.h
@@ -21,6 +21,7 @@
 		OT_TYPE_DECLS,	/* Type declarations */
 		OT_FUNC_DECLS,	/* Function declarations */
 		OT_POST_INCLUDE,/* #include after type definition */
+		OT_IOC_TABLES,	/* Information Object Class tables */
 		OT_CTABLES,	/* Constraint tables */
 		OT_CODE,	/* Some code */
 		OT_CTDEFS,	/* Constraint definitions */
@@ -36,7 +37,7 @@
 } compiler_streams_t;
 
 static char *_compiler_stream2str[] __attribute__ ((unused))
-    = { "IGNORE", "INCLUDES", "DEPS", "FWD-DECLS", "FWD-DEFS", "TYPE-DECLS", "FUNC-DECLS", "POST-INCLUDE", "CTABLES", "CODE", "CTDEFS", "STAT-DEFS" };
+    = { "IGNORE", "INCLUDES", "DEPS", "FWD-DECLS", "FWD-DEFS", "TYPE-DECLS", "FUNC-DECLS", "POST-INCLUDE", "IOC-TABLES", "CTABLES", "CODE", "CTDEFS", "STAT-DEFS" };
 
 int asn1c_compiled_output(arg_t *arg, const char *fmt, ...);
 
@@ -56,18 +57,27 @@
 		INDENT(-1);					\
 	} while(0)
 
-#define	EMBED(ev)	do {					\
-		arg->embed++;					\
-		INDENTED(arg_t _tmp = *arg;			\
-			_tmp.expr = ev;				\
-			_tmp.default_cb(&_tmp);			\
-		);						\
-		arg->embed--;					\
-		if(ev->expr_type != A1TC_EXTENSIBLE)		\
-			OUT(";\n");				\
-		assert(arg->target->target == OT_TYPE_DECLS ||	\
-			arg->target->target == OT_FWD_DEFS);	\
-	} while(0)
+#define EMBED(ev)                                        \
+    do {                                                 \
+        arg->embed++;                                    \
+        INDENTED(arg_t _tmp = *arg; _tmp.expr = ev;      \
+                 _tmp.default_cb(&_tmp, NULL););         \
+        arg->embed--;                                    \
+        if(ev->expr_type != A1TC_EXTENSIBLE) OUT(";\n"); \
+        assert(arg->target->target == OT_TYPE_DECLS      \
+               || arg->target->target == OT_FWD_DEFS);   \
+    } while(0)
+
+#define EMBED_WITH_IOCT(ev, ioc)                                   \
+    do {                                                           \
+        arg->embed++;                                              \
+        INDENTED(arg_t _tmp = *arg; _tmp.expr = ev;                \
+                 _tmp.default_cb(&_tmp, ((ioc).ioct ? &ioc : 0));); \
+        arg->embed--;                                              \
+        if(ev->expr_type != A1TC_EXTENSIBLE) OUT(";\n");           \
+        assert(arg->target->target == OT_TYPE_DECLS                \
+               || arg->target->target == OT_FWD_DEFS);             \
+    } while(0)
 
 /* Output a piece of text into a default stream */
 #define	OUT(fmt, args...)	asn1c_compiled_output(arg, fmt, ##args)
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
index 9e2cab4..cc7d8a6 100644
--- a/libasn1compiler/asn1c_save.c
+++ b/libasn1compiler/asn1c_save.c
@@ -303,6 +303,8 @@
 	safe_fprintf(fp_c, "#include \"%s.h\"\n\n", filename);
 	if(arg->flags & A1C_NO_INCLUDE_DEPS)
 		SAVE_STREAM(fp_c, OT_POST_INCLUDE, "", 1);
+	TQ_FOR(ot, &(cs->destination[OT_IOC_TABLES].chunks), next)
+		safe_fwrite(ot->buf, ot->len, 1, fp_c);
 	TQ_FOR(ot, &(cs->destination[OT_CTABLES].chunks), next)
 		safe_fwrite(ot->buf, ot->len, 1, fp_c);
 	TQ_FOR(ot, &(cs->destination[OT_CODE].chunks), next)
@@ -312,7 +314,7 @@
 	TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next)
 		safe_fwrite(ot->buf, ot->len, 1, fp_c);
 
-	assert(OT_MAX == 12);	/* Protection from reckless changes */
+	assert(OT_MAX == 13);	/* Protection from reckless changes */
 
 	fclose(fp_c);
 	fclose(fp_h);
diff --git a/libasn1compiler/asn1compiler.c b/libasn1compiler/asn1compiler.c
index 42d55e6..37dca3e 100644
--- a/libasn1compiler/asn1compiler.c
+++ b/libasn1compiler/asn1compiler.c
@@ -2,9 +2,10 @@
 #include "asn1c_lang.h"
 #include "asn1c_out.h"
 #include "asn1c_save.h"
+#include "asn1c_ioc.h"
 
 static void default_logger_cb(int, const char *fmt, ...);
-static int asn1c_compile_expr(arg_t *arg);
+static int asn1c_compile_expr(arg_t *arg, const asn1c_ioc_table_and_objset_t *);
 static int asn1c_attach_streams(asn1p_expr_t *expr);
 static int asn1c_detach_streams(asn1p_expr_t *expr);
 
@@ -42,7 +43,7 @@
 			cs->target = OT_TYPE_DECLS;
 			arg->target = cs;
 
-			ret = asn1c_compile_expr(arg);
+			ret = asn1c_compile_expr(arg, NULL);
 			if(ret) {
 				FATAL("Cannot compile \"%s\" (%x:%x) at line %d",
 					arg->expr->Identifier,
@@ -72,7 +73,7 @@
 }
 
 static int
-asn1c_compile_expr(arg_t *arg) {
+asn1c_compile_expr(arg_t *arg, const asn1c_ioc_table_and_objset_t *opt_ioc) {
 	asn1p_expr_t *expr = arg->expr;
 	int (*type_cb)(arg_t *);
 	int ret;
@@ -99,7 +100,7 @@
 			for(i = 0; i<expr->specializations.pspecs_count; i++) {
 				arg->expr = expr->specializations
 						.pspec[i].my_clone;
-				ret = asn1c_compile_expr(arg);
+				ret = asn1c_compile_expr(arg, opt_ioc);
 				if(ret) break;
 			}
 			arg->expr = expr;	/* Restore */
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index a64310d..9859e25 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -1081,7 +1081,7 @@
 	 */
 	for(edx = 0; edx < td->elements_count; edx++) {
 		asn_TYPE_member_t *elm = &td->elements[edx];
-		void *memb_ptr;		/* Pointer to the member */
+        void *memb_ptr;		/* Pointer to the member */
 		void **memb_ptr2;	/* Pointer to that pointer */
 
 		if(IN_EXTENSION_GROUP(specs, edx))
@@ -1119,9 +1119,19 @@
 
 		/* Fetch the member from the stream */
 		ASN_DEBUG("Decoding member %s in %s", elm->name, td->name);
-		rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
-			elm->per_constraints, memb_ptr2, pd);
-		if(rv.code != RC_OK) {
+
+        if((elm->flags & ATF_OPEN_TYPE) && elm->type_selector) {
+            asn_TYPE_descriptor_t *et = elm->type_selector(td, st);
+            if(!et) {
+                FREEMEM(opres);
+                ASN__DECODE_FAILED;
+            }
+            rv = uper_open_type_get(opt_codec_ctx, et, NULL, memb_ptr2, pd);
+        } else {
+            rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
+                                        elm->per_constraints, memb_ptr2, pd);
+        }
+        if(rv.code != RC_OK) {
 			ASN_DEBUG("Failed decode %s in %s",
 				elm->name, td->name);
 			FREEMEM(opres);
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index 29961e3..d11b859 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -91,7 +91,14 @@
 /* The instance of the above function type; used internally. */
 asn_outmost_tag_f asn_TYPE_outmost_tag;
 
-
+/*
+ * Fetch the desired type of the Open Type based on the
+ * Information Object Set driven constraints.
+ */
+typedef struct asn_TYPE_descriptor_s *(asn_type_selector_f)(
+    const struct asn_TYPE_descriptor_s *parent_type_descriptor,
+    const void *parent_structure_ptr);
+
 /*
  * The definitive description of the destination language's structure.
  */
@@ -161,6 +168,7 @@
     ber_tlv_tag_t tag;      /* Outmost (most immediate) tag */
     int tag_mode;           /* IMPLICIT/no/EXPLICIT tag at current level */
     asn_TYPE_descriptor_t *type;            /* Member type descriptor */
+    asn_type_selector_f *type_selector;     /* IoS selector */
     asn_constr_check_f *memb_constraints;   /* Constraints validator */
     asn_oer_constraints_t *oer_constraints; /* OER compiled constraints */
     asn_per_constraints_t *per_constraints; /* PER compiled constraints */