further runtime support for information object classes
diff --git a/examples/sample.source.J2735/Makefile b/examples/sample.source.J2735/Makefile
index f952b40..2c0d4e0 100644
--- a/examples/sample.source.J2735/Makefile
+++ b/examples/sample.source.J2735/Makefile
@@ -974,6 +974,9 @@
 
 ASN_MODULE_HEADERS+=ANY.h
 ASN_MODULE_SOURCES+=ANY.c
+ASN_MODULE_HEADERS+=OPEN_TYPE.h
+ASN_MODULE_SOURCES+=OPEN_TYPE.c
+ASN_MODULE_HEADERS+=constr_CHOICE.h
 ASN_MODULE_HEADERS+=BOOLEAN.h
 ASN_MODULE_SOURCES+=BOOLEAN.c
 ASN_MODULE_HEADERS+=INTEGER.h
@@ -988,7 +991,6 @@
 ASN_MODULE_SOURCES+=asn_SEQUENCE_OF.c
 ASN_MODULE_HEADERS+=asn_SET_OF.h
 ASN_MODULE_SOURCES+=asn_SET_OF.c
-ASN_MODULE_HEADERS+=constr_CHOICE.h
 ASN_MODULE_SOURCES+=constr_CHOICE.c
 ASN_MODULE_HEADERS+=constr_SEQUENCE.h
 ASN_MODULE_SOURCES+=constr_SEQUENCE.c
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 25ba4e5..8ec2140 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -38,6 +38,7 @@
 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);
+static int asn1c_lang_C_OpenType(arg_t *arg, asn1c_ioc_table_and_objset_t *opt_ioc, const char *column_name);
 static int _print_tag(arg_t *arg, struct asn1p_type_tag_s *tag_p);
 static int compute_extensions_start(asn1p_expr_t *expr);
 static int expr_break_recursion(arg_t *arg, asn1p_expr_t *expr);
@@ -301,6 +302,30 @@
 	return asn1c_lang_C_type_SIMPLE_TYPE(arg);
 }
 
+/*
+ * Check if it is a true open type. That is, type is taken from
+ * the Information Object Set driven constraints.
+ */
+static int
+is_open_type(arg_t *arg, asn1p_expr_t *expr, asn1c_ioc_table_and_objset_t *opt_ioc) {
+
+    (void)arg;
+
+    if(!opt_ioc) {
+        return 0;
+    }
+
+    if(expr->meta_type == AMT_TYPEREF
+       && expr->expr_type == A1TC_REFERENCE
+       && expr->reference->comp_count == 2
+       && expr->reference->components[1].lex_type
+              == RLT_AmpUppercase) {
+        return 1;
+    }
+
+    return 0;
+}
+
 int
 asn1c_lang_C_type_SEQUENCE(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
@@ -343,7 +368,21 @@
 		if(comp_mode == 1)
 			v->marker.flags |= EM_OMITABLE | EM_INDIRECT;
 		try_inline_default(arg, v, 1);
-		EMBED_WITH_IOCT(v, ioc_tao);
+        if(is_open_type(arg, v, ioc_tao.ioct ? &ioc_tao : 0)) {
+            arg_t tmp_arg = *arg;
+            tmp_arg.embed++;
+            INDENT(+1);
+            tmp_arg.expr = v;
+            const char *column_name = v->reference->components[1].name;
+            if(asn1c_lang_C_OpenType(&tmp_arg, &ioc_tao, column_name)) {
+                return -1;
+            }
+            INDENT(-1);
+            tmp_arg.embed--;
+            if(v->expr_type != A1TC_EXTENSIBLE) OUT(";\n");
+        } else {
+            EMBED_WITH_IOCT(v, ioc_tao);
+        }
 	}
 
 	PCTX_DEF;
@@ -1032,6 +1071,62 @@
 	return asn1c_lang_C_type_CHOICE_def(arg);
 }
 
+static ssize_t
+find_column_index(arg_t *arg, asn1c_ioc_table_and_objset_t *opt_ioc, const char *column_name) {
+    (void)arg;
+
+    if(!opt_ioc || !opt_ioc->ioct || !column_name) {
+        return -1;
+    }
+
+    if(opt_ioc->ioct->rows == 0) {
+        return 0;   /* No big deal. Just no data */
+    } else {
+        for(size_t clmn = 0; clmn < opt_ioc->ioct->row[0]->columns; clmn++) {
+            if(strcmp(opt_ioc->ioct->row[0]->column[clmn].field->Identifier,
+                      column_name) == 0) {
+                return clmn;
+            }
+        }
+        return -1;
+    }
+
+}
+
+static int
+asn1c_lang_C_OpenType(arg_t *arg, asn1c_ioc_table_and_objset_t *opt_ioc,
+                      const char *column_name) {
+    arg_t tmp_arg = *arg;
+
+    ssize_t column_index = find_column_index(arg, opt_ioc, column_name);
+    if(column_index < 0) {
+        FATAL("Open type generation attempted for %s, incomplete", column_name);
+        return -1;
+    }
+
+    asn1p_expr_t *open_type_choice =
+        asn1p_expr_new(arg->expr->_lineno, arg->expr->module);
+
+    open_type_choice->Identifier = strdup(arg->expr->Identifier);
+    open_type_choice->meta_type = AMT_TYPE;
+    open_type_choice->expr_type = ASN_CONSTR_OPEN_TYPE;
+    open_type_choice->_type_unique_index = arg->expr->_type_unique_index;
+
+    for(size_t row = 0; row < opt_ioc->ioct->rows; row++) {
+        struct asn1p_ioc_cell_s *cell =
+            &opt_ioc->ioct->row[row]->column[column_index];
+
+        asn1p_expr_t *m = asn1p_expr_clone(cell->value, 0);
+        asn1p_expr_add(open_type_choice, m);
+    }
+
+    tmp_arg.expr = open_type_choice;
+    GEN_INCLUDE_STD("OPEN_TYPE");
+    asn1c_lang_C_type_CHOICE(&tmp_arg);
+    asn1p_expr_free(tmp_arg.expr);
+    return 0;
+}
+
 static int
 asn1c_lang_C_type_CHOICE_def(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
@@ -1085,7 +1180,7 @@
 		int i;
 		cmap = compute_canonical_members_order(arg, elements);
 		if(cmap) {
-			OUT("static const int asn_MAP_%s_cmap_%d[] = {",
+			OUT("static const unsigned asn_MAP_%s_cmap_%d[] = {",
 				MKID(expr),
 				expr->_type_unique_index);
 			for(i = 0; i < elements; i++) {
@@ -2652,10 +2747,11 @@
 
     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)
+    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),
@@ -2728,10 +2824,11 @@
 
 
     REDIR(OT_CODE);
-    OUT("static asn_TYPE_descriptor_t *\n");
+    OUT("static asn_type_selector_result_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_type_selector_result_t result = {0, 0};\n");
     OUT("const 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);
@@ -2744,7 +2841,7 @@
         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("if(!memb_ptr) return result;\n");
         OUT("\n");
     }
 
@@ -2774,13 +2871,15 @@
     OUT("    const asn_ioc_cell_t *type_cell = &itable->rows[row * itable->columns_count + for_column];\n");
     OUT("\n");
     OUT("    if(constraining_cell->type_descriptor->compare_struct(constraining_cell->type_descriptor, constraining_value, constraining_cell->value_sptr) == 0) {\n");
-    OUT("        return type_cell->type_descriptor;\n");
+    OUT("        result.type_descriptor = type_cell->type_descriptor;\n");
+    OUT("        result.presence_index = row + 1;\n");
+    OUT("        break;\n");
     OUT("    }\n");
     OUT("}\n");
 
 
     OUT("\n");
-    OUT("return NULL;\n");
+    OUT("return result;\n");
     INDENT(-1);
     OUT("}\n");
     OUT("\n");
@@ -2810,9 +2909,11 @@
 
 	OUT("{ ");
 
-	if(outmost_tag && outmost_tag->tag_value == -1)
-		OUT("ATF_OPEN_TYPE | ");
-	OUT("%s, ",
+    if((outmost_tag && outmost_tag->tag_value == -1)
+       || is_open_type(arg, expr, opt_ioc)) {
+        OUT("ATF_OPEN_TYPE | ");
+    }
+    OUT("%s, ",
 		(expr->marker.flags & EM_INDIRECT)?"ATF_POINTER":"ATF_NOFLAGS");
 	if((expr->marker.flags & EM_OMITABLE) == EM_OMITABLE) {
 		asn1p_expr_t *tv;
@@ -2827,19 +2928,22 @@
 	} else {
 		OUT("0, ");
 	}
-	if(expr->_anonymous_type) {
-		assert(arg->expr->expr_type == ASN_CONSTR_SET_OF
-			|| arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF);
-		OUT("0,\n");
-	} else {
-		OUT("offsetof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(", ");
-		if(arg->expr->expr_type == ASN_CONSTR_CHOICE
-			&& (!UNNAMED_UNIONS)) OUT("choice.");
-		OUT("%s),\n", MKID_safe(expr));
-	}
-	INDENT(+1);
+    if(expr->_anonymous_type) {
+        assert(arg->expr->expr_type == ASN_CONSTR_SET_OF
+               || arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF);
+        OUT("0,\n");
+    } else {
+        OUT("offsetof(struct ");
+        out_name_chain(arg, ONC_avoid_keywords);
+        OUT(", ");
+        if((arg->expr->expr_type == ASN_CONSTR_CHOICE
+            || arg->expr->expr_type == ASN_CONSTR_OPEN_TYPE)
+           && (!UNNAMED_UNIONS))
+            OUT("choice.");
+        OUT("%s),\n", MKID_safe(expr));
+    }
+
+    INDENT(+1);
 	if(C99_MODE) OUT(".tag = ");
 	if(outmost_tag) {
 		if(outmost_tag->tag_value == -1)
@@ -2864,7 +2968,8 @@
 	}
 
 	complex_contents =
-		(expr->expr_type & ASN_CONSTR_MASK)
+		is_open_type(arg, expr, opt_ioc)
+		|| (expr->expr_type & ASN_CONSTR_MASK)
 		|| expr->expr_type == ASN_BASIC_ENUMERATED
 		|| (0 /* -- prohibited by X.693:8.3.4 */
 			&& expr->expr_type == ASN_BASIC_INTEGER
@@ -2872,15 +2977,16 @@
 		|| (expr->expr_type == ASN_BASIC_INTEGER
 			&& asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN);
 	if(C99_MODE) OUT(".type = ");
-	OUT("&asn_DEF_");
-	if(complex_contents) {
-		OUT("%s", MKID(expr));
-		if(!(arg->flags & A1C_ALL_DEFS_GLOBAL))
-			OUT("_%d", expr->_type_unique_index);
-	} else {
-		OUT("%s", asn1c_type_name(arg, expr, TNF_SAFE));
-	}
-	OUT(",\n");
+
+    OUT("&asn_DEF_");
+    if(complex_contents) {
+        OUT("%s", MKID(expr));
+        if(!(arg->flags & A1C_ALL_DEFS_GLOBAL))
+            OUT("_%d", expr->_type_unique_index);
+    } else {
+        OUT("%s", asn1c_type_name(arg, expr, TNF_SAFE));
+    }
+    OUT(",\n");
 
 
     if(C99_MODE) OUT(".type_selector = ");
@@ -3001,8 +3107,9 @@
 	if(HIDE_INNER_DEFS)
 		OUT("static /* Use -fall-defs-global to expose */\n");
 	OUT("asn_TYPE_descriptor_t asn_DEF_%s", p);
-	if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index);
-	OUT(" = {\n");
+    if(HIDE_INNER_DEFS || (arg->flags & A1C_ALL_DEFS_GLOBAL))
+        OUT("_%d", expr->_type_unique_index);
+    OUT(" = {\n");
 	INDENT(+1);
 
 		if(expr->_anonymous_type) {
diff --git a/libasn1parser/asn1p_expr.h b/libasn1parser/asn1p_expr.h
index 213f6a7..3be9672 100644
--- a/libasn1parser/asn1p_expr.h
+++ b/libasn1parser/asn1p_expr.h
@@ -59,6 +59,7 @@
 	ASN_CONSTR_SET,			/* SET */
 	ASN_CONSTR_SEQUENCE_OF,		/* SEQUENCE OF */
 	ASN_CONSTR_SET_OF,		/* SET OF */
+	ASN_CONSTR_OPEN_TYPE,
 
 	/*
 	 * ASN.1 Basic types
diff --git a/libasn1parser/asn1p_expr_str.h b/libasn1parser/asn1p_expr_str.h
index faa1cf8..065766e 100644
--- a/libasn1parser/asn1p_expr_str.h
+++ b/libasn1parser/asn1p_expr_str.h
@@ -17,6 +17,7 @@
 	[ ASN_CONSTR_SET ]	 = "SET",
 	[ ASN_CONSTR_SEQUENCE_OF ]	 = "SEQUENCE OF",
 	[ ASN_CONSTR_SET_OF ]	 = "SET OF",
+	[ ASN_CONSTR_OPEN_TYPE ]	 = "OPEN TYPE",
 	[ ASN_TYPE_ANY ]	 = "ANY",
 	[ ASN_BASIC_BOOLEAN ]	 = "BOOLEAN",
 	[ ASN_BASIC_NULL ]	 = "NULL",
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index 57e7c06..ffad24e 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -242,7 +242,7 @@
 }
 
 void
-BOOLEAN_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+BOOLEAN_free(const asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
 	if(td && ptr && !contents_only) {
 		FREEMEM(ptr);
 	}
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
index 38d6f5c..d5c0279 100644
--- a/skeletons/NativeInteger.c
+++ b/skeletons/NativeInteger.c
@@ -336,9 +336,9 @@
 }
 
 void
-NativeInteger_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
-
-	if(!td || !ptr)
+NativeInteger_free(const asn_TYPE_descriptor_t *td, void *ptr,
+                   int contents_only) {
+    if(!td || !ptr)
 		return;
 
 	ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)",
@@ -356,7 +356,7 @@
     if(aptr && bptr) {
         const asn_INTEGER_specifics_t *specs =
             (const asn_INTEGER_specifics_t *)td->specifics;
-        if(specs->field_unsigned)  {
+        if(specs && specs->field_unsigned) {
             const unsigned long *a = aptr;
             const unsigned long *b = bptr;
             if(*a < *b) {
@@ -364,7 +364,7 @@
             } else if(*a > *b) {
                 return 1;
             } else {
-                return 1;
+                return 0;
             }
         } else {
             const long *a = aptr;
@@ -374,7 +374,7 @@
             } else if(*a > *b) {
                 return 1;
             } else {
-                return 1;
+                return 0;
             }
         }
     } else if(!aptr) {
diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c
index d9eac63..f305d8b 100644
--- a/skeletons/NativeReal.c
+++ b/skeletons/NativeReal.c
@@ -377,9 +377,8 @@
 }
 
 void
-NativeReal_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
-
-	if(!td || !ptr)
+NativeReal_free(const asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+    if(!td || !ptr)
 		return;
 
 	ASN_DEBUG("Freeing %s as REAL (%d, %p, Native)",
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
index 7cc7ebd..57a0c1e 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -1726,8 +1726,9 @@
 }
 
 void
-OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
-	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr,
+                  int contents_only) {
+    OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
 	asn_OCTET_STRING_specifics_t *specs;
 	asn_struct_ctx_t *ctx;
 	struct _stack *stck;
diff --git a/skeletons/OPEN_TYPE.c b/skeletons/OPEN_TYPE.c
new file mode 100644
index 0000000..7a53ac3
--- /dev/null
+++ b/skeletons/OPEN_TYPE.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <OPEN_TYPE.h>
+#include <constr_CHOICE.h>
+#include <per_opentype.h>
+#include <errno.h>
+
+
+asn_dec_rval_t
+OPEN_TYPE_uper_get(asn_codec_ctx_t *opt_codec_ctx,
+                   asn_TYPE_descriptor_t *td, void *sptr,
+                   asn_TYPE_member_t *elm, asn_per_data_t *pd) {
+    asn_type_selector_result_t selected;
+    void *memb_ptr;   /* Pointer to the member */
+    void **memb_ptr2; /* Pointer to that pointer */
+    asn_dec_rval_t rv;
+
+    if(!(elm->flags & ATF_OPEN_TYPE) || !elm->type_selector) {
+        ASN__DECODE_FAILED;
+    }
+
+    selected = elm->type_selector(td, sptr);
+    if(!selected.presence_index) {
+        ASN__DECODE_FAILED;
+    }
+
+    /* Fetch the pointer to this member */
+    assert(elm->flags == ATF_OPEN_TYPE);
+    if(elm->flags & ATF_POINTER) {
+        memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)sptr + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    if(*memb_ptr2 != NULL) {
+        /* Make sure we reset the structure first before encoding */
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0)
+           != 0) {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    void *inner_value =
+        (char *)*memb_ptr2
+        + elm->type->elements[selected.presence_index - 1].memb_offset;
+
+    rv = uper_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL,
+                            &inner_value, pd);
+    switch(rv.code) {
+    case RC_OK:
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2,
+                                       selected.presence_index)
+           == 0) {
+            break;
+        } else {
+            rv.code = RC_FAIL;
+        }
+        /* Fall through */
+    case RC_WMORE:
+    case RC_FAIL:
+        if(*memb_ptr2) {
+            asn_CHOICE_specifics_t *specs = selected.type_descriptor->specifics;
+            if(elm->flags & ATF_POINTER) {
+                ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
+                *memb_ptr2 = NULL;
+            } else {
+                ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor,
+                                              inner_value);
+                memset(*memb_ptr2, 0, specs->struct_size);
+            }
+        }
+    }
+    return rv;
+}
+
+asn_dec_rval_t
+OPEN_TYPE_oer_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+                  void *sptr, asn_TYPE_member_t *elm, const void *ptr,
+                  size_t size) {
+    asn_type_selector_result_t selected;
+    void *memb_ptr;   /* Pointer to the member */
+    void **memb_ptr2; /* Pointer to that pointer */
+    asn_dec_rval_t rv;
+    size_t ot_ret;
+
+    if(!(elm->flags & ATF_OPEN_TYPE) || !elm->type_selector) {
+        ASN__DECODE_FAILED;
+    }
+
+    selected = elm->type_selector(td, sptr);
+    if(!selected.presence_index) {
+        ASN__DECODE_FAILED;
+    }
+
+    /* Fetch the pointer to this member */
+    if(elm->flags & ATF_POINTER) {
+        memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)sptr + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    if(*memb_ptr2 != NULL) {
+        /* Make sure we reset the structure first before encoding */
+        if(CHOICE_variant_set_presence(selected.type_descriptor, *memb_ptr2, 0)
+           != 0) {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    ot_ret = oer_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL,
+                               memb_ptr2, ptr, size);
+    switch(ot_ret) {
+    default:
+        if(CHOICE_variant_set_presence(selected.type_descriptor, *memb_ptr2,
+                                       selected.presence_index)
+           == 0) {
+            rv.code = RC_OK;
+            rv.consumed = ot_ret;
+            return rv;
+        } else {
+            /* Oh, now a full-blown failure failure */
+        }
+        /* Fall through */
+    case -1:
+        rv.code = RC_FAIL;
+        rv.consumed = 0;
+        break;
+    case 0:
+        rv.code = RC_WMORE;
+        rv.consumed = 0;
+        break;
+    }
+
+    if(*memb_ptr2) {
+        asn_CHOICE_specifics_t *specs = selected.type_descriptor->specifics;
+        if(elm->flags & ATF_POINTER) {
+            ASN_STRUCT_FREE(*selected.type_descriptor, *memb_ptr2);
+            *memb_ptr2 = NULL;
+        } else {
+            ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor,
+                                          *memb_ptr2);
+            memset(*memb_ptr2, 0, specs->struct_size);
+        }
+    }
+    return rv;
+}
diff --git a/skeletons/asn_codecs_prim.c b/skeletons/asn_codecs_prim.c
index 426339c..cf7ea02 100644
--- a/skeletons/asn_codecs_prim.c
+++ b/skeletons/asn_codecs_prim.c
@@ -115,9 +115,9 @@
 }
 
 void
-ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
-		int contents_only) {
-	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
+ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t *td, void *sptr,
+                         int contents_only) {
+    ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
 
 	if(!td || !sptr)
 		return;
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
index 435d592..71936c9 100644
--- a/skeletons/constr_CHOICE.c
+++ b/skeletons/constr_CHOICE.c
@@ -63,8 +63,10 @@
 /*
  * See the definitions.
  */
-static signed _fetch_present_idx(const void *struct_ptr, int off, int size);
-static void _set_present_idx(void *sptr, int offset, int size, int pres);
+static unsigned _fetch_present_idx(const void *struct_ptr, unsigned off,
+                                   unsigned size);
+static void _set_present_idx(void *sptr, unsigned offset, unsigned size,
+                             unsigned pres);
 static const void *_get_member_ptr(const asn_TYPE_descriptor_t *,
                                    const void *sptr, asn_TYPE_member_t **elm,
                                    unsigned *present);
@@ -1035,8 +1037,8 @@
 }
 
 void
-CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
-	asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
+CHOICE_free(const asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+    asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 	unsigned present;
 
 	if(!td || !ptr)
@@ -1081,17 +1083,18 @@
  * is guaranteed to be aligned properly. ASN.1 compiler itself does not
  * produce packed code.
  */
-static signed
-_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
-	const void *present_ptr;
+static unsigned
+_fetch_present_idx(const void *struct_ptr, unsigned pres_offset,
+                   unsigned pres_size) {
+    const void *present_ptr;
 	unsigned present;
 
 	present_ptr = ((const char *)struct_ptr) + pres_offset;
 
 	switch(pres_size) {
-	case sizeof(int):	present =   *(const int *)present_ptr; break;
-	case sizeof(short):	present = *(const short *)present_ptr; break;
-	case sizeof(char):	present =  *(const char *)present_ptr; break;
+	case sizeof(int):	present = *(const unsigned int *)present_ptr; break;
+	case sizeof(short):	present = *(const unsigned short *)present_ptr; break;
+	case sizeof(char):	present = *(const unsigned char *)present_ptr; break;
 	default:
 		/* ANSI C mandates enum to be equivalent to integer */
 		assert(pres_size != sizeof(int));
@@ -1102,14 +1105,15 @@
 }
 
 static void
-_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
-	void *present_ptr;
+_set_present_idx(void *struct_ptr, unsigned pres_offset, unsigned pres_size,
+                 unsigned present) {
+    void *present_ptr;
 	present_ptr = ((char *)struct_ptr) + pres_offset;
 
 	switch(pres_size) {
-	case sizeof(int):	*(int *)present_ptr   = present; break;
-	case sizeof(short):	*(short *)present_ptr = present; break;
-	case sizeof(char):	*(char *)present_ptr  = present; break;
+	case sizeof(int):	*(unsigned int *)present_ptr   = present; break;
+	case sizeof(short):	*(unsigned short *)present_ptr = present; break;
+	case sizeof(char):	*(unsigned char *)present_ptr  = present; break;
 	default:
 		/* ANSI C mandates enum to be equivalent to integer */
 		assert(pres_size != sizeof(int));
@@ -1181,3 +1185,50 @@
         return 1;
     }
 }
+
+/*
+ * Return the 1-based choice variant presence index.
+ * Returns 0 in case of error.
+ */
+unsigned
+CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td, const void *sptr) {
+    asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
+    return _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
+}
+
+/*
+ * Sets or resets the 1-based choice variant presence index.
+ * In case a previous index is not zero, the currently selected structure
+ * member is freed and zeroed-out first.
+ * Returns 0 on success and -1 on error.
+ */
+int
+CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, void *sptr,
+                            unsigned present) {
+    extern asn_CHOICE_specifics_t asn_SPC_value_specs_3;
+    asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
+    unsigned old_present;
+
+    if(!sptr) {
+        return -1;
+    }
+
+    if(present > td->elements_count)
+        return -1;
+
+    old_present =
+        _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
+    if(present == old_present)
+        return 0;
+
+    if(old_present == 0) {
+        assert(old_present <= td->elements_count);
+        ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr);
+		memset(sptr, 0, specs->struct_size);
+    }
+
+    _set_present_idx(sptr, specs->pres_offset, specs->pres_size, present);
+
+    return 0;
+}
+
diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
index 3c3b6ca..0aedcf7 100644
--- a/skeletons/constr_CHOICE.h
+++ b/skeletons/constr_CHOICE.h
@@ -28,7 +28,7 @@
     unsigned tag2el_count;
 
     /* Canonical ordering of CHOICE elements, for PER */
-    const int *canonical_order;
+    const unsigned *canonical_order;
 
     /*
      * Extensions-related stuff.
@@ -51,6 +51,22 @@
 per_type_encoder_f CHOICE_encode_uper;
 asn_outmost_tag_f CHOICE_outmost_tag;
 
+/*
+ * Return the 1-based choice variant presence index.
+ * Returns 0 in case of error.
+ */
+unsigned CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td,
+                                     const void *structure_ptr);
+
+/*
+ * Sets or resets the 1-based choice variant presence index.
+ * In case a previous index is not zero, the currently selected structure
+ * member is freed and zeroed-out first.
+ * Returns 0 on success and -1 on error.
+ */
+int CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td,
+                                void *structure_ptr, unsigned present);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 9859e25..e1c57d3 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -5,6 +5,7 @@
  */
 #include <asn_internal.h>
 #include <constr_SEQUENCE.h>
+#include <OPEN_TYPE.h>
 #include <per_opentype.h>
 
 /*
@@ -201,7 +202,7 @@
 		/*
 		 * MICROPHASE 1: Synchronize decoding.
 		 */
-		ASN_DEBUG("In %s SEQUENCE left %d, edx=%d flags=%d"
+		ASN_DEBUG("In %s SEQUENCE left %d, edx=%u flags=%d"
 				" opt=%d ec=%d",
 			td->name, (int)ctx->left, edx,
 			elements[edx].flags, elements[edx].optional,
@@ -948,8 +949,8 @@
 }
 
 void
-SEQUENCE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
-	size_t edx;
+SEQUENCE_free(const asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
+    size_t edx;
 
 	if(!td || !sptr)
 		return;
@@ -1118,15 +1119,10 @@
 		}
 
 		/* Fetch the member from the stream */
-		ASN_DEBUG("Decoding member %s in %s", elm->name, td->name);
+		ASN_DEBUG("Decoding member \"%s\" in %s", elm->name, td->name);
 
         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);
+            rv = OPEN_TYPE_uper_get(opt_codec_ctx, td, st, elm, pd);
         } else {
             rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
                                         elm->per_constraints, memb_ptr2, pd);
diff --git a/skeletons/constr_SEQUENCE_oer.c b/skeletons/constr_SEQUENCE_oer.c
index 84b0db9..7f162ae 100644
--- a/skeletons/constr_SEQUENCE_oer.c
+++ b/skeletons/constr_SEQUENCE_oer.c
@@ -7,6 +7,7 @@
 
 #include <asn_internal.h>
 #include <constr_SEQUENCE.h>
+#include <OPEN_TYPE.h>
 #include <errno.h>
 
 /*
@@ -150,8 +151,6 @@
         for(edx = (ctx->step >> 1); edx < td->elements_count;
             edx++, ctx->step = (ctx->step & ~1) + 2) {
             asn_TYPE_member_t *elm = &td->elements[edx];
-            void *memb_tmpptr;     /* Temporary reference. */
-            void **memb_ptr2;   /* Pointer to a pointer to a memmber */
 
             ASN_DEBUG("Decoding %s->%s", td->name, elm->name);
 
@@ -188,37 +187,20 @@
              */
             ctx->step |= 1; /* Confirm entering next microphase */
         microphase2_decode_continues:
-            if(elm->flags & ATF_POINTER) {
-                /* Member is a pointer to another structure */
-                memb_ptr2 = (void **)((char *)st + elm->memb_offset);
-            } else {
-                memb_tmpptr = (char *)st + elm->memb_offset;
-                memb_ptr2 = &memb_tmpptr; /* Ensure this & remains in scope! */
-            }
-
             if((elm->flags & ATF_OPEN_TYPE) && elm->type_selector) {
-                asn_TYPE_descriptor_t *et = elm->type_selector(td, st);
-                ssize_t ot_ret;
-                if(!et) {
-                    ASN__DECODE_FAILED;
-                }
-                ot_ret = oer_open_type_get(opt_codec_ctx, et, NULL, memb_ptr2,
-                                           ptr, size);
-                switch(ot_ret) {
-                case -1:
-                    rval.code = RC_FAIL;
-                    rval.consumed = 0;
-                    break;
-                case 0:
-                    rval.code = RC_WMORE;
-                    rval.consumed = 1;
-                    break;
-                default:
-                    rval.code = RC_OK;
-                    rval.consumed = ot_ret;
-                    break;
-                }
+                rval = OPEN_TYPE_oer_get(opt_codec_ctx, td, st, elm, ptr, size);
             } else {
+                void *memb_tmpptr; /* Temporary reference. */
+                void **memb_ptr2;  /* Pointer to a pointer to a memmber */
+
+                if(elm->flags & ATF_POINTER) {
+                    /* Member is a pointer to another structure */
+                    memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+                } else {
+                    memb_tmpptr = (char *)st + elm->memb_offset;
+                    memb_ptr2 = &memb_tmpptr; /* Ensure remains in scope! */
+                }
+
                 rval = elm->type->oer_decoder(opt_codec_ctx, elm->type,
                                               elm->oer_constraints, memb_ptr2,
                                               ptr, size);
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index 226bef3..4f370bf 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -910,8 +910,8 @@
 }
 
 void
-SET_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
-	size_t edx;
+SET_free(const asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+    size_t edx;
 
 	if(!td || !ptr)
 		return;
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index 62973ac..1a268df 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -788,7 +788,7 @@
 }
 
 void
-SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
+SET_OF_free(const asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
 	if(td && ptr) {
 		asn_SET_OF_specifics_t *specs;
 		asn_TYPE_member_t *elm = td->elements;
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index d11b859..a7db7b0 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -53,7 +53,7 @@
  * dynamically.)
  */
 typedef void (asn_struct_free_f)(
-		struct asn_TYPE_descriptor_s *type_descriptor,
+		const struct asn_TYPE_descriptor_s *type_descriptor,
 		void *struct_ptr, int free_contents_only);
 #define	ASN_STRUCT_FREE(asn_DEF, ptr)	(asn_DEF).free_struct(&(asn_DEF),ptr,0)
 #define	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr)	\
@@ -95,7 +95,11 @@
  * 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)(
+typedef struct asn_type_selector_result_s {
+    struct asn_TYPE_descriptor_s *type_descriptor; /* Type encoded. */
+    unsigned presence_index; /* Associated choice variant. */
+} asn_type_selector_result_t;
+typedef asn_type_selector_result_t(asn_type_selector_f)(
     const struct asn_TYPE_descriptor_s *parent_type_descriptor,
     const void *parent_structure_ptr);
 
@@ -168,7 +172,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_type_selector_f *type_selector;     /* IoS runtime type 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 */
diff --git a/skeletons/file-dependencies b/skeletons/file-dependencies
index d3c4d0e..10022f5 100644
--- a/skeletons/file-dependencies
+++ b/skeletons/file-dependencies
@@ -5,6 +5,7 @@
 #
 
 ANY.h ANY.c
+OPEN_TYPE.h OPEN_TYPE.c constr_CHOICE.h
 BMPString.h BMPString.c UTF8String.h
 BOOLEAN.h BOOLEAN.c
 ENUMERATED.h ENUMERATED.c INTEGER.h NativeEnumerated.h
@@ -34,7 +35,7 @@
 asn_SEQUENCE_OF.h asn_SEQUENCE_OF.c asn_SET_OF.h
 asn_SET_OF.h asn_SET_OF.c
 constr_CHOICE.h constr_CHOICE.c
-constr_SEQUENCE.h constr_SEQUENCE.c
+constr_SEQUENCE.h constr_SEQUENCE.c OPEN_TYPE.h
 constr_SEQUENCE_OF.h constr_SEQUENCE_OF.c asn_SEQUENCE_OF.h constr_SET_OF.h
 constr_SET.h constr_SET.c
 constr_SET_OF.h constr_SET_OF.c asn_SET_OF.h
diff --git a/tests/tests-asn1c-compiler/141-component-relation-OK.asn1 b/tests/tests-asn1c-compiler/141-component-relation-OK.asn1
index 8d5868c..e1f1d0d 100755
--- a/tests/tests-asn1c-compiler/141-component-relation-OK.asn1
+++ b/tests/tests-asn1c-compiler/141-component-relation-OK.asn1
@@ -8,7 +8,7 @@
 ModuleComponentRelationConstraint
 	{ iso org(3) dod(6) internet (1) private(4) enterprise(1)
 		spelio(9363) software(1) asn1c(5) test(1) 141 }
-	DEFINITIONS ::=
+	DEFINITIONS AUTOMATIC TAGS ::=
 BEGIN
 
     Frame ::= SEQUENCE {