XMLValueList support

diff --git a/ChangeLog b/ChangeLog
index da52c44..9fcd5b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,9 @@
 
-0.9.10:	2005-Feb-24
+0.9.10:	2005-Feb-25
 
-	* Fixed #1150856.
-	  Reported by <vvvy@users.sourceforge.net>.
-	* Fixed XER XMLValueList encoding and decoding.
-	  (Test case 70) (Severity: high, Secruity impact: low)
-	  Reported by <siden@ul-gsm.ru>.
+	* Completed the XER XMLValueList encoding and decoding.
+	* Native integer type is now using "long".
+	* Fixed #1150856. Reported by <vvvy@users.sourceforge.net>.
 
 0.9.9:	2005-Feb-22
 
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 883644b..c0ff5a1 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -85,36 +85,124 @@
 	return asn1c_lang_C_type_SIMPLE_TYPE(arg);
 }
 
+struct value2enum {
+	asn1c_integer_t	 value;
+	const char	*name;
+	int		 idx;
+};
+static int compar_enumMap_byName(const void *ap, const void *bp) {
+	const struct value2enum *a = (const struct value2enum *)ap;
+	const struct value2enum *b = (const struct value2enum *)bp;
+	return strcmp(a->name, b->name);
+}
+static int compar_enumMap_byValue(const void *ap, const void *bp) {
+	const struct value2enum *a = (const struct value2enum *)ap;
+	const struct value2enum *b = (const struct value2enum *)bp;
+	if(a->value < b->value)
+		return -1;
+	else if(a->value == b->value)
+		return 0;
+	return 1;
+}
+
 int
 asn1c_lang_C_type_common_INTEGER(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
 	asn1p_expr_t *v;
+	int el_count = expr_elements_count(arg, expr);
+	struct value2enum *v2e;
+	int map_is_extensible = (expr->expr_type == ASN_BASIC_INTEGER);
 
-	REDIR(OT_DEPS);
+	v2e = alloca((el_count + 1) * sizeof(*v2e));
 
-	if(expr->expr_type == ASN_BASIC_ENUMERATED
-	|| TQ_FIRST(&(expr->members))
-	) {
+	/*
+	 * For all ENUMERATED types and for those INTEGER types which
+	 * have identifiers, print out an enumeration table and a mapping
+	 * between identifiers and associated values.
+	 */
+	if(expr->expr_type == ASN_BASIC_ENUMERATED || el_count) {
+		int eidx = 0;
+
+		REDIR(OT_DEPS);
 		OUT("typedef enum %s {\n", MKID(expr->Identifier));
 		TQ_FOR(v, &(expr->members), next) {
 			switch(v->expr_type) {
 			case A1TC_UNIVERVAL:
-				OUT("\t%s\t= %" PRIdASN ",\n",
+				OUT("\t%s\t= %" PRIdASN "%s\n",
 					asn1c_make_identifier(0,
 						expr->Identifier,
 						v->Identifier, 0),
-					v->value->value.v_integer);
+					v->value->value.v_integer,
+					(eidx+1 < el_count) ? "," : ""
+				);
+				v2e[eidx].name = v->Identifier;
+				v2e[eidx].value = v->value->value.v_integer;
+				eidx++;
 				break;
 			case A1TC_EXTENSIBLE:
 				OUT("\t/*\n");
 				OUT("\t * Enumeration is extensible\n");
 				OUT("\t */\n");
+				map_is_extensible = 1;
 				break;
 			default:
 				return -1;
 			}
 		}
 		OUT("} %s_e;\n", MKID(expr->Identifier));
+		assert(eidx == el_count);
+
+		/*
+		 * Generate a enumerationName<->value map for XER codec.
+		 */
+		REDIR(OT_STAT_DEFS);
+
+		OUT("static asn_INTEGER_enum_map_t asn_MAP_%s_value2enum[] = {\n",
+			MKID_nr(expr->Identifier));
+		qsort(v2e, el_count, sizeof(v2e[0]), compar_enumMap_byValue);
+		for(eidx = 0; eidx < el_count; eidx++) {
+			v2e[eidx].idx = eidx;
+			OUT("\t{ %" PRIdASN ",\t%ld,\t\"%s\" }%s\n",
+				v2e[eidx].value,
+				(long)strlen(v2e[eidx].name), v2e[eidx].name,
+				(eidx + 1 < el_count) ? "," : "");
+		}
+		if(map_is_extensible)
+			OUT("\t/* This list is extensible */\n");
+		OUT("};\n");
+
+		OUT("static unsigned int asn_MAP_%s_enum2value[] = {\n",
+			MKID_nr(expr->Identifier));
+		qsort(v2e, el_count, sizeof(v2e[0]), compar_enumMap_byName);
+		for(eidx = 0; eidx < el_count; eidx++) {
+			OUT("\t%d%s\t/* %s(%" PRIdASN ") */\n",
+				v2e[eidx].idx,
+				(eidx + 1 < el_count) ? "," : "",
+				v2e[eidx].name, v2e[eidx].value);
+		}
+		if(map_is_extensible)
+			OUT("\t/* This list is extensible */\n");
+		OUT("};\n");
+
+		OUT("static asn_INTEGER_specifics_t asn_DEF_%s_specs = {\n",
+			MKID_nr(expr->Identifier));
+		INDENT(+1);
+		OUT("asn_MAP_%s_value2enum,\t"
+			"/* \"tag\" => N; sorted by tag */\n",
+			MKID_nr(expr->Identifier));
+		OUT("asn_MAP_%s_enum2value,\t"
+			"/* N => \"tag\"; sorted by N */\n",
+			MKID_nr(expr->Identifier));
+		OUT("%d,\t/* Number of elements in the maps */\n",
+			el_count);
+		OUT("%d,\t/* Enumeration is %sextensible */\n",
+			map_is_extensible, map_is_extensible ? "": "not ");
+		if(expr->expr_type == ASN_BASIC_ENUMERATED)
+			OUT("1\t/* Strict enumeration */\n");
+		else
+			OUT("0\n");
+		INDENT(-1);
+		OUT("};\n");
 	}
 
 	return asn1c_lang_C_type_SIMPLE_TYPE(arg);
@@ -434,7 +522,7 @@
 			OUT("asn_DEF_%s_tag2el_cxer,\n", p);
 		else
 			OUT("asn_DEF_%s_tag2el,\t/* Same as above */\n", p);
-		OUT("%d,\t/* Count of tags in the CANONICAL-XER map */\n", tag2el_cxer_count);
+		OUT("%d,\t/* Count of tags in the CXER map */\n", tag2el_cxer_count);
 		OUT("%d,\t/* Whether extensible */\n",
 			check_if_extensible(expr));
 		OUT("(unsigned int *)asn_DEF_%s_mmap\t/* Mandatory elements map */\n", p);
@@ -471,7 +559,10 @@
 	OUT("A_%s_OF(",
 		(arg->expr->expr_type == ASN_CONSTR_SET_OF)
 			? "SET" : "SEQUENCE");
-	if(memb->expr_type & ASN_CONSTR_MASK) {
+	if(memb->expr_type & ASN_CONSTR_MASK
+	|| ((memb->expr_type == ASN_BASIC_ENUMERATED
+		|| memb->expr_type == ASN_BASIC_INTEGER)
+	    && expr_elements_count(arg, memb))) {
 		arg_t tmp;
 		asn1p_expr_t tmp_memb;
 		arg->embed++;
@@ -775,6 +866,7 @@
 	int tags_count;
 	int all_tags_count;
 	enum tvm_compat tv_mode;
+	enum etd_spec etd_spec;
 	char *p;
 
 	if(arg->embed) {
@@ -800,36 +892,49 @@
 
 		REDIR(OT_TYPE_DECLS);
 
-		OUT("%s\t", asn1c_type_name(arg, arg->expr, tnfmt | TNF_CHECK));
-		OUT("%s", expr->marker.flags?"*":" ");
-		OUT("%s", MKID(expr->Identifier));
-		if((expr->marker.flags & EM_DEFAULT) == EM_DEFAULT)
-			OUT("\t/* DEFAULT %s */",
-			    asn1f_printable_value(expr->marker.default_value));
-		else if((expr->marker.flags & EM_OPTIONAL) == EM_OPTIONAL)
-			OUT("\t/* OPTIONAL */");
+		OUT("%s", asn1c_type_name(arg, arg->expr, tnfmt | TNF_CHECK));
+		if(!expr->_anonymous_type) {
+			OUT("%s", expr->marker.flags?"\t*":"\t ");
+			OUT("%s", MKID(expr->Identifier));
+			if((expr->marker.flags & EM_DEFAULT) == EM_DEFAULT)
+				OUT("\t/* DEFAULT %s */",
+					asn1f_printable_value(
+						expr->marker.default_value));
+			else if((expr->marker.flags & EM_OPTIONAL) == EM_OPTIONAL)
+				OUT("\t/* OPTIONAL */");
+		}
+
+	} else {
+		GEN_INCLUDE(asn1c_type_name(arg, expr, TNF_INCLUDE));
 
 		REDIR(OT_TYPE_DECLS);
-		return 0;
+
+		OUT("typedef %s\t",
+			asn1c_type_name(arg, arg->expr, TNF_CTYPE | TNF_CHECK));
+		OUT("%s%s_t",
+			expr->marker.flags?"*":" ",
+			MKID(expr->Identifier));
+		OUT_DEBUG("\t/* %s:%d */", __FILE__, __LINE__);
 	}
 
-
-	GEN_INCLUDE(asn1c_type_name(arg, expr, TNF_INCLUDE));
-
-	REDIR(OT_TYPE_DECLS);
-
-	OUT("typedef %s\t", asn1c_type_name(arg, arg->expr, TNF_CTYPE | TNF_CHECK));
-	OUT("%s", expr->marker.flags?"*":" ");
-	OUT("%s_t", MKID(expr->Identifier));
+	if((expr->expr_type == ASN_BASIC_ENUMERATED)
+	|| (expr->expr_type == ASN_BASIC_INTEGER
+		&& expr_elements_count(arg, expr)))
+		etd_spec = ETD_HAS_SPECIFICS;
+	else
+		etd_spec = ETD_NO_SPECIFICS;
 
 	/*
 	 * If this type just blindly refers the other type, alias it.
 	 * 	Type1 ::= Type2
 	 */
+	if(arg->embed && etd_spec == ETD_NO_SPECIFICS) {
+		REDIR(OT_TYPE_DECLS);
+		return 0;
+	}
 	if((!expr->constraints || (arg->flags & A1C_NO_CONSTRAINTS))
-		&& expr->tag.tag_class == TC_NOCLASS
-		&& !TQ_FIRST(&(expr->members))
-	) {
+	&& (arg->embed || expr->tag.tag_class == TC_NOCLASS)
+	&& etd_spec == ETD_NO_SPECIFICS) {
 		char *type_name;
 		REDIR(OT_FUNC_DECLS);
 		type_name = asn1c_type_name(arg, expr, TNF_SAFE);
@@ -837,9 +942,10 @@
 		if(HIDE_INNER_DEFS) OUT("/* ");
 		OUT("#define\tasn_DEF_%s\t", MKID_nr(expr->Identifier));
 		type_name = asn1c_type_name(arg, expr, TNF_SAFE);
-		OUT("asn_DEF_%s\n", type_name);
+		OUT("asn_DEF_%s", type_name);
 		if(HIDE_INNER_DEFS)
-			OUT(" // (Use -fall-defs-global to expose) */");
+			OUT("\t// (Use -fall-defs-global to expose) */");
+		OUT("\n");
 		REDIR(OT_CODE);
 		OUT("/* This type is equivalent to %s */\n", type_name);
 		OUT("\n");
@@ -854,8 +960,8 @@
 	 */
 	tv_mode = emit_tags_vectors(arg, expr, &tags_count, &all_tags_count);
 
-	emit_type_DEF(arg, expr, tv_mode, tags_count, all_tags_count, 0,
-			ETD_NO_SPECIFICS);
+	emit_type_DEF(arg, expr, tv_mode, tags_count, all_tags_count,
+		0, etd_spec);
 
 	REDIR(OT_CODE);
 
@@ -864,6 +970,7 @@
 	 */
 	if(!(arg->flags & A1C_NO_CONSTRAINTS)) {
 		p = MKID(expr->Identifier);
+		if(HIDE_INNER_DEFS) OUT("static ");
 		OUT("int\n");
 		OUT("%s_constraint("
 			"asn_TYPE_descriptor_t *td, const void *sptr,\n", p);
@@ -901,7 +1008,7 @@
 	p = MKID(expr->Identifier);
 	OUT("%s_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) {\n", p);
 	INDENT(+1);
-	{
+  {
 	asn1p_expr_t *terminal = asn1f_find_terminal_type_ex(arg->asn, expr);
 	char *type_name = asn1c_type_name(arg, expr, TNF_SAFE);
 	OUT("td->free_struct    = asn_DEF_%s.free_struct;\n",    type_name);
@@ -920,13 +1027,23 @@
 	}
 	OUT("td->elements       = asn_DEF_%s.elements;\n",       type_name);
 	OUT("td->elements_count = asn_DEF_%s.elements_count;\n", type_name);
-	OUT("td->specifics      = asn_DEF_%s.specifics;\n",      type_name);
+	if(etd_spec != ETD_NO_SPECIFICS) {
+		INDENT(-1);
+		OUT("    /* ");
 	}
-	INDENT(-1);
+	OUT("td->specifics      = asn_DEF_%s.specifics;",        type_name);
+	if(etd_spec == ETD_NO_SPECIFICS) {
+		INDENT(-1);
+		OUT("\n");
+	} else {
+		OUT("\t// Defined explicitly */\n");
+	}
+  }
 	OUT("}\n");
 	OUT("\n");
 
 	p = MKID(expr->Identifier);
+	if(HIDE_INNER_DEFS) OUT("static ");
 	OUT("void\n");
 	OUT("%s_free(asn_TYPE_descriptor_t *td,\n", p);
 	INDENTED(
@@ -938,6 +1055,7 @@
 	OUT("\n");
 
 	p = MKID(expr->Identifier);
+	if(HIDE_INNER_DEFS) OUT("static ");
 	OUT("int\n");
 	OUT("%s_print(asn_TYPE_descriptor_t *td, const void *struct_ptr,\n", p);
 	INDENTED(
@@ -949,6 +1067,7 @@
 	OUT("\n");
 
 	p = MKID(expr->Identifier);
+	if(HIDE_INNER_DEFS) OUT("static ");
 	OUT("asn_dec_rval_t\n");
 	OUT("%s_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,\n", p);
 	INDENTED(
@@ -960,6 +1079,7 @@
 	OUT("\n");
 
 	p = MKID(expr->Identifier);
+	if(HIDE_INNER_DEFS) OUT("static ");
 	OUT("asn_enc_rval_t\n");
 	OUT("%s_encode_der(asn_TYPE_descriptor_t *td,\n", p);
 	INDENTED(
@@ -972,6 +1092,7 @@
 	OUT("\n");
 
 	p = MKID(expr->Identifier);
+	if(HIDE_INNER_DEFS) OUT("static ");
 	OUT("asn_dec_rval_t\n");
 	OUT("%s_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,\n", p);
 	INDENTED(
@@ -983,6 +1104,7 @@
 	OUT("\n");
 
 	p = MKID(expr->Identifier);
+	if(HIDE_INNER_DEFS) OUT("static ");
 	OUT("asn_enc_rval_t\n");
 	OUT("%s_encode_xer(asn_TYPE_descriptor_t *td, void *structure,\n", p);
 	INDENTED(
@@ -997,17 +1119,19 @@
 	REDIR(OT_FUNC_DECLS);
 
 	p = MKID_nr(expr->Identifier);
-	if(HIDE_INNER_DEFS) OUT("/* ");
-	OUT("extern asn_TYPE_descriptor_t asn_DEF_%s;", p);
-	if(HIDE_INNER_DEFS) OUT(" // (Use -fall-defs-global to expose) */");
-	OUT("\n");
-	OUT("asn_struct_free_f %s_free;\n", p);
-	OUT("asn_struct_print_f %s_print;\n", p);
-	OUT("asn_constr_check_f %s_constraint;\n", p);
-	OUT("ber_type_decoder_f %s_decode_ber;\n", p);
-	OUT("der_type_encoder_f %s_encode_der;\n", p);
-	OUT("xer_type_decoder_f %s_decode_xer;\n", p);
-	OUT("xer_type_encoder_f %s_encode_xer;\n", p);
+	if(HIDE_INNER_DEFS) {
+		OUT("/* extern asn_TYPE_descriptor_t asn_DEF_%s;"
+			"\t// (Use -fall-defs-global to expose) */\n", p);
+	} else {
+		OUT("extern asn_TYPE_descriptor_t asn_DEF_%s;\n", p);
+		OUT("asn_struct_free_f %s_free;\n", p);
+		OUT("asn_struct_print_f %s_print;\n", p);
+		OUT("asn_constr_check_f %s_constraint;\n", p);
+		OUT("ber_type_decoder_f %s_decode_ber;\n", p);
+		OUT("der_type_encoder_f %s_encode_der;\n", p);
+		OUT("xer_type_decoder_f %s_decode_xer;\n", p);
+		OUT("xer_type_encoder_f %s_encode_xer;\n", p);
+	}
 
 	REDIR(OT_TYPE_DECLS);
 
@@ -1103,7 +1227,7 @@
 	TQ_FOR(v, &(expr->members), next) {
 		if(v->expr_type == A1TC_EXTENSIBLE) {
 			/*
-			 * CANONICAL-XER mandates sorting
+			 * CXER mandates sorting
 			 * only for the root part.
 			 */
 			if(flags == FTE_CANONICAL_XER
@@ -1256,7 +1380,8 @@
 			OUT("%d, ", tag2el[i].el_no);
 			OUT("%d, ", tag2el[i].toff_first);
 			OUT("%d ", tag2el[i].toff_last);
-			OUT("}, /* %s at %d */\n",
+			OUT("}%s /* %s at %d */\n",
+				(i + 1 < tag2el_count) ? "," : "",
 				tag2el[i].from_expr->Identifier,
 				tag2el[i].from_expr->_lineno
 			);
@@ -1354,7 +1479,9 @@
 	topmost_parent = asn1f_find_terminal_type_ex(arg->asn, expr);
 	if(!topmost_parent) return 0;
 
-	if(!(topmost_parent->expr_type & ASN_CONSTR_MASK))
+	if(!(topmost_parent->expr_type & ASN_CONSTR_MASK)
+	&& !topmost_parent->expr_type == ASN_BASIC_INTEGER
+	&& !topmost_parent->expr_type == ASN_BASIC_ENUMERATED)
 		return 0;
 
 	TQ_FOR(v, &(topmost_parent->members), next) {
@@ -1372,6 +1499,7 @@
 	arg_t tmp_arg;
 	struct asn1p_type_tag_s outmost_tag_s;
 	struct asn1p_type_tag_s *outmost_tag;
+	int complex_contents;
 	char *p;
 
 	if(asn1f_fetch_outmost_tag(arg->asn,
@@ -1429,11 +1557,19 @@
 	} else {
 		OUT("0,\n");
 	}
+
+	complex_contents =
+		(expr->expr_type & ASN_CONSTR_MASK)
+		|| expr->expr_type == ASN_BASIC_ENUMERATED
+		|| (expr->expr_type == ASN_BASIC_INTEGER
+			&& expr_elements_count(arg, expr));
 	if(C99_MODE) OUT(".type = ");
-	if(expr->_anonymous_type && (expr->expr_type & ASN_CONSTR_MASK)) {
+	if(complex_contents
+		&& expr->_anonymous_type
+			&& !strcmp(expr->Identifier, "Member")) {
 		OUT("(void *)&asn_DEF_%s_Member,\n",
 			MKID_nr(arg->expr->Identifier));
-	} else if(expr->expr_type & ASN_CONSTR_MASK) {
+	} else if(complex_contents) {
 		OUT("(void *)&asn_DEF_%s,\n",
 			MKID_nr(expr->Identifier));
 	} else {
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
index b586d4d..67b45bf 100644
--- a/libasn1compiler/asn1c_constraint.c
+++ b/libasn1compiler/asn1c_constraint.c
@@ -95,7 +95,7 @@
 				OUT("double value;\n");
 				break;
 			case ASN_BASIC_BOOLEAN:
-				OUT("int value;\n");
+				OUT("BOOLEAN_t value;\n");
 				break;
 			default:
 				break;
@@ -557,7 +557,7 @@
 	case ASN_BASIC_INTEGER:
 	case ASN_BASIC_ENUMERATED:
 		if(arg->flags & A1C_USE_NATIVE_TYPES) {
-			OUT("value = *(const int *)sptr;\n");
+			OUT("value = *(const long *)sptr;\n");
 		} else {
 			if(r_value->el_count == 0
 			&& (
@@ -601,7 +601,7 @@
 		}
 		break;
 	case ASN_BASIC_BOOLEAN:
-		OUT("value = (*(const int *)sptr) ? 1 : 0;\n");
+		OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
 		break;
 	default:
 		WARNING("%s:%d: Value cannot be determined "
diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h
index 8f03221..5a0a1f2 100644
--- a/libasn1compiler/asn1c_out.h
+++ b/libasn1compiler/asn1c_out.h
@@ -75,6 +75,9 @@
 	OUT(fmt, ##args);					\
 	INDENT_LEVEL = _saved_indent;				\
 } while(0)
+#define	OUT_DEBUG(fmt, args...) do {				\
+		if(arg->flags & A1C_DEBUG) OUT(fmt, ##args);	\
+	} while(0)
 
 /* Generate #include line */
 #define	GEN_INCLUDE(filename)	do {				\
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index 6a4cdc7..ad7321c 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -134,10 +134,12 @@
  * Decode the chunk of XML text encoding INTEGER.
  */
 static ssize_t
-BOOLEAN__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
 	BOOLEAN_t *st = (BOOLEAN_t *)sptr;
 	char *p = (char *)chunk_buf;
 
+	(void)td;
+
 	if(chunk_size == 0) return -1;
 
 	if(p[0] == 0x3c /* '<' */) {
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index db289cb..de856d8 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
@@ -92,11 +93,15 @@
 	return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key);
 }
 
+static const asn_INTEGER_enum_map_t *INTEGER__map_value2enum(asn_INTEGER_specifics_t *specs, long value);
+static const asn_INTEGER_enum_map_t *INTEGER__map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop);
+
 /*
  * INTEGER specific human-readable output.
  */
 static ssize_t
-INTEGER__dump(const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
+INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	char scratch[32];	/* Enough for 64-bit integer */
 	uint8_t *buf = st->buf;
 	uint8_t *buf_end = st->buf + st->size;
@@ -105,10 +110,6 @@
 	char *p;
 	int ret;
 
-	if(st->size == 0) {
-		return (cb("0", 1, app_key) < 0) ? -1 : 1;
-	}
-
 	/*
 	 * Advance buf pointer until the start of the value's body.
 	 * This will make us able to process large integers using simple case,
@@ -126,12 +127,49 @@
 
 	/* Simple case: the integer size is small */
 	if((size_t)(buf_end - buf) <= sizeof(accum)) {
-		accum = (*buf & 0x80) ? -1 : 0;
-		for(; buf < buf_end; buf++)
-			accum = (accum << 8) | *buf;
-		ret = snprintf(scratch, sizeof(scratch), "%ld", accum);
-		assert(ret > 0 && ret < (int)sizeof(scratch));
-		return (cb(scratch, ret, app_key) < 0) ? -1 : ret;
+		const asn_INTEGER_enum_map_t *el;
+		size_t scrsize;
+		char *scr;
+
+		if(buf == buf_end) {
+			accum = 0;
+		} else {
+			accum = (*buf & 0x80) ? -1 : 0;
+			for(; buf < buf_end; buf++)
+				accum = (accum << 8) | *buf;
+		}
+
+		el = INTEGER__map_value2enum(specs, accum);
+		if(el) {
+			scrsize = el->enum_len + 32;
+			scr = (char *)alloca(scrsize);
+			if(plainOrXER == 0)
+				ret = snprintf(scr, scrsize,
+					"%ld (%s)", accum, el->enum_name);
+			else
+				ret = snprintf(scr, scrsize,
+					"<%s/>", el->enum_name);
+		} else if(plainOrXER && specs && specs->strict_enumeration) {
+			ASN_DEBUG("ASN.1 forbids dealing with "
+				"unknown value of ENUMERATED type");
+			errno = EPERM;
+			return -1;
+		} else {
+			scrsize = sizeof(scratch);
+			scr = scratch;
+			ret = snprintf(scr, scrsize, "%ld", accum);
+		}
+		assert(ret > 0 && (size_t)ret < scrsize);
+		return (cb(scr, ret, app_key) < 0) ? -1 : ret;
+	} else if(plainOrXER && specs && specs->strict_enumeration) {
+		/*
+		 * Here and earlier, we cannot encode the ENUMERATED values
+		 * if there is no corresponding identifier.
+		 */
+		ASN_DEBUG("ASN.1 forbids dealing with "
+			"unknown value of ENUMERATED type");
+		errno = EPERM;
+		return -1;
 	}
 
 	/* Output in the long xx:yy:zz... format */
@@ -171,22 +209,97 @@
 	if(!st && !st->buf)
 		ret = cb("<absent>", 8, app_key);
 	else
-		ret = INTEGER__dump(st, cb, app_key);
+		ret = INTEGER__dump(td, st, cb, app_key, 0);
 
 	return (ret < 0) ? -1 : 0;
 }
 
+struct e2v_key {
+	const char *start;
+	const char *stop;
+	asn_INTEGER_enum_map_t *vemap;
+	unsigned int *evmap;
+};
+static int
+INTEGER__compar_enum2value(const void *kp, const void *am) {
+	const struct e2v_key *key = (const struct e2v_key *)kp;
+	const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
+	const char *ptr, *end, *name;
+
+	/* Remap the element (sort by different criterion) */
+	el = key->vemap + key->evmap[el - key->vemap];
+
+	/* Compare strings */
+	for(ptr = key->start, end = key->stop, name = el->enum_name;
+			ptr < end; ptr++, name++) {
+		if(*ptr != *name)
+			return *(const unsigned char *)ptr
+				- *(const unsigned char *)name;
+	}
+	return name[0] ? -1 : 0;
+}
+
+static const asn_INTEGER_enum_map_t *
+INTEGER__map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) {
+	int count = specs ? specs->map_count : 0;
+	struct e2v_key key;
+	const char *lp;
+
+	if(!count) return NULL;
+
+	/* Guaranteed: assert(lstart < lstop); */
+	/* Figure out the tag name */
+	for(lstart++, lp = lstart; lp < lstop; lp++) {
+		switch(*lp) {
+		case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */
+		case 0x2f: /* '/' */ case 0x3e: /* '>' */
+			break;
+		default:
+			continue;
+		}
+		break;
+	}
+	if(lp == lstop) return NULL;	/* No tag found */
+	lstop = lp;
+
+	key.start = lstart;
+	key.stop = lstop;
+	key.vemap = specs->value2enum;
+	key.evmap = specs->enum2value;
+	return (asn_INTEGER_enum_map_t *)bsearch(&key, specs->value2enum, count,
+		sizeof(specs->value2enum[0]), INTEGER__compar_enum2value);
+}
+
+static int
+INTEGER__compar_value2enum(const void *kp, const void *am) {
+	long a = *(const long *)kp;
+	const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
+	long b = el->nat_value;
+	if(a < b) return -1;
+	else if(a == b) return 0;
+	else return 1;
+}
+
+static const asn_INTEGER_enum_map_t *
+INTEGER__map_value2enum(asn_INTEGER_specifics_t *specs, long value) {
+	int count = specs ? specs->map_count : 0;
+	if(!count) return 0;
+	return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum,
+		count, sizeof(specs->value2enum[0]),
+		INTEGER__compar_value2enum);
+}
+
 /*
  * Decode the chunk of XML text encoding INTEGER.
  */
 static ssize_t
-INTEGER__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
 	INTEGER_t *st = (INTEGER_t *)sptr;
 	long sign = 1;
 	long value;
-	char *lp;
-	char *lstart = (char *)chunk_buf;
-	char *lstop = lstart + chunk_size;
+	const char *lp;
+	const char *lstart = (const char *)chunk_buf;
+	const char *lstop = lstart + chunk_size;
 	enum {
 		ST_SKIPSPACE,
 		ST_WAITDIGITS,
@@ -194,8 +307,8 @@
 	} state = ST_SKIPSPACE;
 
 	/*
-	 * We may receive a tag here. But we aren't ready to deal with it yet.
-	 * So, just use stroul()-like code and serialize the result.
+	 * We may have received a tag here. It will be processed inline.
+	 * Use strtoul()-like code and serialize the result.
 	 */
 	for(value = 0, lp = lstart; lp < lstop; lp++) {
 		int lv = *lp;
@@ -242,6 +355,22 @@
 			}
 		    }
 			continue;
+		case 0x3c:	/* '<' */
+			if(state == ST_SKIPSPACE) {
+				const asn_INTEGER_enum_map_t *el;
+				el = INTEGER__map_enum2value(
+					(asn_INTEGER_specifics_t *)
+					td->specifics, lstart, lstop);
+				if(el) {
+					ASN_DEBUG("Found \"%s\" => %ld",
+						el->enum_name, el->nat_value);
+					state = ST_DIGITS;
+					value = el->nat_value;
+					break;
+				}
+				ASN_DEBUG("Unknown identifier for INTEGER");
+			}
+			return -1;
 		}
 		break;
 	}
@@ -280,7 +409,7 @@
 	if(!st && !st->buf)
 		_ASN_ENCODE_FAILED;
 
-	er.encoded = INTEGER__dump(st, cb, app_key);
+	er.encoded = INTEGER__dump(td, st, cb, app_key, 1);
 	if(er.encoded < 0) _ASN_ENCODE_FAILED;
 
 	return er;
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
index 45259e2..a1b555f 100644
--- a/skeletons/INTEGER.h
+++ b/skeletons/INTEGER.h
@@ -12,6 +12,22 @@
 
 extern asn_TYPE_descriptor_t asn_DEF_INTEGER;
 
+/* Map with <tag> to integer value association */
+typedef struct asn_INTEGER_enum_map_s {
+	long		 nat_value;	/* associated native integer value */
+	size_t		 enum_len;	/* strlen("tag") */
+	const char	*enum_name;	/* "tag" */
+} asn_INTEGER_enum_map_t;
+
+/* This type describes an enumeration for INTEGER and ENUMERATED types */
+typedef struct asn_INTEGER_specifics_s {
+	asn_INTEGER_enum_map_t *value2enum;	/* N -> "tag"; sorted by N */
+	unsigned int *enum2value;		/* "tag" => N; sorted by tag */
+	int map_count;				/* Elements in either map */
+	int extensible;				/* This map is extensible */
+	int strict_enumeration;			/* Enumeration set is fixed */
+} asn_INTEGER_specifics_t;
+
 asn_struct_print_f INTEGER_print;
 ber_type_decoder_f INTEGER_decode_ber;
 der_type_encoder_f INTEGER_encode_der;
diff --git a/skeletons/NULL.c b/skeletons/NULL.c
index 8cccc66..6a813fc 100644
--- a/skeletons/NULL.c
+++ b/skeletons/NULL.c
@@ -68,7 +68,8 @@
 
 
 static ssize_t
-NULL__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+NULL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+	(void)td;
 	(void)sptr;
 	if(xer_is_whitespace(chunk_buf, chunk_size))
 		return chunk_size;
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
index d6d1fd8..102372c 100644
--- a/skeletons/NativeInteger.c
+++ b/skeletons/NativeInteger.c
@@ -11,7 +11,6 @@
  */
 #include <asn_internal.h>
 #include <NativeInteger.h>
-#include <INTEGER.h>
 #include <assert.h>
 
 /*
@@ -45,17 +44,17 @@
 asn_dec_rval_t
 NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *td,
-	void **int_ptr, void *buf_ptr, size_t size, int tag_mode) {
-	int *Int = (int *)*int_ptr;
+	void **nint_ptr, void *buf_ptr, size_t size, int tag_mode) {
+	long *native = (long *)*nint_ptr;
 	asn_dec_rval_t rval;
 	ber_tlv_len_t length;
 
 	/*
 	 * If the structure is not there, allocate it.
 	 */
-	if(Int == NULL) {
-		Int = (int *)(*int_ptr = CALLOC(1, sizeof(*Int)));
-		if(Int == NULL) {
+	if(native == NULL) {
+		native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
+		if(native == NULL) {
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
 			return rval;
@@ -88,7 +87,7 @@
 
 	/*
 	 * ASN.1 encoded INTEGER: buf_ptr, length
-	 * Fill the Int, at the same time checking for overflow.
+	 * Fill the native, at the same time checking for overflow.
 	 * If overflow occured, return with RC_FAIL.
 	 */
 	{
@@ -103,15 +102,15 @@
 			return rval;
 		}
 
-		*Int = l;
+		*native = l;
 
 		/*
-		 * Note that int might be shorter than long.
+		 * Note that native integer size might be other than long.
 		 * This expression hopefully will be optimized away
 		 * by compiler.
 		 */
-		if(sizeof(int) != sizeof(long) && ((long)*Int != l)) {
-			*Int = 0;	/* Safe value */
+		if(sizeof(*native) != sizeof(long) && ((long)*native != l)) {
+			*native = 0;	/* Safe value */
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
 			return rval;
@@ -121,8 +120,8 @@
 	rval.code = RC_OK;
 	rval.consumed += length;
 
-	ASN_DEBUG("Took %ld/%ld bytes to encode %s (%d)",
-		(long)rval.consumed, (long)length, td->name, *Int);
+	ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)",
+		(long)rval.consumed, (long)length, td->name, (long)*native);
 
 	return rval;
 }
@@ -134,22 +133,22 @@
 NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	unsigned int Int = *(unsigned int *)ptr;	/* Disable sign ext. */
+	unsigned long native = *(unsigned long *)ptr;	/* Disable sign ext. */
 	asn_enc_rval_t erval;
 	INTEGER_t tmp;
 
 #ifdef	WORDS_BIGENDIAN		/* Opportunistic optimization */
 
-	tmp.buf = (uint8_t *)&Int;
-	tmp.size = sizeof(Int);
+	tmp.buf = (uint8_t *)&native;
+	tmp.size = sizeof(native);
 
 #else	/* Works even if WORDS_BIGENDIAN is not set where should've been */
-	uint8_t buf[sizeof(int)];
+	uint8_t buf[sizeof(native)];
 	uint8_t *p;
 
 	/* Prepare a fake INTEGER */
-	for(p = buf + sizeof(buf) - 1; p >= buf; p--, Int >>= 8)
-		*p = Int;
+	for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8)
+		*p = native;
 
 	tmp.buf = buf;
 	tmp.size = sizeof(buf);
@@ -174,12 +173,12 @@
 	asn_dec_rval_t rval;
 	INTEGER_t *st = 0;
 	void *st_ptr = (void *)&st;
-	int *Int = (int *)*sptr;
+	long *native = (long *)*sptr;
 
-	if(!Int) {
+	if(!native) {
 		*sptr = CALLOC(1, sizeof(int));
-		Int = (int *)*sptr;
-		if(!Int) {
+		native = (long *)*sptr;
+		if(!native) {
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
 			return rval;
@@ -194,17 +193,23 @@
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
 		} else {
-			*Int = l;
+			*native = l;
 
-			/* int might be shorter than long */
-			if(sizeof(int) != sizeof(long) && ((long)*Int != l)) {
-				*Int = 0;	/* Safe value */
+			/* Native type might be shorter than long */
+			if(sizeof(*native) != sizeof(long)
+					&& ((long)*native != l)) {
+				*native = 0;	/* Safe value */
 				rval.code = RC_FAIL;
 				rval.consumed = 0;
 				return rval;
 			}
 		}
 	} else {
+		/*
+		 * Cannot restart from the middle;
+		 * there is no place to save state in the native type.
+		 * Request a continuation from the very beginning.
+		 */
 		rval.consumed = 0;
 	}
 	asn_DEF_INTEGER.free_struct(&asn_DEF_INTEGER, st, 0);
@@ -218,14 +223,14 @@
 		asn_app_consume_bytes_f *cb, void *app_key) {
 	char scratch[32];	/* Enough for 64-bit int */
 	asn_enc_rval_t er;
-	const int *Int = (const int *)sptr;
+	const long *native = (const long *)sptr;
 
 	(void)ilevel;
 	(void)flags;
 
-	if(!Int) _ASN_ENCODE_FAILED;
+	if(!native) _ASN_ENCODE_FAILED;
 
-	er.encoded = snprintf(scratch, sizeof(scratch), "%d", *Int);
+	er.encoded = snprintf(scratch, sizeof(scratch), "%ld", *native);
 	if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch)
 		|| cb(scratch, er.encoded, app_key) < 0)
 		_ASN_ENCODE_FAILED;
@@ -239,16 +244,16 @@
 int
 NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	const int *Int = (const int *)sptr;
+	const long *native = (const long *)sptr;
 	char scratch[32];	/* Enough for 64-bit int */
 	int ret;
 
 	(void)td;	/* Unused argument */
 	(void)ilevel;	/* Unused argument */
 
-	if(Int) {
-		ret = snprintf(scratch, sizeof(scratch), "%d", *Int);
-		assert(ret > 0 && ret < (int)sizeof(scratch));
+	if(native) {
+		ret = snprintf(scratch, sizeof(scratch), "%ld", *native);
+		assert(ret > 0 && (size_t)ret < sizeof(scratch));
 		return (cb(scratch, ret, app_key) < 0) ? -1 : 0;
 	} else {
 		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
diff --git a/skeletons/NativeInteger.h b/skeletons/NativeInteger.h
index 777f8e6..b66d29a 100644
--- a/skeletons/NativeInteger.h
+++ b/skeletons/NativeInteger.h
@@ -13,6 +13,7 @@
 #define	_NativeInteger_H_
 
 #include <asn_application.h>
+#include <INTEGER.h>
 
 extern asn_TYPE_descriptor_t asn_DEF_NativeInteger;
 
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index 3f2454c..4128e76 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -264,7 +264,7 @@
 }
 
 static ssize_t
-OBJECT_IDENTIFIER__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
 	OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
 	char *endptr;
 	long s_arcs[10];
@@ -272,6 +272,8 @@
 	int arcs_count;
 	int ret;
 
+	(void)td;
+
 	arcs_count = OBJECT_IDENTIFIER_parse_arcs(
 		(const char *)chunk_buf, chunk_size, arcs, 10, &endptr);
 	if(arcs_count <= 0)
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index bf03db3..717db89 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -258,13 +258,15 @@
  * Decode the chunk of XML text encoding REAL.
  */
 static ssize_t
-REAL__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+REAL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
 	REAL_t *st = (REAL_t *)sptr;
 	double value;
 	char *xerdata = (char *)chunk_buf;
 	char *endptr = 0;
 	char *b;
 
+	(void)td;
+
 	if(!chunk_size) return -1;
 
 	/*
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index d36d1f7..b0f6f64 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -87,7 +87,7 @@
 }
 
 static ssize_t
-RELATIVE_OID__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+RELATIVE_OID__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
 	RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr;
 	char *endptr;
 	long s_arcs[6];
@@ -95,6 +95,8 @@
 	int arcs_count;
 	int ret;
 
+	(void)td;
+
 	arcs_count = OBJECT_IDENTIFIER_parse_arcs(
 		(const char *)chunk_buf, chunk_size,
 		arcs, 6, &endptr);
diff --git a/skeletons/asn_codecs_prim.c b/skeletons/asn_codecs_prim.c
index 03f107b..5fe09ad 100644
--- a/skeletons/asn_codecs_prim.c
+++ b/skeletons/asn_codecs_prim.c
@@ -137,9 +137,10 @@
  * Local internal type passed around as an argument.
  */
 struct xdp_arg_s {
+	asn_TYPE_descriptor_t *type_descriptor;
 	void *struct_key;
-	ssize_t (*prim_body_decode)(void *struct_key,
-		void *chunk_buf, size_t chunk_size);
+	ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
+		void *struct_key, void *chunk_buf, size_t chunk_size);
 	int decoded_something;
 	int want_more;
 };
@@ -159,7 +160,8 @@
 		return -1;
 	}
 
-	decoded = arg->prim_body_decode(arg->struct_key, chunk_buf, chunk_size);
+	decoded = arg->prim_body_decode(arg->type_descriptor,
+		arg->struct_key, chunk_buf, chunk_size);
 	if(decoded < 0) {
 		return -1;
 	} else {
@@ -196,7 +198,8 @@
 		return -1;
 	}
 
-	decoded = arg->prim_body_decode(arg->struct_key, chunk_buf, chunk_size);
+	decoded = arg->prim_body_decode(arg->type_descriptor,
+		arg->struct_key, chunk_buf, chunk_size);
 	if(decoded < 0) {
 		return -1;
 	} else {
@@ -213,8 +216,8 @@
 	size_t struct_size,
 	const char *opt_mname,
 	void *buf_ptr, size_t size,
-	ssize_t (*prim_body_decode)(void *struct_key,
-		void *chunk_buf, size_t chunk_size)
+	ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
+		void *struct_key, void *chunk_buf, size_t chunk_size)
 ) {
 	const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
 	asn_struct_ctx_t s_ctx;
@@ -235,6 +238,7 @@
 	}
 
 	memset(&s_ctx, 0, sizeof(s_ctx));
+	s_arg.type_descriptor = td;
 	s_arg.struct_key = *sptr;
 	s_arg.prim_body_decode = prim_body_decode;
 	s_arg.decoded_something = 0;
@@ -248,7 +252,8 @@
 		if(!s_arg.decoded_something) {
 			char ch;
 			/* Opportunity has come and gone. Where's the result? */
-			if(prim_body_decode(s_arg.struct_key, &ch, 0) != 0) {
+			if(prim_body_decode(s_arg.type_descriptor,
+				s_arg.struct_key, &ch, 0) != 0) {
 				/*
 				 * This decoder does not like empty stuff.
 				 */
diff --git a/skeletons/asn_codecs_prim.h b/skeletons/asn_codecs_prim.h
index c235f35..7a6723d 100644
--- a/skeletons/asn_codecs_prim.h
+++ b/skeletons/asn_codecs_prim.h
@@ -25,8 +25,8 @@
 	void **struct_ptr, size_t struct_size,
 	const char *opt_mname,
 	void *buf_ptr, size_t size,
-	ssize_t (*prim_body_decode)(void *struct_ptr,
-		void *chunk_buf, size_t chunk_size)
+	ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
+		void *struct_ptr, void *chunk_buf, size_t chunk_size)
 	);
 
 #endif	/* ASN_CODECS_PRIM_H */
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index 2ee3b81..4099186 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -788,7 +788,8 @@
 			break;
 		}
 
-		ASN_DEBUG("Unexpected XML tag in SET");
+		ASN_DEBUG("Unexpected XML tag in SET, expected \"%s\"",
+			xml_tag);
 		break;
 	}
 
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index 931aab2..c6ec6af 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -641,7 +641,7 @@
 	int ilevel, enum xer_encoder_flags_e flags,
 		asn_app_consume_bytes_f *cb, void *app_key) {
 	asn_enc_rval_t er;
-	asn_SET_OF_specifics_t *specs=(asn_SET_OF_specifics_t *)td->specifics;
+	asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics;
 	asn_TYPE_member_t *element = td->elements;
 	A_SET_OF(void) *list;
 	const char *mname = specs->as_XMLValueList
@@ -684,6 +684,8 @@
 			_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
 		}
 
+		if(!xcan && specs->as_XMLValueList)
+			_i_ASN_TEXT_INDENT(1, ilevel + 1);
 		tmper = element->type->xer_encoder(element->type, memb_ptr,
 				ilevel + 1, flags, cb, app_key);
 		if(tmper.encoded == -1) {
@@ -695,7 +697,6 @@
 			const char *name = (*element->name)
 				? element->name : element->type->xml_tag;
 			size_t len = strlen(name);
-			if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel + 1);
 			_ASN_CALLBACK3("<", 1, name, len, "/>", 2);
 		}
 
diff --git a/skeletons/xer_decoder.c b/skeletons/xer_decoder.c
index 82c084e..0de6e33 100644
--- a/skeletons/xer_decoder.c
+++ b/skeletons/xer_decoder.c
@@ -271,7 +271,6 @@
 			ctx->phase = 2;	/* Phase out */
 			RETURN(RC_OK);
 		case XCT_UNKNOWN_BO:
-			if(!ctx->phase) break;
 			/*
 			 * Certain tags in the body may be expected.
 			 */
@@ -280,6 +279,12 @@
 					buf_ptr, ch_size) == 0) {
 				/* Tag's processed fine */
 				ADVANCE(ch_size);
+				if(!ctx->phase) {
+					/* We are not expecting
+					 * the closing tag anymore. */
+					ctx->phase = 2;	/* Phase out */
+					RETURN(RC_OK);
+				}
 				continue;
 			}
 			/* Fall through */