XER support

diff --git a/skeletons/ANY.c b/skeletons/ANY.c
index d501ca1..4c51963 100644
--- a/skeletons/ANY.c
+++ b/skeletons/ANY.c
@@ -14,12 +14,13 @@
 };
 asn_TYPE_descriptor_t asn_DEF_ANY = {
 	"ANY",
+	"ANY",
 	OCTET_STRING_free,
 	OCTET_STRING_print,
 	asn_generic_no_constraint,
 	OCTET_STRING_decode_ber,
 	OCTET_STRING_encode_der,
-	0,				/* Not implemented yet */
+	OCTET_STRING_decode_xer_hex,
 	ANY_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	0, 0, 0, 0,
@@ -111,7 +112,7 @@
 
 int
 ANY_to_type(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) {
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	void *newst = 0;
 
 	if(!st || !td || !struct_ptr) {
diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c
index 6c582a0..e21594a 100644
--- a/skeletons/BIT_STRING.c
+++ b/skeletons/BIT_STRING.c
@@ -19,12 +19,13 @@
 };
 asn_TYPE_descriptor_t asn_DEF_BIT_STRING = {
 	"BIT STRING",
+	"BIT_STRING",
 	OCTET_STRING_free,         /* Implemented in terms of OCTET STRING */
 	BIT_STRING_print,
 	BIT_STRING_constraint,
 	OCTET_STRING_decode_ber,   /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,   /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
+	OCTET_STRING_decode_xer_binary,
 	BIT_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_BIT_STRING_tags,
diff --git a/skeletons/BMPString.c b/skeletons/BMPString.c
index e03d334..cca6e3c 100644
--- a/skeletons/BMPString.c
+++ b/skeletons/BMPString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_BMPString = {
 	"BMPString",
+	"BMPString",
 	OCTET_STRING_free,          /* Implemented in terms of OCTET STRING */
 	BMPString_print,
 	asn_generic_no_constraint,  /* No constraint by default */
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
 	0,				/* Not implemented yet */
-	BMPString_encode_xer,		/* Conver to UTF8 */
+	BMPString_encode_xer,		/* Convert to UTF8 */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_BMPString_tags,
 	sizeof(asn_DEF_BMPString_tags)
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index 43b890f..61eb58f 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -13,6 +13,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_BOOLEAN = {
 	"BOOLEAN",
+	"BOOLEAN",
 	BOOLEAN_free,
 	BOOLEAN_print,
 	asn_generic_no_constraint,
@@ -32,13 +33,13 @@
 /*
  * Decode BOOLEAN type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 BOOLEAN_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 		asn_TYPE_descriptor_t *td,
 		void **bool_value, void *buf_ptr, size_t size,
 		int tag_mode) {
 	BOOLEAN_t *st = (BOOLEAN_t *)*bool_value;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	ber_tlv_len_t length;
 	ber_tlv_len_t lidx;
 
diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c
index 13d7e05..83a71d0 100644
--- a/skeletons/ENUMERATED.c
+++ b/skeletons/ENUMERATED.c
@@ -14,6 +14,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_ENUMERATED = {
 	"ENUMERATED",
+	"ENUMERATED",
 	ASN__PRIMITIVE_TYPE_free,
 	INTEGER_print,			/* Implemented in terms of INTEGER */
 	asn_generic_no_constraint,
diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c
index f846c02..e4ea6f8 100644
--- a/skeletons/GeneralString.c
+++ b/skeletons/GeneralString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_GeneralString = {
 	"GeneralString",
+	"GeneralString",
 	OCTET_STRING_free,
 	OCTET_STRING_print,         /* non-ascii string */
 	asn_generic_unknown_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_hex,
+	OCTET_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GeneralString_tags,
 	sizeof(asn_DEF_GeneralString_tags)
diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c
index 9d5fe4a..2a28d73 100644
--- a/skeletons/GeneralizedTime.c
+++ b/skeletons/GeneralizedTime.c
@@ -123,12 +123,13 @@
 };
 asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = {
 	"GeneralizedTime",
+	"GeneralizedTime",
 	OCTET_STRING_free,
 	GeneralizedTime_print,
 	GeneralizedTime_constraint, /* Check validity of time */
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	GeneralizedTime_encode_der, /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
+	GeneralizedTime_encode_der,
+	OCTET_STRING_decode_xer_utf8,
 	GeneralizedTime_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GeneralizedTime_tags,
@@ -231,7 +232,7 @@
 		sptr = &st;
 	}
 
-	return OCTET_STRING_encode_xer_ascii(td, sptr, ilevel, flags,
+	return OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags,
 		cb, app_key);
 }
 
diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c
index 67442fc..c5d4a30 100644
--- a/skeletons/GraphicString.c
+++ b/skeletons/GraphicString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_GraphicString = {
 	"GraphicString",
+	"GraphicString",
 	OCTET_STRING_free,
 	OCTET_STRING_print,         /* non-ascii string */
 	asn_generic_unknown_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_hex,
+	OCTET_STRING_encode_xer,	/* Can't expect it to be ASCII/UTF8 */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GraphicString_tags,
 	sizeof(asn_DEF_GraphicString_tags)
diff --git a/skeletons/IA5String.c b/skeletons/IA5String.c
index 42eb17c..32a7a7f 100644
--- a/skeletons/IA5String.c
+++ b/skeletons/IA5String.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_IA5String = {
 	"IA5String",
+	"IA5String",
 	OCTET_STRING_free,
-	OCTET_STRING_print_ascii,  /* ASCII subset */
+	OCTET_STRING_print_utf8,	/* ASCII subset */
 	IA5String_constraint,       /* Constraint on the alphabet */
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_IA5String_tags,
 	sizeof(asn_DEF_IA5String_tags)
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index f485bac..fbd9272 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -16,6 +16,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_INTEGER = {
 	"INTEGER",
+	"INTEGER",
 	ASN__PRIMITIVE_TYPE_free,
 	INTEGER_print,
 	asn_generic_no_constraint,
diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c
index 751139d..035734b 100644
--- a/skeletons/ISO646String.c
+++ b/skeletons/ISO646String.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_ISO646String = {
 	"ISO646String",
+	"ISO646String",
 	OCTET_STRING_free,
-	OCTET_STRING_print_ascii,   /* ASCII subset */
+	OCTET_STRING_print_utf8,	/* ASCII subset */
 	VisibleString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_ISO646String_tags,
 	sizeof(asn_DEF_ISO646String_tags)
diff --git a/skeletons/NULL.c b/skeletons/NULL.c
index 7375d0f..3b41be2 100644
--- a/skeletons/NULL.c
+++ b/skeletons/NULL.c
@@ -14,6 +14,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_NULL = {
 	"NULL",
+	"NULL",
 	BOOLEAN_free,
 	NULL_print,
 	asn_generic_no_constraint,
diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c
index 19c7559..191afb7 100644
--- a/skeletons/NativeEnumerated.c
+++ b/skeletons/NativeEnumerated.c
@@ -20,6 +20,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = {
 	"ENUMERATED",			/* The ASN.1 type is still ENUMERATED */
+	"ENUMERATED",
 	NativeInteger_free,
 	NativeInteger_print,
 	asn_generic_no_constraint,
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
index ae71c04..695b963 100644
--- a/skeletons/NativeInteger.c
+++ b/skeletons/NativeInteger.c
@@ -22,6 +22,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_NativeInteger = {
 	"INTEGER",			/* The ASN.1 type is still INTEGER */
+	"INTEGER",
 	NativeInteger_free,
 	NativeInteger_print,
 	asn_generic_no_constraint,
@@ -41,12 +42,12 @@
 /*
  * Decode INTEGER type.
  */
-ber_dec_rval_t
+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;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	ber_tlv_len_t length;
 
 	/*
diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c
index 83b1676..b8a4926 100644
--- a/skeletons/NativeReal.c
+++ b/skeletons/NativeReal.c
@@ -22,6 +22,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_NativeReal = {
 	"REAL",			/* The ASN.1 type is still REAL */
+	"REAL",
 	NativeReal_free,
 	NativeReal_print,
 	asn_generic_no_constraint,
@@ -41,12 +42,12 @@
 /*
  * Decode REAL type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 NativeReal_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *td,
 	void **dbl_ptr, void *buf_ptr, size_t size, int tag_mode) {
 	double *Dbl = (double *)*dbl_ptr;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	ber_tlv_len_t length;
 
 	/*
diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c
index 7d47198..dbff6e2 100644
--- a/skeletons/NumericString.c
+++ b/skeletons/NumericString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_NumericString = {
 	"NumericString",
+	"NumericString",
 	OCTET_STRING_free,
-	OCTET_STRING_print_ascii,   /* ASCII subset */
+	OCTET_STRING_print_utf8,   /* ASCII subset */
 	NumericString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NumericString_tags,
 	sizeof(asn_DEF_NumericString_tags)
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index db2fd7a..a08f18a 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -16,6 +16,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
 	"OBJECT IDENTIFIER",
+	"OBJECT_IDENTIFIER",
 	ASN__PRIMITIVE_TYPE_free,
 	OBJECT_IDENTIFIER_print,
 	OBJECT_IDENTIFIER_constraint,
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
index 66f3a4b..16d3a89 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -20,13 +20,14 @@
 	0
 };
 asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
-	"OCTET STRING",
+	"OCTET STRING",		/* Canonical name */
+	"OCTET_STRING",		/* XML tag name */
 	OCTET_STRING_free,
 	OCTET_STRING_print,	/* non-ascii stuff, generally */
 	asn_generic_no_constraint,
 	OCTET_STRING_decode_ber,
 	OCTET_STRING_encode_der,
-	0,				/* Not implemented yet */
+	OCTET_STRING_decode_xer_hex,
 	OCTET_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_OCTET_STRING_tags,
@@ -160,14 +161,15 @@
 /*
  * Decode OCTET STRING type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *td,
 	void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
 	asn_OCTET_STRING_specifics_t *specs = td->specifics
-				? td->specifics : &asn_DEF_OCTET_STRING_specs;
+				? (asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_DEF_OCTET_STRING_specs;
 	BIT_STRING_t *st = (BIT_STRING_t *)*os_structure;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	asn_struct_ctx_t *ctx;
 	ssize_t consumed_myself = 0;
 	struct _stack *stck;		/* Expectations stack structure */
@@ -511,7 +513,8 @@
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	asn_enc_rval_t er;
 	asn_OCTET_STRING_specifics_t *specs = td->specifics
-				? td->specifics : &asn_DEF_OCTET_STRING_specs;
+				? (asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_DEF_OCTET_STRING_specs;
 	BIT_STRING_t *st = (BIT_STRING_t *)sptr;
 	OS_type_e type_variant = (OS_type_e)specs->subvariant;
 	int fix_last_byte = 0;
@@ -683,8 +686,48 @@
 	OSXET("\046\147\164\073"),	/* > */
 };
 
+static int
+OS__check_escaped_control_char(void *buf, int size) {
+	size_t i;
+	/*
+	 * Inefficient algorithm which translates the escape sequences
+	 * defined above into characters. Returns -1 if not found.
+	 * TODO: replace by a faster algorithm (bsearch(), hash or
+	 * nested table lookups).
+	 */
+	for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {
+		struct OCTET_STRING__xer_escape_table_s *el;
+		el = &OCTET_STRING__xer_escape_table[i];
+		if(el->size == size && memcmp(buf, el->string, size) == 0)
+			return i;
+	}
+	return -1;
+}
+
+static int
+OCTET_STRING__handle_control_chars(void *struct_ptr, void *chunk_buf, size_t chunk_size) {
+	/*
+	 * This might be one of the escape sequences
+	 * for control characters. Check it out.
+	 * #11.15.5
+	 */
+	int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size);
+	if(control_char >= 0) {
+		OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr;
+		void *p = REALLOC(st->buf, st->size + 2);
+		if(p) {
+			st->buf = (uint8_t *)p;
+			st->buf[st->size++] = control_char;
+			st->buf[st->size] = '\0';	/* nul-termination */
+			return 0;
+		}
+	}
+	
+	return -1;	/* No, it's not */
+}
+
 asn_enc_rval_t
-OCTET_STRING_encode_xer_ascii(asn_TYPE_descriptor_t *td, void *sptr,
+OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr,
 	int ilevel, enum xer_encoder_flags_e flags,
 		asn_app_consume_bytes_f *cb, void *app_key) {
 	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
@@ -728,6 +771,396 @@
 	return er;
 }
 
+/*
+ * Convert from hexadecimal format (cstring): "AB CD EF"
+ */
+static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, void *chunk_buf, size_t chunk_size, int have_more) {
+	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+	char *chunk_stop = (char *)chunk_buf;
+	char *p = chunk_stop;
+	char *pend = p + chunk_size;
+	unsigned int clv = 0;
+	int half = 0;	/* Half bit */
+	uint8_t *buf;
+
+	/* Reallocate buffer according to high cap estimation */
+	ssize_t _ns = st->size + (chunk_size + 1) / 2;
+	void *nptr = REALLOC(st->buf, _ns + 1);
+	if(!nptr) return -1;
+	st->buf = (uint8_t *)nptr;
+	buf = st->buf + st->size;
+
+	/*
+	 * If something like " a b c " appears here, the " a b":3 will be
+	 * converted, and the rest skipped. That is, unless buf_size is greater
+	 * than chunk_size, then it'll be equivalent to "ABC0".
+	 */
+	for(; p < pend; p++) {
+		int ch = *(unsigned char *)p;
+		switch(ch) {
+		case 0x09: case 0x0a: case 0x0c: case 0x0d:
+		case 0x20:
+			/* Ignore whitespace */
+			continue;
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
+			clv = (clv << 4) + (ch - 0x30);
+			break;
+		case 0x41: case 0x42: case 0x43:	/* ABC */
+		case 0x44: case 0x45: case 0x46:	/* DEF */
+			clv = (clv << 4) + (ch - (0x41 + 10));
+			break;
+		case 0x61: case 0x62: case 0x63:	/* abc */
+		case 0x64: case 0x65: case 0x66:	/* def */
+			clv = (clv << 4) + (ch - (0x61 + 10));
+			break;
+		default:
+			*buf = 0;	/* JIC */
+			return -1;
+		}
+		if(half++) {
+			half = 0;
+			*buf++ = clv;
+			chunk_stop = p + 1;
+		}
+	}
+
+	/*
+	 * Check partial decoding.
+	 */
+	if(half) {
+		if(have_more) {
+			/*
+			 * Partial specification is fine,
+			 * because no more more PXER_TEXT data is available.
+			 */
+			*buf++ = clv << 4;
+			chunk_stop = p;
+		}
+	} else {
+		chunk_stop = p;
+	}
+
+	st->size = buf - st->buf;	/* Adjust the buffer size */
+	assert(st->size <= _ns);
+	st->buf[st->size] = 0;		/* Courtesy termination */
+
+	return (chunk_stop - (char *)chunk_buf);	/* Converted size */
+}
+
+/*
+ * Convert from binary format: "00101011101"
+ */
+static ssize_t OCTET_STRING__convert_binary(void *sptr, void *chunk_buf, size_t chunk_size, int have_more) {
+	BIT_STRING_t *st = (BIT_STRING_t *)sptr;
+	char *p = (char *)chunk_buf;
+	char *pend = p + chunk_size;
+	int bits_unused = st->bits_unused & 0x7;
+	uint8_t *buf;
+
+	/* Reallocate buffer according to high cap estimation */
+	ssize_t _ns = st->size + (chunk_size + 7) / 8;
+	void *nptr = REALLOC(st->buf, _ns + 1);
+	if(!nptr) return -1;
+	st->buf = (uint8_t *)nptr;
+	buf = st->buf + st->size;
+
+	(void)have_more;
+
+	if(bits_unused == 0)
+		bits_unused = 8;
+	else if(st->size)
+		buf--;
+
+	/*
+	 * Convert series of 0 and 1 into the octet string.
+	 */
+	for(; p < pend; p++) {
+		int ch = *(unsigned char *)p;
+		switch(ch) {
+		case 0x09: case 0x0a: case 0x0c: case 0x0d:
+		case 0x20:
+			/* Ignore whitespace */
+			break;
+		case 0x30:
+		case 0x31:
+			if(bits_unused-- <= 0) {
+				*++buf = 0;	/* Clean the cell */
+				bits_unused = 7;
+			}
+			*buf |= (ch&1) << bits_unused;
+			break;
+		default:
+			st->bits_unused = bits_unused;
+			return -1;
+		}
+	}
+
+	if(bits_unused == 8) {
+		st->size = buf - st->buf;
+		st->bits_unused = 0;
+	} else {
+		st->size = buf - st->buf + 1;
+		st->bits_unused = bits_unused;
+	}
+
+	assert(st->size <= _ns);
+	st->buf[st->size] = 0;		/* Courtesy termination */
+
+	return chunk_size;	/* Converted in full */
+}
+
+/*
+ * Something like strtod(), but with stricter rules.
+ */
+static int
+OS__strtoent(int base, char *buf, char *end, long *return_value) {
+	long val = 0;
+	char *p;
+
+	for(p = buf; p < end; p++) {
+		int ch = *p;
+		if((val * base + base) < 0) return -1;	/* Strange huge value */
+		switch(ch) {
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
+			val = val * base + (ch - 0x30);
+			break;
+		case 0x41: case 0x42: case 0x43:	/* ABC */
+		case 0x44: case 0x45: case 0x46:	/* DEF */
+			val = val * base + (ch - (0x41 + 10));
+			break;
+		case 0x61: case 0x62: case 0x63:	/* abc */
+		case 0x64: case 0x65: case 0x66:	/* def */
+			val = val * base + (ch - (0x61 + 10));
+			break;
+		case 0x3b:	/* ';' */
+			*return_value = val;
+			return (p - buf) + 1;
+		default:
+			return -1;	/* Character set error */
+		}
+	}
+
+	/* Do not return value. It's an error we're talking about here. */
+	return (p - buf);
+}
+
+/*
+ * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"
+ */
+static ssize_t OCTET_STRING__convert_entrefs(void *sptr, void *chunk_buf, size_t chunk_size, int have_more) {
+	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+	char *p = (char *)chunk_buf;
+	char *pend = p + chunk_size;
+	uint8_t *buf;
+
+	/* Reallocate buffer */
+	ssize_t _ns = st->size + chunk_size;
+	void *nptr = REALLOC(st->buf, _ns + 1);
+	if(!nptr) return -1;
+	st->buf = (uint8_t *)nptr;
+	buf = st->buf + st->size;
+
+	/*
+	 * Convert series of 0 and 1 into the octet string.
+	 */
+	for(; p < pend; p++) {
+		int ch = *(unsigned char *)p;
+		int len;	/* Length of the rest of the chunk */
+
+		if(ch != 0x26 /* '&' */) {
+			*buf++ = ch;
+			continue;	/* That was easy... */
+		}
+
+		/*
+		 * Process entity reference.
+		 */
+		len = chunk_size - (p - (char *)chunk_buf);
+		if(len == 1 /* "&" */) goto want_more;
+		if(p[1] == 0x23 /* '#' */) {
+			char *pval;	/* Pointer to start of digits */
+			long val;	/* Entity reference value */
+			int base;
+
+			if(len == 2 /* "&#" */) goto want_more;
+			if(p[2] == 0x78 /* 'x' */)
+				pval = p + 3, base = 16;
+			else
+				pval = p + 2, base = 10;
+			len = OS__strtoent(base, pval, p + len, &val);
+			if(len == -1) {
+				/* Invalid charset. Just copy verbatim. */
+				*buf++ = ch;
+				continue;
+			}
+			if(!len || pval[len-1] != 0x3b) goto want_more;
+			assert(val > 0);
+			p += (pval - p) + len - 1; /* Advance past entref */
+
+			if(val < 0x80) {
+				*buf++ = (char)val;
+			} else if(val < 0x800) {
+				*buf++ = 0xc0 | ((val >> 6));
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else if(val < 0x10000) {
+				*buf++ = 0xe0 | ((val >> 12));
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else if(val < 0x200000) {
+				*buf++ = 0xf0 | ((val >> 18));
+				*buf++ = 0x80 | ((val >> 12) & 0x3f);
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else if(val < 0x4000000) {
+				*buf++ = 0xf8 | ((val >> 24));
+				*buf++ = 0x80 | ((val >> 18) & 0x3f);
+				*buf++ = 0x80 | ((val >> 12) & 0x3f);
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else {
+				*buf++ = 0xfc | ((val >> 30) & 0x1);
+				*buf++ = 0x80 | ((val >> 24) & 0x3f);
+				*buf++ = 0x80 | ((val >> 18) & 0x3f);
+				*buf++ = 0x80 | ((val >> 12) & 0x3f);
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			}
+		} else {
+			/*
+			 * Ugly, limited parsing of &amp; &gt; &lt;
+			 */
+			char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);
+			if(!sc) goto want_more;
+			if((sc - p) == 4
+				&& p[1] == 0x61	/* 'a' */
+				&& p[2] == 0x6d	/* 'm' */
+				&& p[3] == 0x70	/* 'p' */) {
+				*buf++ = 0x26;
+				p = sc;
+				continue;
+			}
+			if((sc - p) == 3) {
+				if(p[1] == 0x6c) {
+					*buf = 0x3c;	/* '<' */
+				} else if(p[1] == 0x67) {
+					*buf = 0x3e;	/* '>' */
+				} else {
+					/* Unsupported entity reference */
+					*buf++ = ch;
+					continue;
+				}
+				if(p[2] != 0x74) {
+					/* Unsupported entity reference */
+					*buf++ = ch;
+					continue;
+				}
+				buf++;
+				p = sc;
+				continue;
+			}
+			/* Unsupported entity reference */
+			*buf++ = ch;
+		}
+
+		continue;
+	want_more:
+		if(have_more) {
+			/*
+			 * We know that no more data (of the same type)
+			 * is coming. Copy the rest verbatim.
+			 */
+			*buf++ = ch;
+			continue;
+		}
+		*buf = 0;	/* JIC */
+		/* Processing stalled: need more data */
+		return (p - (char *)chunk_buf);
+	}
+
+	st->size = buf - st->buf;
+	assert(st->size <= _ns);
+	st->buf[st->size] = 0;		/* Courtesy termination */
+
+	return chunk_size;	/* Converted in full */
+}
+
+/*
+ * Decode OCTET STRING from the XML element's body.
+ */
+static asn_dec_rval_t
+OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, void **sptr,
+	const char *opt_mname, void *buf_ptr, size_t size,
+	int (*opt_unexpected_tag_decoder)
+		(void *struct_ptr, void *chunk_buf, size_t chunk_size),
+	ssize_t (*body_receiver)
+		(void *struct_ptr, void *chunk_buf, size_t chunk_size,
+			int have_more)
+) {
+	asn_OCTET_STRING_specifics_t *specs = td->specifics
+				? (asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_DEF_OCTET_STRING_specs;
+	const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
+	asn_struct_ctx_t *ctx;		/* Per-structure parser context */
+
+	/*
+	 * Create the string if does not exist.
+	 */
+	if(!*sptr) {
+		*sptr = CALLOC(1, specs->struct_size);
+		if(*sptr == NULL) {
+			asn_dec_rval_t rval;
+			rval.code = RC_FAIL;
+			rval.consumed = 0;
+			return rval;
+		}
+	}
+
+	/* Restore parsing context */
+	ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);
+
+	return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,
+		buf_ptr, size, opt_unexpected_tag_decoder, body_receiver);
+}
+
+/*
+ * Decode OCTET STRING from the hexadecimal data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, void **sptr,
+		const char *opt_mname, void *buf_ptr, size_t size) {
+	return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+		buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal);
+}
+
+/*
+ * Decode OCTET STRING from the binary (0/1) data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, void **sptr,
+		const char *opt_mname, void *buf_ptr, size_t size) {
+	return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+		buf_ptr, size, 0, OCTET_STRING__convert_binary);
+}
+
+/*
+ * Decode OCTET STRING from the string (ASCII/UTF-8) data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, void **sptr,
+		const char *opt_mname, void *buf_ptr, size_t size) {
+	return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+		buf_ptr, size,
+		OCTET_STRING__handle_control_chars,
+		OCTET_STRING__convert_entrefs);
+}
+
+
 int
 OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
@@ -770,7 +1203,7 @@
 }
 
 int
-OCTET_STRING_print_ascii(asn_TYPE_descriptor_t *td, const void *sptr,
+OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr,
 		int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
 	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
 
@@ -788,10 +1221,11 @@
 OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
 	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
 	asn_OCTET_STRING_specifics_t *specs = td->specifics
-				? td->specifics : &asn_DEF_OCTET_STRING_specs;
+				? (asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_DEF_OCTET_STRING_specs;
 	asn_struct_ctx_t *ctx = (asn_struct_ctx_t *)
 					((char *)st + specs->ctx_offset);
-	struct _stack *stck = ctx->ptr;
+	struct _stack *stck = (struct _stack *)ctx->ptr;
 
 	if(!td || !st)
 		return;
@@ -863,7 +1297,8 @@
 OCTET_STRING_t *
 OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) {
 	asn_OCTET_STRING_specifics_t *specs = td->specifics
-				? td->specifics : &asn_DEF_OCTET_STRING_specs;
+				? (asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_DEF_OCTET_STRING_specs;
 	OCTET_STRING_t *st;
 
 	st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
diff --git a/skeletons/OCTET_STRING.h b/skeletons/OCTET_STRING.h
index dd5262e..1081635 100644
--- a/skeletons/OCTET_STRING.h
+++ b/skeletons/OCTET_STRING.h
@@ -18,11 +18,14 @@
 
 asn_struct_free_f OCTET_STRING_free;
 asn_struct_print_f OCTET_STRING_print;
-asn_struct_print_f OCTET_STRING_print_ascii;
+asn_struct_print_f OCTET_STRING_print_utf8;
 ber_type_decoder_f OCTET_STRING_decode_ber;
 der_type_encoder_f OCTET_STRING_encode_der;
+xer_type_decoder_f OCTET_STRING_decode_xer_hex;		/* Hexadecimal */
+xer_type_decoder_f OCTET_STRING_decode_xer_binary;	/* 01010111010 */
+xer_type_decoder_f OCTET_STRING_decode_xer_utf8;	/* ASCII/UTF-8 */
 xer_type_encoder_f OCTET_STRING_encode_xer;
-xer_type_encoder_f OCTET_STRING_encode_xer_ascii;
+xer_type_encoder_f OCTET_STRING_encode_xer_utf8;
 
 /******************************
  * Handy conversion routines. *
diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c
index 125e695..9f52147 100644
--- a/skeletons/ObjectDescriptor.c
+++ b/skeletons/ObjectDescriptor.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_ObjectDescriptor = {
 	"ObjectDescriptor",
+	"ObjectDescriptor",
 	OCTET_STRING_free,
-	OCTET_STRING_print_ascii,   /* Treat as ASCII subset (it's not) */
+	OCTET_STRING_print_utf8,   /* Treat as ASCII subset (it's not) */
 	asn_generic_unknown_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_ObjectDescriptor_tags,
 	sizeof(asn_DEF_ObjectDescriptor_tags)
diff --git a/skeletons/PrintableString.c b/skeletons/PrintableString.c
index dfe4f9c..dc363d8 100644
--- a/skeletons/PrintableString.c
+++ b/skeletons/PrintableString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_PrintableString = {
 	"PrintableString",
+	"PrintableString",
 	OCTET_STRING_free,
-	OCTET_STRING_print_ascii,   /* ASCII subset */
+	OCTET_STRING_print_utf8,	/* ASCII subset */
 	PrintableString_constraint,
-	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
+	OCTET_STRING_decode_ber,      /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_PrintableString_tags,
 	sizeof(asn_DEF_PrintableString_tags)
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index d395c84..c61f723 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -25,6 +25,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_REAL = {
 	"REAL",
+	"REAL",
 	ASN__PRIMITIVE_TYPE_free,
 	REAL_print,
 	asn_generic_no_constraint,
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index 899e69c..eba1eaa 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -17,6 +17,7 @@
 };
 asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = {
 	"RELATIVE-OID",
+	"RELATIVE_OID",
 	ASN__PRIMITIVE_TYPE_free,
 	RELATIVE_OID_print,
 	asn_generic_no_constraint,
diff --git a/skeletons/T61String.c b/skeletons/T61String.c
index 41835c4..a37c176 100644
--- a/skeletons/T61String.c
+++ b/skeletons/T61String.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_T61String = {
 	"T61String",
+	"T61String",
 	OCTET_STRING_free,
 	OCTET_STRING_print,         /* non-ascii string */
 	asn_generic_unknown_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_hex,
+	OCTET_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_T61String_tags,
 	sizeof(asn_DEF_T61String_tags)
diff --git a/skeletons/TeletexString.c b/skeletons/TeletexString.c
index aa8d2a9..47aad41 100644
--- a/skeletons/TeletexString.c
+++ b/skeletons/TeletexString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_TeletexString = {
 	"TeletexString",
+	"TeletexString",
 	OCTET_STRING_free,
 	OCTET_STRING_print,         /* non-ascii string */
 	asn_generic_unknown_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_hex,
+	OCTET_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_TeletexString_tags,
 	sizeof(asn_DEF_TeletexString_tags)
diff --git a/skeletons/UTCTime.c b/skeletons/UTCTime.c
index 045b172..f9de9dd 100644
--- a/skeletons/UTCTime.c
+++ b/skeletons/UTCTime.c
@@ -21,12 +21,13 @@
 };
 asn_TYPE_descriptor_t asn_DEF_UTCTime = {
 	"UTCTime",
+	"UTCTime",
 	OCTET_STRING_free,
 	UTCTime_print,
 	UTCTime_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
+	OCTET_STRING_decode_xer_utf8,
 	UTCTime_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UTCTime_tags,
@@ -88,7 +89,7 @@
 		sptr = &st;
 	}
 
-	return OCTET_STRING_encode_xer_ascii(td, sptr, ilevel, flags,
+	return OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags,
 		cb, app_key);
 }
 
diff --git a/skeletons/UTF8String.c b/skeletons/UTF8String.c
index 934a424..1c0c731 100644
--- a/skeletons/UTF8String.c
+++ b/skeletons/UTF8String.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_UTF8String = {
 	"UTF8String",
+	"UTF8String",
 	OCTET_STRING_free,
 	UTF8String_print,
 	UTF8String_constraint,      /* Check for invalid codes, etc. */
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,	/* Already in UTF-8 format */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UTF8String_tags,
 	sizeof(asn_DEF_UTF8String_tags)
diff --git a/skeletons/UniversalString.c b/skeletons/UniversalString.c
index f43de18..2221000 100644
--- a/skeletons/UniversalString.c
+++ b/skeletons/UniversalString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_UniversalString = {
 	"UniversalString",
+	"UniversalString",
 	OCTET_STRING_free,
 	UniversalString_print,      /* Convert into UTF8 and print */
 	asn_generic_no_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
 	0,				/* Not implemented yet */
-	UniversalString_encode_xer,	/* Conver into UTF8 */
+	UniversalString_encode_xer,	/* Convert into UTF8 */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UniversalString_tags,
 	sizeof(asn_DEF_UniversalString_tags)
diff --git a/skeletons/VideotexString.c b/skeletons/VideotexString.c
index fa6892e..2a2baa8 100644
--- a/skeletons/VideotexString.c
+++ b/skeletons/VideotexString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_VideotexString = {
 	"VideotexString",
+	"VideotexString",
 	OCTET_STRING_free,
 	OCTET_STRING_print,         /* non-ascii string */
 	asn_generic_unknown_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_hex,
+	OCTET_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_VideotexString_tags,
 	sizeof(asn_DEF_VideotexString_tags)
diff --git a/skeletons/VisibleString.c b/skeletons/VisibleString.c
index 8e361e7..7170b54 100644
--- a/skeletons/VisibleString.c
+++ b/skeletons/VisibleString.c
@@ -14,13 +14,14 @@
 };
 asn_TYPE_descriptor_t asn_DEF_VisibleString = {
 	"VisibleString",
+	"VisibleString",
 	OCTET_STRING_free,
-	OCTET_STRING_print_ascii,   /* ASCII subset */
+	OCTET_STRING_print_utf8,   /* ASCII subset */
 	VisibleString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	0,				/* Not implemented yet */
-	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_utf8,
+	OCTET_STRING_encode_xer_utf8,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_VisibleString_tags,
 	sizeof(asn_DEF_VisibleString_tags)
diff --git a/skeletons/asn_SEQUENCE_OF.c b/skeletons/asn_SEQUENCE_OF.c
index b2d5f1f..ec952fc 100644
--- a/skeletons/asn_SEQUENCE_OF.c
+++ b/skeletons/asn_SEQUENCE_OF.c
@@ -3,7 +3,6 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
-#include <asn_types.h>	/* for MALLOC/REALLOC/FREEMEM */
 #include <asn_SEQUENCE_OF.h>
 
 typedef A_SEQUENCE_OF(void) asn_sequence;
diff --git a/skeletons/asn_SET_OF.c b/skeletons/asn_SET_OF.c
index 7aeafdd..5e268c0 100644
--- a/skeletons/asn_SET_OF.c
+++ b/skeletons/asn_SET_OF.c
@@ -3,7 +3,6 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
-#include <asn_types.h>	/* for MALLOC/REALLOC/FREEMEM */
 #include <asn_SET_OF.h>
 #include <errno.h>
 
diff --git a/skeletons/asn_application.h b/skeletons/asn_application.h
index 33de699..4987e5c 100644
--- a/skeletons/asn_application.h
+++ b/skeletons/asn_application.h
@@ -8,7 +8,8 @@
 #ifndef	_ASN_APPLICATION_H_
 #define	_ASN_APPLICATION_H_
 
-#include <asn_types.h>		/* for platform-dependent types */
+#include <asn_system.h>		/* for platform-dependent types */
+#include <asn_codecs.h>		/* for ASN.1 codecs specifics */
 
 /*
  * Generic type of an application-defined callback to return various
diff --git a/skeletons/asn_codecs.h b/skeletons/asn_codecs.h
new file mode 100644
index 0000000..2f8ed10
--- /dev/null
+++ b/skeletons/asn_codecs.h
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_ASN_CODECS_H_
+#define	_ASN_CODECS_H_
+
+struct asn_TYPE_descriptor_s;	/* Forward declaration */
+
+/*
+ * This structure defines a context that may be passed to every ASN.1 encoder
+ * or decoder function.
+ * WARNING: if max_stack_size member is set, and you are calling the
+ * function pointers of the asn_TYPE_descriptor_t directly,
+ * this structure must be ALLOCATED ON THE STACK!
+ */
+typedef struct asn_codec_ctx_s {
+	/*
+	 * Limit the decoder routines to use no (much) more stack than a given
+	 * number of bytes. Most of decoders are stack-based, and this
+	 * would protect against stack overflows if the number of nested
+	 * encodings is high.
+	 * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based,
+	 * and are safe from this kind of overflow.
+	 * A value from getrlimit(RLIMIT_STACK) may be used to initialize
+	 * this variable. Be careful in multithreaded environments, as the
+	 * stack size is rather limited.
+	 */
+	size_t  max_stack_size; /* 0 disables stack bounds checking */
+} asn_codec_ctx_t;
+
+/*
+ * Type of the return value of the encoding functions (der_encode, xer_encode).
+ */
+typedef struct asn_enc_rval_s {
+	/*
+	 * Number of bytes encoded.
+	 * -1 indicates failure to encode the structure.
+	 * In this case, the members below this one are meaningful.
+	 */
+	ssize_t encoded;
+
+	/*
+	 * Members meaningful when (encoded == -1), for post mortem analysis.
+	 */
+
+	/* Type which cannot be encoded */
+	struct asn_TYPE_descriptor_s *failed_type;
+
+	/* Pointer to the structure of that type */
+	void *structure_ptr;
+} asn_enc_rval_t;
+#define	_ASN_ENCODE_FAILED do {					\
+	asn_enc_rval_t __er = { -1, td, sptr };			\
+	return __er;						\
+} while(0)
+
+/*
+ * Type of the return value of the decoding functions (ber_decode, xer_decode)
+ * 
+ * Please note that the number of consumed bytes is ALWAYS meaningful,
+ * even if code==RC_FAIL. This is to indicate the number of successfully
+ * decoded bytes, hence providing a possibility to fail with more diagnostics
+ * (i.e., print the offending remainder of the buffer).
+ */
+enum asn_dec_rval_code_e {
+	RC_OK,		/* Decoded successfully */
+	RC_WMORE,	/* More data expected, call again */
+	RC_FAIL		/* Failure to decode data */
+};
+typedef struct asn_dec_rval_s {
+	enum asn_dec_rval_code_e code;	/* Result code */
+	size_t consumed;		/* Number of bytes consumed */
+} asn_dec_rval_t;
+
+#endif	/* _ASN_CODECS_H_ */
diff --git a/skeletons/asn_internal.h b/skeletons/asn_internal.h
index a7690eb..c2aa9e5 100644
--- a/skeletons/asn_internal.h
+++ b/skeletons/asn_internal.h
@@ -8,7 +8,7 @@
 #ifndef	_ASN_INTERNAL_H_
 #define	_ASN_INTERNAL_H_
 
-#define	ASN1C_ENVIRONMENT_VERSION	96	/* Compile-time version */
+#define	ASN1C_ENVIRONMENT_VERSION	98	/* Compile-time version */
 int get_asn1c_environment_version(void);	/* Run-time version */
 
 #include <asn_application.h>	/* Application-visible API */
diff --git a/skeletons/asn_types.h b/skeletons/asn_system.h
similarity index 91%
rename from skeletons/asn_types.h
rename to skeletons/asn_system.h
index cf5c87e..ee64a0c 100644
--- a/skeletons/asn_types.h
+++ b/skeletons/asn_system.h
@@ -5,8 +5,8 @@
 /*
  * Miscellaneous system-dependent types.
  */
-#ifndef	_ASN_TYPES_H_
-#define	_ASN_TYPES_H_
+#ifndef	_ASN_SYSTEM_H_
+#define	_ASN_SYSTEM_H_
 
 #ifdef	HAVE_CONFIG_H
 #include "config.h"
@@ -31,7 +31,7 @@
  * 2. Sun Solaris requires <alloca.h> for alloca(3),
  * but does not have <stdint.h>.
  */
-#if	(!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_))
+#if	(!defined(__FreeBSD__) || !defined(_SYS_INTSYSTEM_H_))
 #if	defined(sun)
 #include <alloca.h>	/* For alloca(3) */
 #else
@@ -62,4 +62,4 @@
 #endif /* __GNUC__ */
 #endif	/* MIN */
 
-#endif	/* _ASN_TYPES_H_ */
+#endif	/* _ASN_SYSTEM_H_ */
diff --git a/skeletons/ber_codec_prim.c b/skeletons/ber_codec_prim.c
index c4d06e1..2c367ae 100644
--- a/skeletons/ber_codec_prim.c
+++ b/skeletons/ber_codec_prim.c
@@ -10,12 +10,12 @@
 /*
  * Decode an always-primitive type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *td,
 	void **sptr, void *buf_ptr, size_t size, int tag_mode) {
 	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	ber_tlv_len_t length;
 
 	/*
diff --git a/skeletons/ber_decoder.c b/skeletons/ber_decoder.c
index cda6c16..c78cfee 100644
--- a/skeletons/ber_decoder.c
+++ b/skeletons/ber_decoder.c
@@ -14,7 +14,7 @@
 	} while(0)
 #undef	RETURN
 #define	RETURN(_code)	do {						\
-		ber_dec_rval_t rval;					\
+		asn_dec_rval_t rval;					\
 		rval.code = _code;					\
 		if(opt_ctx) opt_ctx->step = step; /* Save context */	\
 		if(_code == RC_OK || opt_ctx)				\
@@ -27,7 +27,7 @@
 /*
  * The BER decoder of any type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 ber_decode(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *type_descriptor,
 	void **struct_ptr, void *ptr, size_t size) {
@@ -55,7 +55,7 @@
 /*
  * Check the set of <TL<TL<TL...>>> tags matches the definition.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 ber_check_tags(asn_codec_ctx_t *opt_codec_ctx,
 		asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx,
 		void *ptr, size_t size, int tag_mode, int last_tag_form,
diff --git a/skeletons/ber_decoder.h b/skeletons/ber_decoder.h
index 8499c6a..b835b0f 100644
--- a/skeletons/ber_decoder.h
+++ b/skeletons/ber_decoder.h
@@ -11,29 +11,10 @@
 struct asn_codec_ctx_s;		/* Forward declaration */
 
 /*
- * This structure describes the return value common across the
- * various BER decoders.
- * 
- * Please note that the number of consumed bytes is ALWAYS meaningful,
- * even if code!=RC_OK. This is so to indicate the number of successfully
- * decoded bytes, hence provide a possibility, to fail with more diagnostics
- * (i.e., print the offending remainder of the buffer).
- */
-  enum ber_dec_rval_code_e {
-	RC_OK,		/* Decoded successfully */
-	RC_WMORE,	/* More data expected, call again */
-	RC_FAIL		/* Failure to decode data */
-  };
-typedef struct ber_dec_rval_s {
-	enum ber_dec_rval_code_e code;	/* Result code */
-	size_t consumed;		/* Number of bytes consumed */
-} ber_dec_rval_t;
-
-/*
  * The BER decoder of any type.
  * This function may be invoked directly from the application.
  */
-ber_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx,
+asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx,
 	struct asn_TYPE_descriptor_s *type_descriptor,
 	void **struct_ptr,	/* Pointer to a target structure's pointer */
 	void *buffer,		/* Data to be decoded */
@@ -43,10 +24,10 @@
 /*
  * Type of generic function which decodes the byte stream into the structure.
  */
-typedef ber_dec_rval_t (ber_type_decoder_f)(
+typedef asn_dec_rval_t (ber_type_decoder_f)(
 		struct asn_codec_ctx_s *opt_codec_ctx,
 		struct asn_TYPE_descriptor_s *type_descriptor,
-		void **type_structure, void *buf_ptr, size_t size,
+		void **struct_ptr, void *buf_ptr, size_t size,
 		int tag_mode);
 
 /*******************************
@@ -60,7 +41,7 @@
  * "end of content" sequences. The number may only be negative if the
  * head->last_tag_form is non-zero.
  */
-ber_dec_rval_t ber_check_tags(
+asn_dec_rval_t ber_check_tags(
 		struct asn_codec_ctx_s *opt_codec_ctx,	/* optional context */
 		struct asn_TYPE_descriptor_s *type_dsc,
 		asn_struct_ctx_t *opt_ctx,	/* saved decoding context */
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
index 236b9ad..9305313 100644
--- a/skeletons/constr_CHOICE.c
+++ b/skeletons/constr_CHOICE.c
@@ -96,7 +96,7 @@
 /*
  * The decoder of the CHOICE type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
@@ -113,7 +113,7 @@
 
 	ber_tlv_tag_t tlv_tag;	/* T from TLV */
 	ssize_t tag_len;	/* Length of TLV's T */
-	ber_dec_rval_t rval;	/* Return code from subparsers */
+	asn_dec_rval_t rval;	/* Return code from subparsers */
 
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 
diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
index 8cd323a..2685134 100644
--- a/skeletons/constr_CHOICE.h
+++ b/skeletons/constr_CHOICE.h
@@ -12,7 +12,7 @@
 	 * Target structure description.
 	 */
 	int struct_size;	/* Size of the target structure. */
-	int ctx_offset;		/* Offset of the ber_dec_ctx_t member */
+	int ctx_offset;		/* Offset of the asn_codec_ctx_t member */
 	int pres_offset;	/* Identifier of the present member */
 	int pres_size;		/* Size of the identifier (enum) */
 
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 693ddd2..fcca479 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -107,7 +107,7 @@
 /*
  * The decoder of the SEQUENCE type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
@@ -123,7 +123,7 @@
 	asn_struct_ctx_t *ctx;	/* Decoder context */
 
 	ber_tlv_tag_t tlv_tag;	/* T from TLV */
-	ber_dec_rval_t rval;	/* Return code from subparsers */
+	asn_dec_rval_t rval;	/* Return code from subparsers */
 
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 	int edx;			/* SEQUENCE element's index */
diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c
index 3d526d0..f126d78 100644
--- a/skeletons/constr_SEQUENCE_OF.c
+++ b/skeletons/constr_SEQUENCE_OF.c
@@ -92,7 +92,8 @@
 	asn_TYPE_member_t *element = td->elements;
 	A_SEQUENCE_OF(void) *list;
 	const char *mname = specs->as_XMLValueList
-		? 0 : ((*element->name) ? element->name : element->type->name);
+		? 0 : ((*element->name)
+			? element->name : element->type->xml_tag);
 	unsigned int mlen = mname ? strlen(mname) : 0;
 	int xcan = (flags & XER_F_CANONICAL);
 	int i;
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index ce6afd6..be36016 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -96,7 +96,7 @@
 /*
  * The decoder of the SET type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 SET_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
@@ -112,7 +112,7 @@
 	asn_struct_ctx_t *ctx;	/* Decoder context */
 
 	ber_tlv_tag_t tlv_tag;	/* T from TLV */
-	ber_dec_rval_t rval;	/* Return code from subparsers */
+	asn_dec_rval_t rval;	/* Return code from subparsers */
 
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 	int edx;			/* SET element's index */
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index 518713c..164668c 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -65,7 +65,7 @@
 /*
  * The decoder of the SET OF type.
  */
-ber_dec_rval_t
+asn_dec_rval_t
 SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
@@ -81,7 +81,7 @@
 	asn_struct_ctx_t *ctx;	/* Decoder context */
 
 	ber_tlv_tag_t tlv_tag;	/* T from TLV */
-	ber_dec_rval_t rval;	/* Return code from subparsers */
+	asn_dec_rval_t rval;	/* Return code from subparsers */
 
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 
@@ -495,7 +495,8 @@
 	asn_TYPE_member_t *element = td->elements;
 	A_SET_OF(void) *list;
 	const char *mname = specs->as_XMLValueList
-		? 0 : ((*element->name) ? element->name : element->type->name);
+		? 0 : ((*element->name)
+			? element->name : element->type->xml_tag);
 	size_t mlen = mname ? strlen(mname) : 0;
 	int xcan = (flags & XER_F_CANONICAL);
 	xer_tmp_enc_t *encs = 0;
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index 7e3254e..79bd0a2 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -8,8 +8,8 @@
  * This structure even contains pointer to these encoding and decoding routines
  * for each defined ASN.1 type.
  */
-#ifndef	_CONSTR_TYPE_H
-#define	_CONSTR_TYPE_H
+#ifndef	_CONSTR_TYPE_H_
+#define	_CONSTR_TYPE_H_
 
 #include <ber_tlv_length.h>
 #include <ber_tlv_tag.h>
@@ -29,58 +29,11 @@
 	void *ptr;		/* Decoder-specific stuff (stack elements) */
 } asn_struct_ctx_t;
 
-/*
- * This structure defines a context that may be passed to every ASN.1 encoder
- * or decoder function.
- * WARNING: if max_stack_size member is set, and you are calling the
- * function pointers of the asn_TYPE_descriptor_t directly,
- * this structure must be ALLOCATED ON THE STACK!
- */
-typedef struct asn_codec_ctx_s {
-	/*
-	 * Limit the decoder routines to use no (much) more stack than a given
-	 * number of bytes. Most of decoders are stack-based, and this
-	 * would protect against stack overflows if the number of nested
-	 * encodings is high.
-	 * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based,
-	 * and are safe from this kind of overflow.
-	 * A value from getrlimit(RLIMIT_STACK) may be used to initialize
-	 * this variable. Be careful in multithreaded environments, as the
-	 * stack size is rather limited.
-	 */
-	size_t  max_stack_size; /* 0 disables stack bounds checking */
-} asn_codec_ctx_t;
-
-/*
- * Type of the return value of the encoding functions (der_encode, xer_encode).
- */
-typedef struct asn_enc_rval_s {
-	/*
-	 * Number of bytes encoded.
-	 * -1 indicates failure to encode the structure.
-	 * In this case, the members below this one are meaningful.
-	 */
-	ssize_t encoded;
-
-	/*
-	 * Members meaningful when (encoded == -1), for post mortem analysis.
-	 */
-
-	/* Type which cannot be encoded */
-	struct asn_TYPE_descriptor_s *failed_type;
-
-	/* Pointer to the structure of that type */
-	void *structure_ptr;
-} asn_enc_rval_t;
-#define	_ASN_ENCODE_FAILED do {					\
-	asn_enc_rval_t __er = { -1, td, sptr };			\
-	return __er;						\
-} while(0)
-
-#include <ber_decoder.h>
-#include <der_encoder.h>
-#include <xer_encoder.h>
-#include <constraints.h>
+#include <ber_decoder.h>	/* Basic Encoding Rules decoder */
+#include <der_encoder.h>	/* Distinguished Encoding Rules encoder */
+#include <xer_decoder.h>	/* Decoder of XER (XML, text) */
+#include <xer_encoder.h>	/* Encoder into XER (XML, text) */
+#include <constraints.h>	/* Subtype constraints support */
 
 /*
  * Free the structure according to its specification.
@@ -119,7 +72,8 @@
  * The definitive description of the destination language's structure.
  */
 typedef struct asn_TYPE_descriptor_s {
-	char *name;	/* A name of the ASN.1 type */
+	char *name;	/* A name of the ASN.1 type. "" in some cases. */
+	char *xml_tag;	/* Name used in XML tag */
 
 	/*
 	 * Generalized functions for dealing with the specific type.
@@ -128,9 +82,9 @@
 	asn_struct_free_f  *free_struct;	/* Free the structure */
 	asn_struct_print_f *print_struct;	/* Human readable output */
 	asn_constr_check_f *check_constraints;	/* Constraints validator */
-	ber_type_decoder_f *ber_decoder;	/* Free-form BER decoder */
+	ber_type_decoder_f *ber_decoder;	/* Generic BER decoder */
 	der_type_encoder_f *der_encoder;	/* Canonical DER encoder */
-	int (*xer_decoder);/* PLACEHOLDER */ /* Free-form XER decoder */
+	xer_type_decoder_f *xer_decoder;	/* Generic XER decoder */
 	xer_type_encoder_f *xer_encoder;	/* [Canonical] XER encoder */
 
 	/***********************************************************************
diff --git a/skeletons/constraints.h b/skeletons/constraints.h
index 07eb836..d8434e4 100644
--- a/skeletons/constraints.h
+++ b/skeletons/constraints.h
@@ -5,7 +5,7 @@
 #ifndef	_ASN1_CONSTRAINTS_VALIDATOR_H_
 #define	_ASN1_CONSTRAINTS_VALIDATOR_H_
 
-#include <asn_types.h>	/* System-dependent types */
+#include <asn_system.h>		/* Platform-dependent types */
 
 struct asn_TYPE_descriptor_s;		/* Forward declaration */
 
diff --git a/skeletons/file-dependencies b/skeletons/file-dependencies
index 6b7ac69..a95d98b 100644
--- a/skeletons/file-dependencies
+++ b/skeletons/file-dependencies
@@ -44,7 +44,8 @@
 COMMON-FILES:	# This is a special section
 asn_application.h
 asn_internal.h
-asn_types.h
+asn_codecs.h
+asn_system.h			# Platform-dependent types
 OCTET_STRING.h OCTET_STRING.c	# This one is used too widely
 BIT_STRING.h BIT_STRING.c	# This one is necessary for the above one
 ber_decoder.h ber_decoder.c
@@ -54,4 +55,5 @@
 constr_TYPE.h constr_TYPE.c
 constraints.h constraints.c
 der_encoder.h der_encoder.c
+xer_decoder.h xer_decoder.c xer_support.h xer_support.c	# XER/XML decoding
 xer_encoder.h xer_encoder.c
diff --git a/skeletons/tests/Makefile.am b/skeletons/tests/Makefile.am
index a58e469..c374438 100644
--- a/skeletons/tests/Makefile.am
+++ b/skeletons/tests/Makefile.am
@@ -5,10 +5,12 @@
 	check-length		\
 	check-OIDs		\
 	check-GeneralizedTime	\
+	check-OCTET_STRING	\
 	check-UTF8String	\
 	check-UTCTime		\
 	check-INTEGER		\
-	check-REAL
+	check-REAL		\
+	check-XER
 
 LDADD = -lm
 
diff --git a/skeletons/tests/Makefile.in b/skeletons/tests/Makefile.in
index 835df71..f5a3c68 100644
--- a/skeletons/tests/Makefile.in
+++ b/skeletons/tests/Makefile.in
@@ -13,7 +13,7 @@
 # PARTICULAR PURPOSE.
 
 @SET_MAKE@
-SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OIDs.c check-REAL.c check-UTCTime.c check-UTF8String.c check-ber_tlv_tag.c check-length.c
+SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OCTET_STRING.c check-OIDs.c check-REAL.c check-UTCTime.c check-UTF8String.c check-XER.c check-ber_tlv_tag.c check-length.c
 
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
@@ -38,8 +38,9 @@
 host_triplet = @host@
 check_PROGRAMS = check-ber_tlv_tag$(EXEEXT) check-length$(EXEEXT) \
 	check-OIDs$(EXEEXT) check-GeneralizedTime$(EXEEXT) \
-	check-UTF8String$(EXEEXT) check-UTCTime$(EXEEXT) \
-	check-INTEGER$(EXEEXT) check-REAL$(EXEEXT)
+	check-OCTET_STRING$(EXEEXT) check-UTF8String$(EXEEXT) \
+	check-UTCTime$(EXEEXT) check-INTEGER$(EXEEXT) \
+	check-REAL$(EXEEXT) check-XER$(EXEEXT)
 subdir = skeletons/tests
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -57,6 +58,10 @@
 check_INTEGER_OBJECTS = check-INTEGER.$(OBJEXT)
 check_INTEGER_LDADD = $(LDADD)
 check_INTEGER_DEPENDENCIES =
+check_OCTET_STRING_SOURCES = check-OCTET_STRING.c
+check_OCTET_STRING_OBJECTS = check-OCTET_STRING.$(OBJEXT)
+check_OCTET_STRING_LDADD = $(LDADD)
+check_OCTET_STRING_DEPENDENCIES =
 check_OIDs_SOURCES = check-OIDs.c
 check_OIDs_OBJECTS = check-OIDs.$(OBJEXT)
 check_OIDs_LDADD = $(LDADD)
@@ -73,6 +78,10 @@
 check_UTF8String_OBJECTS = check-UTF8String.$(OBJEXT)
 check_UTF8String_LDADD = $(LDADD)
 check_UTF8String_DEPENDENCIES =
+check_XER_SOURCES = check-XER.c
+check_XER_OBJECTS = check-XER.$(OBJEXT)
+check_XER_LDADD = $(LDADD)
+check_XER_DEPENDENCIES =
 check_ber_tlv_tag_SOURCES = check-ber_tlv_tag.c
 check_ber_tlv_tag_OBJECTS = check-ber_tlv_tag.$(OBJEXT)
 check_ber_tlv_tag_LDADD = $(LDADD)
@@ -86,10 +95,12 @@
 am__depfiles_maybe = depfiles
 @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/check-GeneralizedTime.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-INTEGER.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/check-OCTET_STRING.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-OIDs.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-REAL.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-UTCTime.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-UTF8String.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/check-XER.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-ber_tlv_tag.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/check-length.Po
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -100,12 +111,13 @@
 CCLD = $(CC)
 LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OIDs.c \
-	check-REAL.c check-UTCTime.c check-UTF8String.c \
-	check-ber_tlv_tag.c check-length.c
-DIST_SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OIDs.c \
-	check-REAL.c check-UTCTime.c check-UTF8String.c \
-	check-ber_tlv_tag.c check-length.c
+SOURCES = check-GeneralizedTime.c check-INTEGER.c check-OCTET_STRING.c \
+	check-OIDs.c check-REAL.c check-UTCTime.c check-UTF8String.c \
+	check-XER.c check-ber_tlv_tag.c check-length.c
+DIST_SOURCES = check-GeneralizedTime.c check-INTEGER.c \
+	check-OCTET_STRING.c check-OIDs.c check-REAL.c check-UTCTime.c \
+	check-UTF8String.c check-XER.c check-ber_tlv_tag.c \
+	check-length.c
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -267,6 +279,9 @@
 check-INTEGER$(EXEEXT): $(check_INTEGER_OBJECTS) $(check_INTEGER_DEPENDENCIES) 
 	@rm -f check-INTEGER$(EXEEXT)
 	$(LINK) $(check_INTEGER_LDFLAGS) $(check_INTEGER_OBJECTS) $(check_INTEGER_LDADD) $(LIBS)
+check-OCTET_STRING$(EXEEXT): $(check_OCTET_STRING_OBJECTS) $(check_OCTET_STRING_DEPENDENCIES) 
+	@rm -f check-OCTET_STRING$(EXEEXT)
+	$(LINK) $(check_OCTET_STRING_LDFLAGS) $(check_OCTET_STRING_OBJECTS) $(check_OCTET_STRING_LDADD) $(LIBS)
 check-OIDs$(EXEEXT): $(check_OIDs_OBJECTS) $(check_OIDs_DEPENDENCIES) 
 	@rm -f check-OIDs$(EXEEXT)
 	$(LINK) $(check_OIDs_LDFLAGS) $(check_OIDs_OBJECTS) $(check_OIDs_LDADD) $(LIBS)
@@ -279,6 +294,9 @@
 check-UTF8String$(EXEEXT): $(check_UTF8String_OBJECTS) $(check_UTF8String_DEPENDENCIES) 
 	@rm -f check-UTF8String$(EXEEXT)
 	$(LINK) $(check_UTF8String_LDFLAGS) $(check_UTF8String_OBJECTS) $(check_UTF8String_LDADD) $(LIBS)
+check-XER$(EXEEXT): $(check_XER_OBJECTS) $(check_XER_DEPENDENCIES) 
+	@rm -f check-XER$(EXEEXT)
+	$(LINK) $(check_XER_LDFLAGS) $(check_XER_OBJECTS) $(check_XER_LDADD) $(LIBS)
 check-ber_tlv_tag$(EXEEXT): $(check_ber_tlv_tag_OBJECTS) $(check_ber_tlv_tag_DEPENDENCIES) 
 	@rm -f check-ber_tlv_tag$(EXEEXT)
 	$(LINK) $(check_ber_tlv_tag_LDFLAGS) $(check_ber_tlv_tag_OBJECTS) $(check_ber_tlv_tag_LDADD) $(LIBS)
@@ -294,10 +312,12 @@
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-GeneralizedTime.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-INTEGER.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-OCTET_STRING.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-OIDs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-REAL.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-UTCTime.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-UTF8String.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-XER.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-ber_tlv_tag.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-length.Po@am__quote@
 
diff --git a/skeletons/tests/check-GeneralizedTime.c b/skeletons/tests/check-GeneralizedTime.c
index 0cec17d..ff20772 100644
--- a/skeletons/tests/check-GeneralizedTime.c
+++ b/skeletons/tests/check-GeneralizedTime.c
@@ -116,7 +116,7 @@
 }
 
 asn_enc_rval_t
-OCTET_STRING_encode_xer_ascii(asn_TYPE_descriptor_t *td, void *ptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) {
+OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *ptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) {
 	asn_enc_rval_t erval;
 
 	(void)td;
diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c
index 0cd4d14..436e013 100644
--- a/skeletons/tests/check-OIDs.c
+++ b/skeletons/tests/check-OIDs.c
@@ -19,7 +19,7 @@
 static void
 check_OID(uint8_t *buf, size_t len, int *ck_buf, int ck_len) {
 	OBJECT_IDENTIFIER_t *oid;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	unsigned long arcs[10];
 	int alen;
 	int i;
@@ -66,7 +66,7 @@
 static void
 check_ROID(uint8_t *buf, size_t len, int *ck_buf, int ck_len) {
 	RELATIVE_OID_t *oid;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	unsigned long arcs[10];
 	int alen;
 	int i;
diff --git a/skeletons/tests/check-UTCTime.c b/skeletons/tests/check-UTCTime.c
index 6762865..4c76858 100644
--- a/skeletons/tests/check-UTCTime.c
+++ b/skeletons/tests/check-UTCTime.c
@@ -79,7 +79,7 @@
 }
 
 asn_enc_rval_t
-OCTET_STRING_encode_xer_ascii(asn_TYPE_descriptor_t *td, void *ptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) {
+OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *ptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) {
 	asn_enc_rval_t erval;
 
 	(void)td;
diff --git a/skeletons/tests/check-UTF8String.c b/skeletons/tests/check-UTF8String.c
index 1497921..ae368ea 100644
--- a/skeletons/tests/check-UTF8String.c
+++ b/skeletons/tests/check-UTF8String.c
@@ -4,6 +4,8 @@
 #include <ber_tlv_length.c>
 #include <ber_tlv_tag.c>
 #include <der_encoder.c>
+#include <xer_decoder.c>
+#include <xer_support.c>
 #include <constraints.c>
 #include <sys/time.h>
 
diff --git a/skeletons/tests/check-length.c b/skeletons/tests/check-length.c
index d76902d..80064d5 100644
--- a/skeletons/tests/check-length.c
+++ b/skeletons/tests/check-length.c
@@ -2,6 +2,8 @@
 #include <ber_tlv_length.c>
 #include <ber_tlv_tag.c>
 #include <der_encoder.c>
+#include <xer_decoder.c>
+#include <xer_support.c>
 #include <constraints.c>
 #undef	ADVANCE
 #undef	RETURN
@@ -37,7 +39,7 @@
 	OCTET_STRING_t *os;
 	OCTET_STRING_t *nos = 0;
 	asn_enc_rval_t erval;
-	ber_dec_rval_t rval;
+	asn_dec_rval_t rval;
 	int i;
 
 	os = OCTET_STRING_new_fromBuf(&asn_DEF_OCTET_STRING, 0, size);
diff --git a/skeletons/xer_decoder.c b/skeletons/xer_decoder.c
new file mode 100644
index 0000000..39e830d
--- /dev/null
+++ b/skeletons/xer_decoder.c
@@ -0,0 +1,288 @@
+
+#include <asn_application.h>
+#include <asn_internal.h>
+#include <xer_support.h>		/* XER/XML parsing support */
+#include <assert.h>
+
+
+/*
+ * Decode the XER encoding of a given type.
+ */
+asn_dec_rval_t
+xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+		void **struct_ptr, void *buffer, size_t size) {
+	asn_codec_ctx_t s_codec_ctx;
+
+	/*
+	 * Satisfy the requirement that the codec context
+	 * must be allocated on the stack.
+	 */
+	if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
+		s_codec_ctx = *opt_codec_ctx;
+		opt_codec_ctx = &s_codec_ctx;
+	}
+
+	/*
+	 * Invoke type-specific decoder.
+	 */
+	return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size);
+}
+
+
+
+struct xer__cb_arg {
+	pxml_chunk_type_e	chunk_type;
+	size_t			chunk_size;
+	void			*chunk_buf;
+	int callback_not_invoked;
+};
+
+static int
+xer__token_cb(pxml_chunk_type_e type, void *_chunk_data, size_t _chunk_size, void *key) {
+	struct xer__cb_arg *arg = (struct xer__cb_arg *)key;
+	arg->chunk_type = type;
+	arg->chunk_size = _chunk_size;
+	arg->chunk_buf = _chunk_data;
+	arg->callback_not_invoked = 0;
+	return -1;	/* Terminate the XML parsing */
+}
+
+/*
+ * Fetch the next token from the XER/XML stream.
+ */
+ssize_t
+xer_next_token(int *stateContext, void *buffer, size_t size,
+		pxer_chunk_type_e *ch_type) {
+	struct xer__cb_arg arg;
+	ssize_t ret;
+
+	arg.callback_not_invoked = 1;
+	ret = pxml_parse(stateContext, buffer, size, xer__token_cb, &arg);
+	if(ret < 0) return -1;
+	if(arg.callback_not_invoked) {
+		assert(ret == 0);	/* No data was consumed */
+		return 0;		/* Try again with more data */
+	} else {
+		assert(arg.chunk_size);
+		assert(arg.chunk_buf == buffer);
+	}
+
+	/*
+	 * Translate the XML chunk types into more convenient ones.
+	 */
+	switch(arg.chunk_type) {
+	case PXML_TEXT:
+		*ch_type = PXER_TEXT;
+		break;
+	case PXML_TAG: return 0;	/* Want more */
+	case PXML_TAG_END:
+		*ch_type = PXER_TAG;
+		break;
+	case PXML_COMMENT:
+	case PXML_COMMENT_END:
+		*ch_type = PXER_COMMENT;
+		break;
+	}
+
+	return arg.chunk_size;
+}
+
+#define	CSLASH	0x2f	/* '/' */
+#define	LANGLE	0x3c	/* '<' */
+#define	RANGLE	0x3e	/* '>' */
+
+xer_check_tag_e
+xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
+	const char *buf = (const char *)buf_ptr;
+	const char *end;
+	xer_check_tag_e ct = XCT_OPENING;
+
+	if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
+		return XCT_BROKEN;
+	}
+
+	/*
+	 * Determine the tag class.
+	 */
+	if(buf[1] == CSLASH) {
+		buf += 2;	/* advance past "</" */
+		size -= 3;	/* strip "</" and ">" */
+		ct = XCT_CLOSING;
+		if(size > 0 && buf[size-1] == CSLASH)
+			return XCT_BROKEN;	/* </abc/> */
+	} else {
+		buf++;		/* advance past "<" */
+		size -= 2;	/* strip "<" and ">" */
+		if(size > 0 && buf[size-1] == CSLASH) {
+			ct = XCT_BOTH;
+			size--;	/* One more, for "/" */
+		}
+	}
+
+	/*
+	 * Determine the tag name.
+	 */
+	for(end = buf + size; buf < end; buf++, need_tag++) {
+		int b = *buf, n = *need_tag;
+		if(b != n) {
+			if(n == 0) {
+				switch(b) {
+				case 0x09: case 0x0a: case 0x0c: case 0x0d:
+				case 0x20:
+					/* "<abc def/>": whitespace is normal */
+					return ct;
+				}
+			}
+			return XCT_UNEXPECTED;
+		}
+		if(b == 0)
+			return XCT_BROKEN;	/* Embedded 0 in buf?! */
+	}
+	if(*need_tag) return XCT_UNEXPECTED;
+
+	return ct;
+}
+
+
+#undef	ADVANCE
+#define	ADVANCE(num_bytes)	do {				\
+		size_t num = (num_bytes);			\
+		buf_ptr = ((char *)buf_ptr) + num;		\
+		size -= num;					\
+		consumed_myself += num;				\
+	} while(0)
+
+#undef	RETURN
+#define	RETURN(_code)	do {					\
+		rval.code = _code;				\
+		rval.consumed = consumed_myself;		\
+		return rval;					\
+	} while(0)
+
+#define	XER_GOT_BODY(chunk_buf, chunk_size)	do {		\
+		ssize_t converted_size = body_receiver		\
+			(struct_ptr, chunk_buf, chunk_size,	\
+				(size_t)chunk_size < size);	\
+		if(converted_size == -1) RETURN(RC_FAIL);	\
+		chunk_size = converted_size;			\
+	} while(0)
+#define	XER_GOT_EMPTY()	do {					\
+		ssize_t chunk_size = 0;				\
+		XER_GOT_BODY(0, chunk_size);			\
+	} while(0)
+
+/*
+ * Generalized function for decoding the primitive values.
+ */
+asn_dec_rval_t
+xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
+	asn_struct_ctx_t *ctx,	/* Type decoder context */
+	void *struct_ptr,	/* The structure must be already allocated */
+	const char *xml_tag,	/* Expected XML tag */
+	void *buf_ptr, size_t size,
+	int (*opt_unexpected_tag_decoder)
+		(void *struct_ptr, void *chunk_buf, size_t chunk_size),
+	ssize_t (*body_receiver)
+		(void *struct_ptr, void *chunk_buf, size_t chunk_size,
+			int have_more)
+	) {
+
+	asn_dec_rval_t rval;
+	ssize_t consumed_myself = 0;
+	pxer_chunk_type_e ch_type;	/* XER chunk type */
+	int xer_state;			/* XER low level parsing context */
+
+	(void)opt_codec_ctx;
+
+	/*
+	 * Phases of XER/XML processing:
+	 * Phase 0: Check that the opening tag matches our expectations.
+	 * Phase 1: Processing body and reacting on closing tag.
+	 */
+	if(ctx->phase > 1) RETURN(RC_FAIL);
+	for(xer_state = ctx->step;;) {
+		ssize_t ch_size;	/* Chunk size */
+		xer_check_tag_e tcv;	/* Tag check value */
+
+		/*
+		 * Get the next part of the XML stream.
+		 */
+		ch_size = xer_next_token(&xer_state, buf_ptr, size, &ch_type);
+		switch(ch_size) {
+		case -1: RETURN(RC_FAIL);
+		case 0:
+			ctx->step = xer_state;
+			RETURN(RC_WMORE);
+		default:
+			switch(ch_type) {
+			case PXER_COMMENT:		/* Got XML comment */
+				ADVANCE(ch_size);	/* Skip silently */
+				continue;
+			case PXER_TEXT:
+				if(ctx->phase == 0) {
+					/* Unexpected data */
+					/* TODO: ignore whitespace? */
+					RETURN(RC_FAIL);
+				}
+				XER_GOT_BODY(buf_ptr, ch_size);
+				ADVANCE(ch_size);
+				continue;
+			case PXER_TAG:
+				break;	/* Check the rest down there */
+			}
+		}
+
+		assert(ch_type == PXER_TAG && size);
+
+		tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
+		if(ctx->phase == 0) {
+			/*
+			 * Expecting the opening tag
+			 * for the type being processed.
+			 */
+			switch(tcv) {
+			case XCT_BOTH:
+				/* Finished decoding of an empty element */
+				XER_GOT_EMPTY();
+				ADVANCE(ch_size);
+				ctx->phase = 2;	/* Phase out */
+				RETURN(RC_OK);
+			case XCT_OPENING:
+				ADVANCE(ch_size);
+				ctx->phase = 1;	/* Processing body phase */
+				continue;
+			default:
+				break;		/* Unexpected tag */
+			}
+		} else {
+			/*
+			 * Waiting for the closing XML tag.
+			 */
+			switch(tcv) {
+			case XCT_CLOSING:
+				ADVANCE(ch_size);
+				ctx->phase = 2;	/* Phase out */
+				RETURN(RC_OK);
+			case XCT_UNEXPECTED:
+				/*
+				 * Certain tags in the body may be expected.
+				 */
+				if(opt_unexpected_tag_decoder
+				&& opt_unexpected_tag_decoder(struct_ptr,
+						buf_ptr, ch_size) == 0) {
+					/* Tag's processed fine */
+					ADVANCE(ch_size);
+					continue;
+				}
+				/* Fall through */
+			default:
+				break;
+			}
+			ASN_DEBUG("Unexpected XML tag");
+		}
+		break;	/* Dark and mysterious things have just happened */
+	}
+
+	RETURN(RC_FAIL);
+}
+
diff --git a/skeletons/xer_decoder.h b/skeletons/xer_decoder.h
new file mode 100644
index 0000000..e258b5b
--- /dev/null
+++ b/skeletons/xer_decoder.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_XER_DECODER_H_
+#define	_XER_DECODER_H_
+
+#include <asn_application.h>
+
+struct asn_TYPE_descriptor_s;	/* Forward declaration */
+
+/*
+ * The XER decoder of any type. May be invoked by the application.
+ */
+asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx,
+	struct asn_TYPE_descriptor_s *type_descriptor,
+	void **struct_ptr,	/* Pointer to a target structure's pointer */
+	void *buffer,		/* Data to be decoded */
+	size_t size		/* Size of that buffer */
+	);
+
+/*
+ * Type of the type-specific XER decoder function.
+ */
+typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx,
+		struct asn_TYPE_descriptor_s *type_descriptor,
+		void **struct_ptr,
+		const char *opt_mname,	/* Member name */
+		void *buf_ptr, size_t size
+	);
+
+/*******************************
+ * INTERNALLY USEFUL FUNCTIONS *
+ *******************************/
+
+/*
+ * Generalized function for decoding the primitive values.
+ * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8
+ * and others. This function should not be used by applications, as its API
+ * is subject to changes.
+ */
+asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
+	asn_struct_ctx_t *ctx,	/* Type decoder context */
+	void *struct_ptr,	/* The structure must be already allocated */
+	const char *xml_tag,	/* Expected XML tag name */
+	void *buf_ptr, size_t size,
+	int (*opt_unexpected_tag_decoder)
+		(void *struct_ptr, void *chunk_buf, size_t chunk_size),
+	ssize_t (*body_receiver)
+		(void *struct_ptr, void *chunk_buf, size_t chunk_size,
+			int have_more)
+	);
+
+
+/*
+ * Fetch the next XER (XML) token from the stream.
+ * The function returns the number of bytes occupied by the chunk type,
+ * returned in the _ch_type. The _ch_type is only set (and valid) when
+ * the return value is greater than 0.
+ */
+  typedef enum pxer_chunk_type {
+	PXER_TAG,	/* Complete XER tag */
+	PXER_TEXT,	/* Plain text between XER tags */
+	PXER_COMMENT,	/* A comment, may be part of */
+  } pxer_chunk_type_e;
+ssize_t xer_next_token(int *stateContext, void *buffer, size_t size,
+	pxer_chunk_type_e *_ch_type);
+
+/*
+ * This function checks the buffer against the tag name is expected to occur.
+ */
+  typedef enum xer_check_tag {
+	XCT_BROKEN,	/* The tag is broken */
+	XCT_UNEXPECTED,	/* The tag is fine, but unexpected */
+	XCT_OPENING,	/* This is the opening <tag> */
+	XCT_CLOSING,	/* This is the closing </tag> */
+	XCT_BOTH,	/* This is the opening and closing tag <tag/> */
+  } xer_check_tag_e;
+xer_check_tag_e xer_check_tag(const void *buf_ptr, int size,
+		const char *need_tag);
+
+#endif	/* _XER_DECODER_H_ */
diff --git a/skeletons/xer_encoder.c b/skeletons/xer_encoder.c
index d3f04d6..5fb0de6 100644
--- a/skeletons/xer_encoder.c
+++ b/skeletons/xer_encoder.c
@@ -21,7 +21,7 @@
 
 	if(!td || !sptr) goto cb_failed;
 
-	mname = td->name;
+	mname = td->xml_tag;
 	mlen = strlen(mname);
 
 	_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
diff --git a/skeletons/xer_support.c b/skeletons/xer_support.c
new file mode 100644
index 0000000..1fe59bc
--- /dev/null
+++ b/skeletons/xer_support.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com.
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <xer_support.h>
+
+/* Parser states */
+typedef enum {
+	ST_TEXT,
+	ST_TAG_START,
+	ST_TAG_BODY,
+	ST_TAG_QUOTE_WAIT,
+	ST_TAG_QUOTED_STRING,
+	ST_TAG_UNQUOTED_STRING,
+	ST_COMMENT_WAIT_DASH1,	// "<!--"[1]
+	ST_COMMENT_WAIT_DASH2,	// "<!--"[2]
+	ST_COMMENT,
+	ST_COMMENT_CLO_DASH2,	// "-->"[0]
+	ST_COMMENT_CLO_RT	// "-->"[1]
+} pstate_e;
+
+static pxml_chunk_type_e final_chunk_type[] = {
+	PXML_TEXT,
+	PXML_TAG_END,
+	PXML_COMMENT_END,
+	PXML_TAG_END,
+	PXML_COMMENT_END,
+};
+
+
+static int
+_charclass[256] = {
+	0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0,
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+	1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+	2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0,	/* 01234567 89       */
+	0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,	/*  ABCDEFG HIJKLMNO */
+	3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0,	/* PQRSTUVW XYZ      */
+	0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,	/*  abcdefg hijklmno */
+	3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0	/* pqrstuvw xyz      */
+};
+#define WHITESPACE(c)	(_charclass[(unsigned char)(c)] == 1)
+#define ALNUM(c)	(_charclass[(unsigned char)(c)] >= 2)
+#define ALPHA(c)	(_charclass[(unsigned char)(c)] == 3)
+
+/* Aliases for characters, ASCII/UTF-8 */
+#define	EXCLAM	0x21	/* '!' */
+#define	CQUOTE	0x22	/* '"' */
+#define	CDASH	0x2d	/* '-' */
+#define	CSLASH	0x2f	/* '/' */
+#define	LANGLE	0x3c	/* '<' */
+#define	CEQUAL	0x3d	/* '=' */
+#define	RANGLE	0x3e	/* '>' */
+
+/* Invoke token callback */
+#define	TOKEN_CB_CALL(type, _ns, _current_too, _final) do {	\
+		int _ret;					\
+		pstate_e ns  = _ns;				\
+		ssize_t _sz = (p - chunk_start) + _current_too;	\
+		if (!_sz) {					\
+			/* Shortcut */				\
+			state = _ns;				\
+			break;					\
+		}						\
+		_ret = cb(type, chunk_start, _sz, key);		\
+		if(_ret < _sz) {				\
+			if(_current_too && _ret == -1)		\
+				state = ns;			\
+			goto finish;				\
+		}						\
+		chunk_start = p + _current_too;			\
+		state = ns;					\
+	} while(0)
+
+#define TOKEN_CB(_type, _ns, _current_too)			\
+	TOKEN_CB_CALL(_type, _ns, _current_too, 0)
+
+#define TOKEN_CB_FINAL(_type, _ns, _current_too)		\
+	TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1)
+
+/*
+ * Parser itself
+ */
+int pxml_parse(int *stateContext, void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) {
+	pstate_e state = (pstate_e)*stateContext;
+	char *chunk_start = (char *)xmlbuf;
+	char *p = chunk_start;
+	char *end = p + size;
+
+	for(; p < end; p++) {
+	  int C = *(unsigned char *)p;
+	  switch(state) {
+	  case ST_TEXT:
+		/*
+		 * Initial state: we're in the middle of some text,
+		 * or just have started.
+		 */
+		if (C == LANGLE) 
+			/* We're now in the tag, probably */
+			TOKEN_CB(PXML_TEXT, ST_TAG_START, 0);
+		break;
+	  case ST_TAG_START:
+		if (ALPHA(C) || (C == CSLASH))
+			state = ST_TAG_BODY;
+		else if (C == EXCLAM)
+			state = ST_COMMENT_WAIT_DASH1;
+		else 
+			/*
+			 * Not characters and not whitespace.
+			 * Must be something like "3 < 4".
+			 */
+			TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */
+		break;
+	  case ST_TAG_BODY:
+		switch(C) {
+		case RANGLE:
+			/* End of the tag */
+			TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
+			break;
+		case LANGLE:
+			/*
+			 * The previous tag wasn't completed, but still
+			 * recognized as valid. (Mozilla-compatible)
+			 */
+			TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0);	
+			break;
+		case CEQUAL:
+			state = ST_TAG_QUOTE_WAIT;
+			break;
+		}
+		break;
+	  case ST_TAG_QUOTE_WAIT:
+		/*
+		 * State after the equal sign ("=") in the tag.
+		 */
+		switch(C) {
+		case CQUOTE:
+			state = ST_TAG_QUOTED_STRING;
+			break;
+		case RANGLE:
+			/* End of the tag */
+			TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
+			break;
+		default:
+			if(!WHITESPACE(C))
+				/* Unquoted string value */
+				state = ST_TAG_UNQUOTED_STRING;
+		}
+		break;
+	  case ST_TAG_QUOTED_STRING:
+		/*
+		 * Tag attribute's string value in quotes.
+		 */
+		if(C == CQUOTE) {
+			/* Return back to the tag state */
+			state = ST_TAG_BODY;
+		}
+		break;
+	  case ST_TAG_UNQUOTED_STRING:
+		if(C == RANGLE) {
+			/* End of the tag */
+			TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
+		} else if(WHITESPACE(C)) {
+			/* Return back to the tag state */
+			state = ST_TAG_BODY;
+		}
+		break;
+	  case ST_COMMENT_WAIT_DASH1:
+		if(C == CDASH) {
+			state = ST_COMMENT_WAIT_DASH2;
+		} else {
+			/* Some ordinary tag. */
+			state = ST_TAG_BODY;
+		}
+		break;
+	  case ST_COMMENT_WAIT_DASH2:
+		if(C == CDASH) {
+			/* Seen "<--" */
+			state = ST_COMMENT;
+		} else {
+			/* Some ordinary tag */
+			state = ST_TAG_BODY;
+		}
+		break;
+	  case ST_COMMENT:
+		if(C == CDASH) {
+			state = ST_COMMENT_CLO_DASH2;
+		}
+		break;
+	  case ST_COMMENT_CLO_DASH2:
+		if(C == CDASH) {
+			state = ST_COMMENT_CLO_RT;
+		} else {
+			/* This is not an end of a comment */
+			state = ST_COMMENT;
+		}
+		break;
+	  case ST_COMMENT_CLO_RT:
+		if(C == RANGLE) {
+			TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1);
+		} else {
+			state = ST_COMMENT;
+		}
+		break;
+	  } /* switch(*ptr) */
+	} /* for() */
+
+	/*
+	 * Flush the partially processed chunk, state permitting.
+	 */
+	if(p - chunk_start) {
+		switch (state) {
+		case ST_COMMENT:
+			TOKEN_CB(PXML_COMMENT, state, 0);
+			break;
+		case ST_TEXT:
+			TOKEN_CB(PXML_TEXT, state, 0);
+			break;
+		default: break;	/* a no-op */
+		}
+	}
+
+finish:
+	*stateContext = (int)state;
+	return chunk_start - (char *)xmlbuf;
+}
+
diff --git a/skeletons/xer_support.h b/skeletons/xer_support.h
new file mode 100644
index 0000000..a1a010c
--- /dev/null
+++ b/skeletons/xer_support.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com.
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_XER_SUPPORT_H_
+#define	_XER_SUPPORT_H_
+
+/*
+ * Types of data transferred to the application.
+ */
+typedef enum {
+	PXML_TEXT,	/* Plain text between XML tags. */
+	PXML_TAG,	/* A tag, starting with '<'. */
+	PXML_COMMENT,	/* An XML comment, including "<!--" and "-->". */
+	/* 
+	 * The following chunk types are reported if the chunk
+	 * terminates the specified XML element.
+	 */
+	PXML_TAG_END,		/* Tag ended */
+	PXML_COMMENT_END	/* Comment ended */
+} pxml_chunk_type_e;
+
+/*
+ * Callback function that is called by the parser when parsed data is
+ * available. The _opaque is the pointer to a field containing opaque user 
+ * data specified in pxml_create() call. The chunk type is _type and the text 
+ * data is the piece of buffer identified by _bufid (as supplied to
+ * pxml_feed() call) starting at offset _offset and of _size bytes size. 
+ * The chunk is NOT '\0'-terminated.
+ */
+typedef int (pxml_callback_f)(pxml_chunk_type_e _type,
+	void *_chunk_data, size_t _chunk_size, void *_key);
+
+/*
+ * Parse the given buffer as it were a chunk of XML data.
+ * Invoke the specified callback each time the meaninful data is found.
+ * This function returns number of bytes consumed from the bufer.
+ * It will always be lesser than or equal to the specified _size.
+ * The next invocation of this function must account the difference.
+ */
+ssize_t pxml_parse(int *_stateContext, void *_buf, size_t _size,
+	pxml_callback_f *cb, void *_key);
+
+#endif	/* _XER_SUPPORT_H_ */