XER support


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@365 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/ANY.c b/skeletons/ANY.c
index 389452c..a1c7711 100644
--- a/skeletons/ANY.c
+++ b/skeletons/ANY.c
@@ -2,17 +2,20 @@
  * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <ANY.h>
 #include <assert.h>
 #include <errno.h>
 
 asn1_TYPE_descriptor_t asn1_DEF_ANY = {
 	"ANY",
+	OCTET_STRING_free,
+	OCTET_STRING_print,
 	asn_generic_no_constraint,
 	OCTET_STRING_decode_ber,
 	OCTET_STRING_encode_der,
-	OCTET_STRING_print,
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	ANY_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	0, 0, 0, 0,
 	-1,	/* Both ways are fine (primitive and constructed) */
@@ -21,6 +24,23 @@
 };
 
 
+asn_enc_rval_t
+ANY_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+
+	(void)ilevel;
+	(void)flags;
+	(void)cb;
+	(void)app_key;
+
+	/*
+	 * XER-encoding of ANY type is not supported.
+	 */
+
+	_ASN_ENCODE_FAILED;
+}
+
 struct _callback_arg {
 	uint8_t *buffer;
 	size_t offset;
@@ -32,7 +52,7 @@
 int
 ANY_fromType(ANY_t *st, asn1_TYPE_descriptor_t *td, void *sptr) {
 	struct _callback_arg arg;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 
 	if(!st || !td) {
 		errno = EINVAL;
@@ -53,7 +73,7 @@
 		if(arg.buffer) FREEMEM(arg.buffer);
 		return -1;
 	}
-	assert(erval.encoded == arg.offset);
+	assert((size_t)erval.encoded == arg.offset);
 
 	if(st->buf) FREEMEM(st->buf);
 	st->buf = arg.buffer;
diff --git a/skeletons/ANY.h b/skeletons/ANY.h
index 719b3a9..d010de4 100644
--- a/skeletons/ANY.h
+++ b/skeletons/ANY.h
@@ -17,10 +17,11 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_ANY;
 
+asn_struct_free_f ANY_free;
+asn_struct_print_f ANY_print;
 ber_type_decoder_f ANY_decode_ber;
 der_type_encoder_f ANY_encode_der;
-asn_struct_print_f ANY_print;
-asn_struct_free_f ANY_free;
+xer_type_encoder_f ANY_encode_xer;
 
 /******************************
  * Handy conversion routines. *
diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c
index a43a22a..b6da3ae 100644
--- a/skeletons/BIT_STRING.c
+++ b/skeletons/BIT_STRING.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <BIT_STRING.h>
 
 /*
@@ -12,11 +13,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	BIT_STRING_print,
-	OCTET_STRING_free,         /* Implemented in terms of OCTET STRING */
+	0,				/* Not implemented yet */
+	BIT_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_BIT_STRING_tags,
 	sizeof(asn1_DEF_BIT_STRING_tags)
@@ -61,6 +64,66 @@
 	return 0;
 }
 
+static char *_bit_pattern[16] = {
+	"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
+	"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
+};
+
+asn_enc_rval_t
+BIT_STRING_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er;
+	char scratch[128];
+	char *p = scratch;
+	char *scend = scratch + (sizeof(scratch) - 10);
+	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+	uint8_t *buf;
+	uint8_t *end;
+
+	if(!st || !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	buf = st->buf;
+	end = buf + st->size - 1;	/* Last byte is special */
+
+	/*
+	 * Binary dump
+	 */
+	for(buf++; buf < end; buf++) {
+		int v = *buf;
+		int nline = (flags & XER_F_CANONICAL)
+			?0:((((buf - st->buf) - 1) % 16) == 0);
+		if(p >= scend || nline) {
+			er.encoded += p - scratch;
+			_ASN_CALLBACK(scratch, p - scratch);
+			p = scratch;
+			if(nline) _i_ASN_TEXT_INDENT(1, ilevel);
+		}
+		memcpy(p + 0, _bit_pattern[v >> 4], 4);
+		memcpy(p + 4, _bit_pattern[v & 0x0f], 4);
+		p += 8;
+	}
+
+	er.encoded += p - scratch;
+	_ASN_CALLBACK(scratch, p - scratch);
+
+	if(buf < end + 1) {
+		int v = *buf;
+		int mbit = st->buf[0];	/* bits to skip from the right */
+		int i;
+		for(i = 7; i >= mbit; i--)
+			*p++ = (v & (1 << i)) ? '1' : '0';
+		er.encoded += p - scratch;
+		_ASN_CALLBACK(scratch, p - scratch);
+	}
+
+	return er;
+}
+
+
 /*
  * BIT STRING specific contents printer.
  */
@@ -99,6 +162,7 @@
 		*p++ = h2c[*buf & 0x0F];
 		*p++ = 0x20;
 	}
+	if(p > scratch) p--;	/* Eat the tailing space */
 
 	/* Dump the incomplete 16-bytes row */
 	return cb(scratch, p - scratch, app_key);
diff --git a/skeletons/BIT_STRING.h b/skeletons/BIT_STRING.h
index 1def8bb..f9ebf9b 100644
--- a/skeletons/BIT_STRING.h
+++ b/skeletons/BIT_STRING.h
@@ -14,5 +14,6 @@
 
 asn_struct_print_f BIT_STRING_print;	/* Human-readable output */
 asn_constr_check_f BIT_STRING_constraint;
+xer_type_encoder_f BIT_STRING_encode_xer;
 
 #endif	/* _BIT_STRING_H_ */
diff --git a/skeletons/BMPString.c b/skeletons/BMPString.c
index 3e779cc..bdbd40d 100644
--- a/skeletons/BMPString.c
+++ b/skeletons/BMPString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <BMPString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	BMPString_print,
-	OCTET_STRING_free,          /* -//- */
+	0,				/* Not implemented yet */
+	BMPString_encode_xer,		/* Conver to UTF8 */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_BMPString_tags,
 	sizeof(asn1_DEF_BMPString_tags)
@@ -33,27 +36,22 @@
 /*
  * BMPString specific contents printer.
  */
-int
-BMPString_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+static ssize_t
+BMPString__dump(const BMPString_t *st,
 		asn_app_consume_bytes_f *cb, void *app_key) {
-	const BMPString_t *st = (const BMPString_t *)sptr;
-	uint16_t *wchar;
-	uint16_t *wend;
 	char scratch[128];			/* Scratchpad buffer */
-	char *p;
+	char *p = scratch;
+	ssize_t wrote = 0;
+	uint8_t *ch;
+	uint8_t *end;
 
-	(void)td;	/* Unused argument */
-	(void)ilevel;	/* Unused argument */
-
-	if(!st || !st->buf) return cb("<absent>", 8, app_key);
-
-	wchar = (uint16_t *)st->buf;
-	wend = (uint16_t *)(st->buf + st->size);
-	for(p = scratch; wchar < wend; wchar++) {
-		uint16_t wc = (((uint8_t *)wchar)[0] << 8)
-				| ((uint8_t *)wchar)[1];	/* 2 bytes */
+	ch = st->buf;
+	end = (st->buf + st->size);
+	for(end--; ch < end; ch += 2) {
+		uint16_t wc = (ch[0] << 8) | ch[1];	/* 2 bytes */
 		if(sizeof(scratch) - (p - scratch) < 3) {
-			if(cb(scratch, p - scratch, app_key))
+			wrote += p - scratch;
+			if(cb(scratch, p - scratch, app_key) < 0)
 				return -1;
 			p = scratch;
 		}
@@ -69,5 +67,45 @@
 		}
 	}
 
-	return cb(scratch, p - scratch, app_key);
+	wrote += p - scratch;
+	if(cb(scratch, p - scratch, app_key) < 0)
+		return -1;
+
+	return wrote;
 }
+
+asn_enc_rval_t
+BMPString_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const BMPString_t *st = (const BMPString_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;
+	(void)flags;
+
+	if(!st || !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = BMPString__dump(st, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
+}
+
+int
+BMPString_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const BMPString_t *st = (const BMPString_t *)sptr;
+
+	(void)td;	/* Unused argument */
+	(void)ilevel;	/* Unused argument */
+
+	if(!st || !st->buf) return cb("<absent>", 8, app_key);
+
+	if(BMPString__dump(st, cb, app_key) < 0)
+		return -1;
+
+	return 0;
+}
+
diff --git a/skeletons/BMPString.h b/skeletons/BMPString.h
index e3957ca..31d67ea 100644
--- a/skeletons/BMPString.h
+++ b/skeletons/BMPString.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #ifndef	_BMPString_H_
@@ -13,5 +13,6 @@
 extern asn1_TYPE_descriptor_t asn1_DEF_BMPString;
 
 asn_struct_print_f BMPString_print;	/* Human-readable output */
+xer_type_encoder_f BMPString_encode_xer;
 
 #endif	/* _BMPString_H_ */
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index 5ba2e4f..9609a19 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <BOOLEAN.h>
 
 /*
@@ -12,11 +13,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_BOOLEAN = {
 	"BOOLEAN",
+	BOOLEAN_free,
+	BOOLEAN_print,
 	asn_generic_no_constraint,
 	BOOLEAN_decode_ber,
 	BOOLEAN_encode_der,
-	BOOLEAN_print,
-	BOOLEAN_free,
+	0,				/* Not implemented yet */
+	BOOLEAN_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_BOOLEAN_tags,
 	sizeof(asn1_DEF_BOOLEAN_tags) / sizeof(asn1_DEF_BOOLEAN_tags[0]),
@@ -93,11 +96,11 @@
 	return rval;
 }
 
-der_enc_rval_t
+asn_enc_rval_t
 BOOLEAN_encode_der(asn1_TYPE_descriptor_t *td, void *sptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	BOOLEAN_t *st = (BOOLEAN_t *)sptr;
 
 	erval.encoded = der_write_tags(td, 1, tag_mode, tag, cb, app_key);
@@ -126,6 +129,29 @@
 	return erval;
 }
 
+asn_enc_rval_t
+BOOLEAN_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const BOOLEAN_t *st = (const BOOLEAN_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;
+	(void)flags;
+
+	if(!st) _ASN_ENCODE_FAILED;
+
+	if(*st) {
+		_ASN_CALLBACK("<true/>", 7);
+		er.encoded = 7;
+	} else {
+		_ASN_CALLBACK("<false/>", 8);
+		er.encoded = 8;
+	}
+
+	return er;
+}
+
 int
 BOOLEAN_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/BOOLEAN.h b/skeletons/BOOLEAN.h
index 6ad69a4..b9b836e 100644
--- a/skeletons/BOOLEAN.h
+++ b/skeletons/BOOLEAN.h
@@ -16,9 +16,10 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_BOOLEAN;
 
+asn_struct_free_f BOOLEAN_free;
+asn_struct_print_f BOOLEAN_print;
 ber_type_decoder_f BOOLEAN_decode_ber;
 der_type_encoder_f BOOLEAN_encode_der;
-asn_struct_print_f BOOLEAN_print;
-asn_struct_free_f BOOLEAN_free;
+xer_type_encoder_f BOOLEAN_encode_xer;
 
 #endif	/* _BOOLEAN_H_ */
diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c
index ed908b5..158119d 100644
--- a/skeletons/ENUMERATED.c
+++ b/skeletons/ENUMERATED.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <ENUMERATED.h>
 
 /*
@@ -12,11 +13,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_ENUMERATED = {
 	"ENUMERATED",
+	INTEGER_free,			/* Implemented in terms of INTEGER */
+	INTEGER_print,			/* Implemented in terms of INTEGER */
 	asn_generic_no_constraint,
 	INTEGER_decode_ber,		/* Implemented in terms of INTEGER */
 	INTEGER_encode_der,		/* Implemented in terms of INTEGER */
-	INTEGER_print,			/* Implemented in terms of INTEGER */
-	INTEGER_free,			/* Implemented in terms of INTEGER */
+	0,				/* Not implemented yet */
+	INTEGER_encode_xer,		/* Implemented in terms of INTEGER */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_ENUMERATED_tags,
 	sizeof(asn1_DEF_ENUMERATED_tags) / sizeof(asn1_DEF_ENUMERATED_tags[0]),
diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c
index dfca2ca..c9d8248 100644
--- a/skeletons/GeneralString.c
+++ b/skeletons/GeneralString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <GeneralString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	OCTET_STRING_print,         /* non-ascii string */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_GeneralString_tags,
 	sizeof(asn1_DEF_GeneralString_tags)
diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c
index 88806f9..8f8fff2 100644
--- a/skeletons/GeneralizedTime.c
+++ b/skeletons/GeneralizedTime.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <GeneralizedTime.h>
 #include <time.h>
 #include <errno.h>
@@ -113,11 +114,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	GeneralizedTime_print,
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	GeneralizedTime_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_GeneralizedTime_tags,
 	sizeof(asn1_DEF_GeneralizedTime_tags)
@@ -153,12 +156,12 @@
 	return 0;
 }
 
-der_enc_rval_t
+asn_enc_rval_t
 GeneralizedTime_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	GeneralizedTime_t *st = (GeneralizedTime_t *)ptr;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 
 	/* If not canonical DER, re-encode into canonical DER. */
 	if(st->size && st->buf[st->size-1] != 'Z') {
@@ -194,6 +197,36 @@
 	return erval;
 }
 
+asn_enc_rval_t
+GeneralizedTime_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	OCTET_STRING_t st;
+
+	if(flags & XER_F_CANONICAL) {
+		char buf[32];
+		struct tm tm;
+		ssize_t ret;
+
+		errno = EPERM;
+		if(asn_GT2time((GeneralizedTime_t *)sptr, &tm, 1) == -1
+				&& errno != EPERM)
+			_ASN_ENCODE_FAILED;
+	
+		ret = snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
+				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+				tm.tm_hour, tm.tm_min, tm.tm_sec);
+		assert(ret > 0 && ret < (int)sizeof(buf));
+	
+		st.buf = (uint8_t *)buf;
+		st.size = ret;
+		sptr = &st;
+	}
+
+	return OCTET_STRING_encode_xer_ascii(td, sptr, ilevel, flags,
+		cb, app_key);
+}
+
 int
 GeneralizedTime_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/GeneralizedTime.h b/skeletons/GeneralizedTime.h
index a7a8a4a..06b4ca5 100644
--- a/skeletons/GeneralizedTime.h
+++ b/skeletons/GeneralizedTime.h
@@ -12,9 +12,10 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_GeneralizedTime;
 
+asn_struct_print_f GeneralizedTime_print;
 asn_constr_check_f GeneralizedTime_constraint;
 der_type_encoder_f GeneralizedTime_encode_der;
-asn_struct_print_f GeneralizedTime_print;
+xer_type_encoder_f GeneralizedTime_encode_xer;
 
 /***********************
  * Some handy helpers. *
diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c
index ceb247d..e8fa797 100644
--- a/skeletons/GraphicString.c
+++ b/skeletons/GraphicString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <GraphicString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	OCTET_STRING_print,         /* non-ascii string */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_GraphicString_tags,
 	sizeof(asn1_DEF_GraphicString_tags)
diff --git a/skeletons/IA5String.c b/skeletons/IA5String.c
index 9fc308b..a2c828d 100644
--- a/skeletons/IA5String.c
+++ b/skeletons/IA5String.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <IA5String.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_IA5String = {
 	"IA5String",
+	OCTET_STRING_free,
+	OCTET_STRING_print_ascii,  /* 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 */
-	OCTET_STRING_print_ascii,  /* ASCII subset */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_IA5String_tags,
 	sizeof(asn1_DEF_IA5String_tags)
@@ -63,3 +66,4 @@
 
 	return 0;
 }
+
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 5bfcf1f..75782a6 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <INTEGER.h>
 #include <assert.h>
 #include <errno.h>
@@ -14,11 +15,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_INTEGER = {
 	"INTEGER",
+	INTEGER_free,
+	INTEGER_print,
 	asn_generic_no_constraint,
 	INTEGER_decode_ber,
 	INTEGER_encode_der,
-	INTEGER_print,
-	INTEGER_free,
+	0,				/* Not implemented yet */
+	INTEGER_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_INTEGER_tags,
 	sizeof(asn1_DEF_INTEGER_tags) / sizeof(asn1_DEF_INTEGER_tags[0]),
@@ -100,11 +103,11 @@
 /*
  * Encode INTEGER type using DER.
  */
-der_enc_rval_t
+asn_enc_rval_t
 INTEGER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	INTEGER_t *st = (INTEGER_t *)ptr;
 
 	ASN_DEBUG("%s %s as INTEGER (tm=%d)",
@@ -185,24 +188,19 @@
 /*
  * INTEGER specific human-readable output.
  */
-int
-INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
-	asn_app_consume_bytes_f *cb, void *app_key) {
+static ssize_t
+INTEGER__dump(const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
 	char scratch[32];	/* Enough for 64-bit integer */
-	const INTEGER_t *st = (const INTEGER_t *)sptr;
 	uint8_t *buf = st->buf;
 	uint8_t *buf_end = st->buf + st->size;
 	signed long accum;
+	ssize_t wrote = 0;
 	char *p;
 	int ret;
 
-	(void)td;	/* Unused argument */
-	(void)ilevel;	/* Unused argument */
-
-	if(!st && !st->buf) return cb("<absent>", 8, app_key);
-
-	if(st->size == 0)
-		return cb("0", 1, app_key);
+	if(st->size == 0) {
+		return (cb("0", 1, app_key) < 0) ? -1 : 1;
+	}
 
 	/*
 	 * Advance buf pointer until the start of the value's body.
@@ -226,7 +224,7 @@
 			accum = (accum << 8) | *buf;
 		ret = snprintf(scratch, sizeof(scratch), "%ld", accum);
 		assert(ret > 0 && ret < (int)sizeof(scratch));
-		return cb(scratch, ret, app_key);
+		return (cb(scratch, ret, app_key) < 0) ? -1 : ret;
 	}
 
 	/* Output in the long xx:yy:zz... format */
@@ -235,8 +233,9 @@
 		static const char *h2c = "0123456789ABCDEF";
 		if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) {
 			/* Flush buffer */
-			if(cb(scratch, p - scratch, app_key))
+			if(cb(scratch, p - scratch, app_key) < 0)
 				return -1;
+			wrote += p - scratch;
 			p = scratch;
 		}
 		*p++ = h2c[*buf >> 4];
@@ -246,7 +245,43 @@
 	if(p != scratch)
 		p--;	/* Remove the last ':' */
 
-	return cb(scratch, p - scratch, app_key);
+	wrote += p - scratch;
+	return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote;
+}
+
+/*
+ * INTEGER specific human-readable output.
+ */
+int
+INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+	asn_app_consume_bytes_f *cb, void *app_key) {
+	const INTEGER_t *st = (const INTEGER_t *)sptr;
+
+	(void)td;
+	(void)ilevel;
+
+	if(!st && !st->buf) return cb("<absent>", 8, app_key);
+
+	return (INTEGER__dump(st, cb, app_key) < 0) ? -1 : 0;
+}
+
+asn_enc_rval_t
+INTEGER_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const INTEGER_t *st = (const INTEGER_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;
+	(void)flags;
+	
+	if(!st && !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = INTEGER__dump(st, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
 }
 
 void
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
index ef4d3f2..8e3c545 100644
--- a/skeletons/INTEGER.h
+++ b/skeletons/INTEGER.h
@@ -14,10 +14,11 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_INTEGER;
 
+asn_struct_free_f INTEGER_free;
+asn_struct_print_f INTEGER_print;
 ber_type_decoder_f INTEGER_decode_ber;
 der_type_encoder_f INTEGER_encode_der;
-asn_struct_print_f INTEGER_print;
-asn_struct_free_f INTEGER_free;
+xer_type_encoder_f INTEGER_encode_xer;
 
 /***********************************
  * Some handy conversion routines. *
diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c
index 8a99cbc..e5a4d44 100644
--- a/skeletons/ISO646String.c
+++ b/skeletons/ISO646String.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <ISO646String.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_ISO646String = {
 	"ISO646String",
+	OCTET_STRING_free,
+	OCTET_STRING_print_ascii,   /* ASCII subset */
 	VisibleString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_print_ascii,   /* ASCII subset */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_ISO646String_tags,
 	sizeof(asn1_DEF_ISO646String_tags)
diff --git a/skeletons/NULL.c b/skeletons/NULL.c
index 36796b8..e15b9af 100644
--- a/skeletons/NULL.c
+++ b/skeletons/NULL.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <NULL.h>
 #include <BOOLEAN.h>	/* Implemented in terms of BOOLEAN type */
 
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_NULL = {
 	"NULL",
+	BOOLEAN_free,
+	NULL_print,
 	asn_generic_no_constraint,
 	BOOLEAN_decode_ber,	/* Implemented in terms of BOOLEAN */
 	NULL_encode_der,	/* Special handling of DER encoding */
-	NULL_print,
-	BOOLEAN_free,
+	0,				/* Not implemented yet */
+	NULL_encode_xer,	/* Special handling of DER encoding */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_NULL_tags,
 	sizeof(asn1_DEF_NULL_tags) / sizeof(asn1_DEF_NULL_tags[0]),
@@ -28,21 +31,40 @@
 	0	/* No specifics */
 };
 
-der_enc_rval_t
-NULL_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+asn_enc_rval_t
+NULL_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 
-	erval.encoded = der_write_tags(sd, 0, tag_mode, tag, cb, app_key);
+	erval.encoded = der_write_tags(td, 0, tag_mode, tag, cb, app_key);
 	if(erval.encoded == -1) {
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 	}
 
 	return erval;
 }
 
+asn_enc_rval_t
+NULL_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er;
+
+	(void)td;
+	(void)sptr;
+	(void)ilevel;
+	(void)flags;
+	(void)cb;
+	(void)app_key;
+
+	/* XMLNullValue is empty */
+	er.encoded = 0;
+
+	return er;
+}
+
 int
 NULL_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/NULL.h b/skeletons/NULL.h
index 003a5a6..0c07ffe 100644
--- a/skeletons/NULL.h
+++ b/skeletons/NULL.h
@@ -15,7 +15,8 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_NULL;
 
-der_type_encoder_f NULL_encode_der;
 asn_struct_print_f NULL_print;
+der_type_encoder_f NULL_encode_der;
+xer_type_encoder_f NULL_encode_xer;
 
 #endif	/* NULL_H */
diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c
index 53ce501..ec4dd88 100644
--- a/skeletons/NativeEnumerated.c
+++ b/skeletons/NativeEnumerated.c
@@ -9,6 +9,7 @@
  * implementation deals with the standard (machine-specific) representation
  * of them instead of using the platform-independent buffer.
  */
+#include <asn_internal.h>
 #include <NativeEnumerated.h>
 
 /*
@@ -19,11 +20,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_NativeEnumerated = {
 	"ENUMERATED",			/* The ASN.1 type is still ENUMERATED */
+	NativeInteger_free,
+	NativeInteger_print,
 	asn_generic_no_constraint,
 	NativeInteger_decode_ber,
 	NativeInteger_encode_der,
-	NativeInteger_print,
-	NativeInteger_free,
+	0,				/* Not implemented yet */
+	NativeInteger_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_NativeEnumerated_tags,
 	sizeof(asn1_DEF_NativeEnumerated_tags) / sizeof(asn1_DEF_NativeEnumerated_tags[0]),
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
index 98fee96..b0872a2 100644
--- a/skeletons/NativeInteger.c
+++ b/skeletons/NativeInteger.c
@@ -9,6 +9,7 @@
  * implementation deals with the standard (machine-specific) representation
  * of them instead of using the platform-independent buffer.
  */
+#include <asn_internal.h>
 #include <NativeInteger.h>
 #include <INTEGER.h>
 #include <assert.h>
@@ -21,11 +22,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_NativeInteger = {
 	"INTEGER",			/* The ASN.1 type is still INTEGER */
+	NativeInteger_free,
+	NativeInteger_print,
 	asn_generic_no_constraint,
 	NativeInteger_decode_ber,
 	NativeInteger_encode_der,
-	NativeInteger_print,
-	NativeInteger_free,
+	0,				/* Not implemented yet */
+	NativeInteger_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_NativeInteger_tags,
 	sizeof(asn1_DEF_NativeInteger_tags) / sizeof(asn1_DEF_NativeInteger_tags[0]),
@@ -127,17 +130,17 @@
 /*
  * Encode the NativeInteger using the standard INTEGER type DER encoder.
  */
-der_enc_rval_t
+asn_enc_rval_t
 NativeInteger_encode_der(asn1_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. */
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	INTEGER_t tmp;
 
 #ifdef	WORDS_BIGENDIAN		/* Opportunistic optimization */
 
-	tmp.buf = &Int;
+	tmp.buf = (uint8_t *)&Int;
 	tmp.size = sizeof(Int);
 
 #else	/* Works even if WORDS_BIGENDIAN is not set where should've been */
@@ -161,6 +164,27 @@
 	return erval;
 }
 
+asn_enc_rval_t
+NativeInteger_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		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;
+
+	(void)ilevel;
+	(void)flags;
+
+	if(!Int) _ASN_ENCODE_FAILED;
+
+	er.encoded = snprintf(scratch, sizeof(scratch), "%d", *Int);
+	if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch)
+		|| cb(scratch, er.encoded, app_key) < 0)
+		_ASN_ENCODE_FAILED;
+
+	return er;
+}
+
 /*
  * INTEGER specific human-readable output.
  */
diff --git a/skeletons/NativeInteger.h b/skeletons/NativeInteger.h
index e0f26c7..2d0cdda 100644
--- a/skeletons/NativeInteger.h
+++ b/skeletons/NativeInteger.h
@@ -16,9 +16,10 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_NativeInteger;
 
+asn_struct_free_f  NativeInteger_free;
+asn_struct_print_f NativeInteger_print;
 ber_type_decoder_f NativeInteger_decode_ber;
 der_type_encoder_f NativeInteger_encode_der;
-asn_struct_print_f NativeInteger_print;
-asn_struct_free_f  NativeInteger_free;
+xer_type_encoder_f NativeInteger_encode_xer;
 
 #endif	/* _NativeInteger_H_ */
diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c
index e7cc28f..1566a7f 100644
--- a/skeletons/NativeReal.c
+++ b/skeletons/NativeReal.c
@@ -9,6 +9,7 @@
  * implementation deals with the standard (machine-specific) representation
  * of them instead of using the platform-independent buffer.
  */
+#include <asn_internal.h>
 #include <NativeReal.h>
 #include <INTEGER.h>
 #include <REAL.h>
@@ -22,11 +23,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_NativeReal = {
 	"REAL",			/* The ASN.1 type is still REAL */
+	NativeReal_free,
+	NativeReal_print,
 	asn_generic_no_constraint,
 	NativeReal_decode_ber,
 	NativeReal_encode_der,
-	NativeReal_print,
-	NativeReal_free,
+	0,				/* Not implemented yet */
+	NativeReal_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_NativeReal_tags,
 	sizeof(asn1_DEF_NativeReal_tags) / sizeof(asn1_DEF_NativeReal_tags[0]),
@@ -116,12 +119,12 @@
 /*
  * Encode the NativeReal using the standard REAL type DER encoder.
  */
-der_enc_rval_t
+asn_enc_rval_t
 NativeReal_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	double Dbl = *(const double *)ptr;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	REAL_t tmp;
 
 	if(asn1_double2REAL(&tmp, Dbl)) {
@@ -140,6 +143,25 @@
 	return erval;
 }
 
+
+asn_enc_rval_t
+NativeReal_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const double *Dbl = (const double *)sptr;
+	asn_enc_rval_t er;
+	double d;
+
+	(void)ilevel;
+
+	if(!Dbl) _ASN_ENCODE_FAILED;
+
+	er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
+}
+
 /*
  * REAL specific human-readable output.
  */
@@ -147,32 +169,13 @@
 NativeReal_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	const double *Dbl = (const double *)sptr;
-	char scratch[64];
-	int ret;
 
 	(void)td;	/* Unused argument */
 	(void)ilevel;	/* Unused argument */
 
-	if(Dbl) {
-		char *p = scratch;
-		int buf_size = sizeof(scratch);
-	    for(;;) {
-		ret = snprintf(p, buf_size, "%f", *Dbl);
-		if(ret >= 0 && ret < buf_size) {
-			ret = cb(p, ret, app_key);
-			if(p != scratch) free(p);
-			return ret;
-		} else {
-			if(p != scratch) free(p);
-		}
-		if(ret < 0) buf_size <<= 2;	/* Old libc. */
-		else buf_size = ret + 1;
-		(void *)p = MALLOC(ret);
-		if(!p) return -1;
-	    }
-	} else {
-		return cb("<absent>", 8, app_key);
-	}
+	if(!Dbl) return cb("<absent>", 8, app_key);
+
+	return (REAL__dump(*Dbl, 0, cb, app_key) < 0) ? -1 : 0;
 }
 
 void
diff --git a/skeletons/NativeReal.h b/skeletons/NativeReal.h
index 1a5436d..a130a33 100644
--- a/skeletons/NativeReal.h
+++ b/skeletons/NativeReal.h
@@ -15,9 +15,10 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_NativeReal;
 
+asn_struct_free_f  NativeReal_free;
+asn_struct_print_f NativeReal_print;
 ber_type_decoder_f NativeReal_decode_ber;
 der_type_encoder_f NativeReal_encode_der;
-asn_struct_print_f NativeReal_print;
-asn_struct_free_f  NativeReal_free;
+xer_type_encoder_f NativeReal_encode_xer;
 
 #endif	/* ASN_TYPE_NativeReal_H */
diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c
index a23e39f..b4a6df9 100644
--- a/skeletons/NumericString.c
+++ b/skeletons/NumericString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <NumericString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_NumericString = {
 	"NumericString",
+	OCTET_STRING_free,
+	OCTET_STRING_print_ascii,   /* ASCII subset */
 	NumericString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_print_ascii,   /* ASCII subset */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_NumericString_tags,
 	sizeof(asn1_DEF_NumericString_tags)
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index c55410d..43ced79 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <OBJECT_IDENTIFIER.h>
 #include <limits.h>	/* for CHAR_BIT */
 #include <assert.h>
@@ -15,11 +16,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER = {
 	"OBJECT IDENTIFIER",
+	INTEGER_free,
+	OBJECT_IDENTIFIER_print,
 	OBJECT_IDENTIFIER_constraint,
 	INTEGER_decode_ber,	/* Implemented in terms of INTEGER type */
 	OBJECT_IDENTIFIER_encode_der,
-	OBJECT_IDENTIFIER_print,
-	INTEGER_free,
+	0,				/* Not implemented yet */
+	OBJECT_IDENTIFIER_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_OBJECT_IDENTIFIER_tags,
 	sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags)
@@ -36,11 +39,11 @@
 /*
  * Encode OBJECT IDENTIFIER type using DER.
  */
-der_enc_rval_t
+asn_enc_rval_t
 OBJECT_IDENTIFIER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)ptr;
 
 	ASN_DEBUG("%s %s as OBJECT IDENTIFIER (tm=%d)",
@@ -57,10 +60,8 @@
 	}
 
 	if(cb && st->buf) {
-		ssize_t ret;
-
-		ret = cb(st->buf, st->size, app_key);
-		if(ret == -1) {
+		int ret = cb(st->buf, st->size, app_key);
+		if(ret < 0) {
 			erval.encoded = -1;
 			erval.failed_type = sd;
 			erval.structure_ptr = ptr;
@@ -215,9 +216,8 @@
 	return 0;
 }
 
-
-int
-OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
+ssize_t
+OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add,
 		asn_app_consume_bytes_f *cb, void *app_key) {
 	char scratch[64];	/* Conservative estimate */
 	unsigned long accum;	/* Bits accumulator */
@@ -228,36 +228,42 @@
 		return -1;
 
 	if(accum) {
+		ssize_t len;
+
 		/* Fill the scratch buffer in reverse. */
 		p = scratch + sizeof(scratch);
 		for(; accum; accum /= 10)
-			*(--p) = (char)(accum % 10) + 0x30;
+			*(--p) = (char)(accum % 10) + 0x30; /* Put a digit */
 
-		return cb(p, sizeof(scratch) - (p - scratch), app_key);
+		len = sizeof(scratch) - (p - scratch);
+		if(cb(p, len, app_key) < 0)
+			return -1;
+		return len;
 	} else {
 		*scratch = 0x30;
-		return cb(scratch, 1, app_key);
+		if(cb(scratch, 1, app_key) < 0)
+			return -1;
+		return 1;
 	}
 }
 
 int
-OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
-	int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
-	const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
+OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+
+	if(OBJECT_IDENTIFIER__dump_arc(arcbuf, arclen, add, cb, app_key) < 0)
+		return -1;
+
+	return 0;
+}
+
+static ssize_t
+OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
+	ssize_t wrote_len = 0;
 	int startn;
 	int add = 0;
 	int i;
 
-	(void)td;	/* Unused argument */
-	(void)ilevel;	/* Unused argument */
-
-	if(!st || !st->buf)
-		return cb("<absent>", 8, app_key);
-
-	/* Dump preamble */
-	if(cb("{ ", 2, app_key))
-		return -1;
-
 	for(i = 0, startn = 0; i < st->size; i++) {
 		uint8_t b = st->buf[i];
 		if((b & 0x80))			/* Continuation expected */
@@ -269,30 +275,71 @@
 			 */
 			if(i) {
 				add = -80;
-				if(cb("2", 1, app_key)) return -1;
+				if(cb("2", 1, app_key) < 0) return -1;
 			} else if(b <= 39) {
 				add = 0;
-				if(cb("0", 1, app_key)) return -1;
+				if(cb("0", 1, app_key) < 0) return -1;
 			} else if(b < 79) {
 				add = -40;
-				if(cb("1", 1, app_key)) return -1;
+				if(cb("1", 1, app_key) < 0) return -1;
 			} else {
 				add = -80;
-				if(cb("2", 1, app_key)) return -1;
+				if(cb("2", 1, app_key) < 0) return -1;
 			}
+			wrote_len += 1;
 		}
 
-		if(cb(" ", 1, app_key))	/* Separate arcs */
+		if(cb(".", 1, app_key) < 0)	/* Separate arcs */
 			return -1;
 
-		if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
-				i - startn + 1, add,
-				cb, app_key))
-			return -1;
+		add = OBJECT_IDENTIFIER__dump_arc(&st->buf[startn],
+				i - startn + 1, add, cb, app_key);
+		if(add < 0) return -1;
+		wrote_len += 1 + add;
 		startn = i + 1;
 		add = 0;
 	}
 
+	return wrote_len;
+}
+
+asn_enc_rval_t
+OBJECT_IDENTIFIER_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;
+	(void)flags;
+
+	if(!st || !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
+}
+
+int
+OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
+	int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
+	const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
+
+	(void)td;	/* Unused argument */
+	(void)ilevel;	/* Unused argument */
+
+	if(!st || !st->buf)
+		return cb("<absent>", 8, app_key);
+
+	/* Dump preamble */
+	if(cb("{ ", 2, app_key))
+		return -1;
+
+	if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0)
+		return -1;
+
 	return cb(" }", 2, app_key);
 }
 
diff --git a/skeletons/OBJECT_IDENTIFIER.h b/skeletons/OBJECT_IDENTIFIER.h
index 8d43c99..4f45090 100644
--- a/skeletons/OBJECT_IDENTIFIER.h
+++ b/skeletons/OBJECT_IDENTIFIER.h
@@ -12,9 +12,10 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER;
 
-der_type_encoder_f OBJECT_IDENTIFIER_encode_der;
-asn_constr_check_f OBJECT_IDENTIFIER_constraint;
 asn_struct_print_f OBJECT_IDENTIFIER_print;
+asn_constr_check_f OBJECT_IDENTIFIER_constraint;
+der_type_encoder_f OBJECT_IDENTIFIER_encode_der;
+xer_type_encoder_f OBJECT_IDENTIFIER_encode_xer;
 
 /**********************************
  * Some handy conversion routines *
@@ -27,6 +28,10 @@
 	int add, /* Arbitrary offset, required to process the first two arcs */
 	asn_app_consume_bytes_f *cb, void *app_key);
 
+/* Same as above, but returns the number of written digits, instead of 0 */
+ssize_t OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add,
+	asn_app_consume_bytes_f *cb, void *app_key);
+
 /*
  * This function fills an (_arcs) array with OBJECT IDENTIFIER arcs
  * up to specified (_arc_slots) elements.
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
index e0af730..4b7bd66 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <OCTET_STRING.h>
 #include <assert.h>
 #include <errno.h>
@@ -14,11 +15,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING = {
 	"OCTET STRING",
+	OCTET_STRING_free,
+	OCTET_STRING_print,	/* non-ascii stuff, generally */
 	asn_generic_no_constraint,
 	OCTET_STRING_decode_ber,
 	OCTET_STRING_encode_der,
-	OCTET_STRING_print,	/* non-ascii stuff, generally */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_OCTET_STRING_tags,
 	sizeof(asn1_DEF_OCTET_STRING_tags)
@@ -440,11 +443,11 @@
 /*
  * Encode OCTET STRING type using DER.
  */
-der_enc_rval_t
+asn_enc_rval_t
 OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	OCTET_STRING_t *st = (OCTET_STRING_t *)ptr;
 	int add_byte = 0;
 	int is_bit_str = (td->specifics == (void *)-1);
@@ -514,6 +517,84 @@
 	return erval;
 }
 
+asn_enc_rval_t
+OCTET_STRING_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	static const char *h2c = "0123456789ABCDEF";
+	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+	asn_enc_rval_t er;
+	char scratch[16 * 3 + 4];
+	char *p = scratch;
+	uint8_t *buf;
+	uint8_t *end;
+	size_t i;
+
+	if(!st || !st->buf) {
+		er.encoded = -1;
+		er.failed_type = td;
+		er.structure_ptr = sptr;
+		return er;
+	}
+
+	er.encoded = 0;
+
+	/*
+	 * Dump the contents of the buffer in hexadecimal.
+	 */
+	buf = st->buf;
+	end = buf + st->size;
+	if(flags & XER_F_CANONICAL) {
+		char *scend = scratch + (sizeof(scratch) - 2);
+		for(; buf < end; buf++) {
+			if(p >= scend) {
+				_ASN_CALLBACK(scratch, p - scratch);
+				er.encoded += p - scratch;
+				p = scratch;
+			}
+			*p++ = h2c[(*buf >> 4) & 0x0F];
+			*p++ = h2c[*buf & 0x0F];
+		}
+	} else {
+		for(i = 0; buf < end; buf++, i++) {
+			if(!(i % 16) && (i || st->size > 16)) {
+				_ASN_CALLBACK(scratch, p-scratch);
+				er.encoded += (p-scratch);
+				p = scratch;
+				_i_ASN_TEXT_INDENT(1, ilevel);
+			}
+			*p++ = h2c[(*buf >> 4) & 0x0F];
+			*p++ = h2c[*buf & 0x0F];
+			*p++ = 0x20;
+		}
+		if(i) p--;	/* Remove the tail space */
+	}
+
+	_ASN_CALLBACK(scratch, p-scratch);	/* Dump the rest */
+	er.encoded += p - scratch;
+
+	return er;
+}
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer_ascii(asn1_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;
+	asn_enc_rval_t er;
+
+	(void)ilevel;	/* Unused argument */
+	(void)flags;	/* Unused argument */
+
+	if(!st || !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	_ASN_CALLBACK(st->buf, st->size);
+	er.encoded = st->size;
+
+	return er;
+}
+
 int
 OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
@@ -524,7 +605,7 @@
 	uint8_t *buf;
 	uint8_t *end;
 	size_t i;
-	int ret;
+	int lvl;
 
 	(void)td;	/* Unused argument */
 
@@ -540,14 +621,15 @@
 			if(cb(scratch, p - scratch, app_key)
 			|| cb("\n", 1, app_key))
 				return -1;
-			for(ret = 0; ret < ilevel; ret++)
+			for(lvl = 0; lvl < ilevel; lvl++)
 				cb(" ", 1, app_key);
 			p = scratch;
 		}
 		*p++ = h2c[(*buf >> 4) & 0x0F];
 		*p++ = h2c[*buf & 0x0F];
-		*p++ = ' ';
+		*p++ = 0x20;
 	}
+	if(i) p--;	/* Remove the tail space */
 
 	return cb(scratch, p - scratch, app_key);
 }
diff --git a/skeletons/OCTET_STRING.h b/skeletons/OCTET_STRING.h
index df6ff4f..a67cef9 100644
--- a/skeletons/OCTET_STRING.h
+++ b/skeletons/OCTET_STRING.h
@@ -16,11 +16,13 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING;
 
-ber_type_decoder_f OCTET_STRING_decode_ber;
-der_type_encoder_f OCTET_STRING_encode_der;
+asn_struct_free_f OCTET_STRING_free;
 asn_struct_print_f OCTET_STRING_print;
 asn_struct_print_f OCTET_STRING_print_ascii;
-asn_struct_free_f OCTET_STRING_free;
+ber_type_decoder_f OCTET_STRING_decode_ber;
+der_type_encoder_f OCTET_STRING_encode_der;
+xer_type_encoder_f OCTET_STRING_encode_xer;
+xer_type_encoder_f OCTET_STRING_encode_xer_ascii;
 
 /***********************************
  * Some handy conversion routines. *
diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c
index 5017918..4ddcaac 100644
--- a/skeletons/ObjectDescriptor.c
+++ b/skeletons/ObjectDescriptor.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <ObjectDescriptor.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_ObjectDescriptor = {
 	"ObjectDescriptor",
+	OCTET_STRING_free,
+	OCTET_STRING_print_ascii,   /* 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 */
-	OCTET_STRING_print_ascii,   /* Treat as ASCII subset (it's not) */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_ObjectDescriptor_tags,
 	sizeof(asn1_DEF_ObjectDescriptor_tags)
diff --git a/skeletons/PrintableString.c b/skeletons/PrintableString.c
index c37de49..1368447 100644
--- a/skeletons/PrintableString.c
+++ b/skeletons/PrintableString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <PrintableString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_PrintableString = {
 	"PrintableString",
+	OCTET_STRING_free,
+	OCTET_STRING_print_ascii,   /* ASCII subset */
 	PrintableString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_print_ascii,   /* ASCII subset */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_PrintableString_tags,
 	sizeof(asn1_DEF_PrintableString_tags)
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index e42a061..7c23010 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <REAL.h>
 #include <INTEGER.h>
 #include <stdlib.h>	/* for strtod(3) */
@@ -29,11 +30,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_REAL = {
 	"REAL",
+	INTEGER_free,
+	REAL_print,
 	asn_generic_no_constraint,
 	INTEGER_decode_ber,	/* Implemented in terms of INTEGER type */
 	INTEGER_encode_der,
-	REAL_print,
-	INTEGER_free,
+	0,				/* Not implemented yet */
+	REAL_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_REAL_tags,
 	sizeof(asn1_DEF_REAL_tags) / sizeof(asn1_DEF_REAL_tags[0]),
@@ -44,33 +47,113 @@
 	0	/* No specifics */
 };
 
+ssize_t
+REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) {
+	char local_buf[32];
+	char *buf = local_buf;
+	ssize_t buflen = sizeof(local_buf);
+	const char *fmt = canonical?"%15E":"f";
+	ssize_t ret;
+
+	do {
+		ret = snprintf(buf, buflen, fmt, d);
+		if(ret < 0) {
+			buflen <<= 1;
+		} else if(ret >= buflen) {
+			buflen = ret + 1;
+		} else {
+			buflen = ret;
+			break;
+		}
+		if(buf != local_buf) free(buf);
+		(void *)buf = MALLOC(buflen);
+		if(!buf) return -1;
+	} while(1);
+
+	/*
+	 * Transform the "[-]d.dddE+-dd" output into "[-]d.dddE[-]d"
+	 */
+	if(canonical) {
+		char *dot, *E;
+		char *end = buf + buflen;
+
+		dot = (buf[0] == '-') ? (buf + 2) : (buf + 1);
+		if(*dot >= 0x30) {
+			errno = EINVAL;
+			return -1;	/* Not a dot, really */
+		}
+		*dot = '.';		/* Replace possible comma */
+
+		for(E = dot; dot < end; E++) {
+			if(*E == 'E') {
+				char *s = ++E;
+				if(*E == '+') {
+					/* Skip the "+" too */
+					buflen -= 2;
+				} else {
+					buflen -= 1;
+					s++;
+				}
+				E += 2;
+				if(E[-1] != '0' || E > end) {
+					errno = EINVAL;
+					return -1;
+				}
+				for(; E <= end; s++, E++)
+					*s = *E;
+			}
+		}
+		if(E == end) {
+			errno = EINVAL;
+			return -1;		/* No promised E */
+		}
+	}
+
+	ret = cb(buf, buflen, app_key);
+	if(buf != local_buf) free(buf);
+	return (ret < 0) ? -1 : buflen;
+}
+
 int
 REAL_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	const REAL_t *st = (const REAL_t *)sptr;
-	char buf[128];
 	double d;
-	int ret;
 
 	(void)td;	/* Unused argument */
 	(void)ilevel;	/* Unused argument */
 
-	if(!st)
+	if(!st || !st->buf)
 		return cb("<absent>", 8, app_key);
 
 	if(asn1_REAL2double(st, &d))
 		return cb("<error>", 7, app_key);
 
-	ret = snprintf(buf, sizeof(buf), "%f", d);
-	if(ret < 0 || ret >= sizeof(buf))
-		return cb("<error>", 7, app_key);
+	return (REAL__dump(d, 0, cb, app_key) < 0) ? -1 : 0;
+}
 
-	return cb(buf, ret, app_key);
+asn_enc_rval_t
+REAL_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	REAL_t *st = (REAL_t *)sptr;
+	asn_enc_rval_t er;
+	double d;
+
+	(void)ilevel;
+
+	if(!st || !st->buf || asn1_REAL2double(st, &d))
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = REAL__dump(d, flags & XER_F_CANONICAL, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
 }
 
 int
 asn1_REAL2double(const REAL_t *st, double *dbl_value) {
-	unsigned long octv;
+	unsigned int octv;
 
 	if(!st || !st->buf) {
 		errno = EINVAL;
@@ -158,7 +241,7 @@
 	sign = (octv & 0x40);	/* bit 7 */
 	scaleF = (octv & 0x0C) >> 2;	/* bits 4 to 3 */
 
-	if(st->size <= (1 + (octv & 0x03))) {
+	if(st->size <= (int)(1 + (octv & 0x03))) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -166,7 +249,7 @@
 	if((octv & 0x03) == 0x11) {
 		/* 8.5.6.4, case d) */
 		elen = st->buf[1];	/* unsigned binary number */
-		if(elen == 0 || st->size <= (2 + elen)) {
+		if(elen == 0 || st->size <= (int)(2 + elen)) {
 			errno = EINVAL;
 			return -1;
 		}
diff --git a/skeletons/REAL.h b/skeletons/REAL.h
index 751000b..83f96d0 100644
--- a/skeletons/REAL.h
+++ b/skeletons/REAL.h
@@ -15,11 +15,14 @@
 extern asn1_TYPE_descriptor_t asn1_DEF_REAL;
 
 asn_struct_print_f REAL_print;
+xer_type_encoder_f REAL_encode_xer;
 
 /***********************************
  * Some handy conversion routines. *
  ***********************************/
 
+ssize_t REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key);
+
 /*
  * Convert between native double type and REAL representation (DER).
  * RETURN VALUES:
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index bee795c..5d1e1a9 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <RELATIVE-OID.h>
 #include <limits.h>	/* for CHAR_BIT */
 #include <assert.h>
@@ -15,11 +16,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_RELATIVE_OID = {
 	"RELATIVE-OID",
+	INTEGER_free,
+	RELATIVE_OID_print,
 	asn_generic_no_constraint,
 	INTEGER_decode_ber,	/* Implemented in terms of INTEGER type */
 	OBJECT_IDENTIFIER_encode_der,
-	RELATIVE_OID_print,
-	INTEGER_free,
+	0,				/* Not implemented yet */
+	RELATIVE_OID_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_RELATIVE_OID_tags,
 	sizeof(asn1_DEF_RELATIVE_OID_tags)
@@ -32,12 +35,39 @@
 	0	/* No specifics */
 };
 
+static ssize_t
+RELATIVE_OID__dump_body(const RELATIVE_OID_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
+	ssize_t wrote = 0;
+	ssize_t ret;
+	int startn;
+	int i;
+
+	for(i = 0, startn = 0; i < st->size; i++) {
+		uint8_t b = st->buf[i];
+		if((b & 0x80))			/* Continuation expected */
+			continue;
+		if(startn) {
+			/* Separate arcs */
+			if(cb(".", 1, app_key) < 0)
+				return -1;
+			wrote++;
+		}
+
+		ret = OBJECT_IDENTIFIER__dump_arc(&st->buf[startn],
+			i - startn + 1, 0, cb, app_key);
+		if(ret < 0) return -1;
+		wrote += ret;
+
+		startn = i + 1;
+	}
+
+	return wrote;
+}
+
 int
 RELATIVE_OID_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	const RELATIVE_OID_t *st = (const RELATIVE_OID_t *)sptr;
-	int startn;
-	int i;
 
 	(void)td;	/* Unused argument */
 	(void)ilevel;	/* Unused argument */
@@ -49,21 +79,30 @@
 	if(cb("{ ", 2, app_key))
 		return -1;
 
-	for(i = 0, startn = 0; i < st->size; i++) {
-		uint8_t b = st->buf[i];
-		if((b & 0x80))			/* Continuation expected */
-			continue;
-		if(startn && cb(" ", 1, app_key))	/* Separate arcs */
-			return -1;
-		if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
-			i - startn + 1, 0, cb, app_key))
-			return -1;
-		startn = i + 1;
-	}
+	if(RELATIVE_OID__dump_body(st, cb, app_key) < 0)
+		return -1;
 
 	return cb(" }", 2, app_key);
 }
 
+asn_enc_rval_t
+RELATIVE_OID_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;	/* Unused argument */
+	(void)flags;	/* Unused argument */
+
+	if(!st || !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = RELATIVE_OID__dump_body(st, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
+}
 
 int
 RELATIVE_OID_get_arcs(RELATIVE_OID_t *roid,
diff --git a/skeletons/RELATIVE-OID.h b/skeletons/RELATIVE-OID.h
index 1dafb62..e6af934 100644
--- a/skeletons/RELATIVE-OID.h
+++ b/skeletons/RELATIVE-OID.h
@@ -14,6 +14,7 @@
 extern asn1_TYPE_descriptor_t asn1_DEF_RELATIVE_OID;
 
 asn_struct_print_f RELATIVE_OID_print;
+xer_type_encoder_f RELATIVE_OID_encode_xer;
 
 /**********************************
  * Some handy conversion routines *
diff --git a/skeletons/T61String.c b/skeletons/T61String.c
index b306a5b..d2ac2d5 100644
--- a/skeletons/T61String.c
+++ b/skeletons/T61String.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <T61String.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	OCTET_STRING_print,         /* non-ascii string */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_T61String_tags,
 	sizeof(asn1_DEF_T61String_tags)
diff --git a/skeletons/TeletexString.c b/skeletons/TeletexString.c
index 09f3eb6..7a56953 100644
--- a/skeletons/TeletexString.c
+++ b/skeletons/TeletexString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <TeletexString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	OCTET_STRING_print,         /* non-ascii string */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_TeletexString_tags,
 	sizeof(asn1_DEF_TeletexString_tags)
diff --git a/skeletons/UTCTime.c b/skeletons/UTCTime.c
index 029a43e..22e5498 100644
--- a/skeletons/UTCTime.c
+++ b/skeletons/UTCTime.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <UTCTime.h>
 #include <GeneralizedTime.h>
 #include <time.h>
@@ -18,11 +19,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	UTCTime_print,
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	UTCTime_encode_xer,
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_UTCTime_tags,
 	sizeof(asn1_DEF_UTCTime_tags)
@@ -58,6 +61,36 @@
 	return 0;
 }
 
+asn_enc_rval_t
+UTCTime_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	OCTET_STRING_t st;
+
+	if(flags & XER_F_CANONICAL) {
+		char buf[32];
+		struct tm tm;
+		ssize_t ret;
+
+		errno = EPERM;
+		if(asn_UT2time((UTCTime_t *)sptr, &tm, 1) == -1
+				&& errno != EPERM)
+			_ASN_ENCODE_FAILED;
+	
+		ret = snprintf(buf, sizeof(buf), "%02d%02d%02d%02d%02d%02dZ",
+				tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday,
+				tm.tm_hour, tm.tm_min, tm.tm_sec);
+		assert(ret > 0 && ret < (int)sizeof(buf));
+	
+		st.buf = (uint8_t *)buf;
+		st.size = ret;
+		sptr = &st;
+	}
+
+	return OCTET_STRING_encode_xer_ascii(td, sptr, ilevel, flags,
+		cb, app_key);
+}
+
 int
 UTCTime_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/UTCTime.h b/skeletons/UTCTime.h
index d00dafb..b026ded 100644
--- a/skeletons/UTCTime.h
+++ b/skeletons/UTCTime.h
@@ -12,8 +12,9 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_UTCTime;
 
-asn_constr_check_f UTCTime_constraint;
 asn_struct_print_f UTCTime_print;
+asn_constr_check_f UTCTime_constraint;
+xer_type_encoder_f UTCTime_encode_xer;
 
 /***********************
  * Some handy helpers. *
diff --git a/skeletons/UTF8String.c b/skeletons/UTF8String.c
index 40fef39..7220a67 100644
--- a/skeletons/UTF8String.c
+++ b/skeletons/UTF8String.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <UTF8String.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	UTF8String_print,
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,	/* Already in UTF-8 format */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_UTF8String_tags,
 	sizeof(asn1_DEF_UTF8String_tags)
diff --git a/skeletons/UTF8String.h b/skeletons/UTF8String.h
index f18bf70..543d319 100644
--- a/skeletons/UTF8String.h
+++ b/skeletons/UTF8String.h
@@ -12,8 +12,8 @@
 
 extern asn1_TYPE_descriptor_t asn1_DEF_UTF8String;
 
-asn_constr_check_f UTF8String_constraint;
 asn_struct_print_f UTF8String_print;
+asn_constr_check_f UTF8String_constraint;
 
 /* Returns length of UTF-8 string in characters or -1 if error. */
 ssize_t UTF8String_length(const UTF8String_t *st, const char *opt_type_name,
diff --git a/skeletons/UniversalString.c b/skeletons/UniversalString.c
index 1498896..d56cd92 100644
--- a/skeletons/UniversalString.c
+++ b/skeletons/UniversalString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <UniversalString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	UniversalString_print,      /* Convert into UTF8 and print */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	UniversalString_encode_xer,	/* Conver into UTF8 */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_UniversalString_tags,
 	sizeof(asn1_DEF_UniversalString_tags)
@@ -31,29 +34,25 @@
 };
 
 
-int
-UniversalString_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
-	asn_app_consume_bytes_f *cb, void *app_key) {
-	const UniversalString_t *st = (const UniversalString_t *)sptr;
-	uint32_t *wchar;
-	uint32_t *wend;
+static ssize_t
+UniversalString__dump(const UniversalString_t *st,
+		asn_app_consume_bytes_f *cb, void *app_key) {
 	char scratch[128];			/* Scratchpad buffer */
-	char *p;
+	char *p = scratch;
+	ssize_t wrote = 0;
+	uint8_t *ch;
+	uint8_t *end;
 
-	(void)td;	/* Unused argument */
-	(void)ilevel;	/* Unused argument */
-
-	if(!st || !st->buf) return cb("<absent>", 8, app_key);
-
-	wchar = (uint32_t *)st->buf;
-	wend = (uint32_t *)(st->buf + st->size);
-	for(p = scratch; wchar < wend; wchar++) {
-		uint32_t wc =    (((uint8_t *)wchar)[0] << 24)
-				| (((uint8_t *)wchar)[1] << 16)
-				| (((uint8_t *)wchar)[2] << 8)
-				|  ((uint8_t *)wchar)[3];	/* 4 bytes */
+	ch = st->buf;
+	end = (st->buf + st->size);
+	for(end -= 3; ch < end; ch += 4) {
+		uint32_t wc =     (ch[0] << 24)
+				| (ch[1] << 16)
+				| (ch[2] << 8)
+				|  ch[3];	/* 4 bytes */
 		if(sizeof(scratch) - (p - scratch) < 6) {
-			if(cb(scratch, p - scratch, app_key))
+			wrote += p - scratch;
+			if(cb(scratch, p - scratch, app_key) < 0)
 				return -1;
 			p = scratch;
 		}
@@ -87,5 +86,45 @@
 		}
 	}
 
-	return cb(scratch, p - scratch, app_key);
+	wrote += p - scratch;
+	if(cb(scratch, p - scratch, app_key) < 0)
+		return -1;
+
+	return wrote;
 }
+
+asn_enc_rval_t
+UniversalString_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	const UniversalString_t *st = (const UniversalString_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;
+	(void)flags;
+
+	if(!st || !st->buf)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = UniversalString__dump(st, cb, app_key);
+	if(er.encoded < 0) _ASN_ENCODE_FAILED;
+
+	return er;
+}
+
+int
+UniversalString_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+	asn_app_consume_bytes_f *cb, void *app_key) {
+	const UniversalString_t *st = (const UniversalString_t *)sptr;
+
+	(void)td;	/* Unused argument */
+	(void)ilevel;	/* Unused argument */
+
+	if(!st || !st->buf) return cb("<absent>", 8, app_key);
+
+	if(UniversalString__dump(st, cb, app_key) < 0)
+		return -1;
+
+	return 0;
+}
+
diff --git a/skeletons/UniversalString.h b/skeletons/UniversalString.h
index cafbc80..8887523 100644
--- a/skeletons/UniversalString.h
+++ b/skeletons/UniversalString.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #ifndef	_UniversalString_H_
@@ -13,5 +13,6 @@
 extern asn1_TYPE_descriptor_t asn1_DEF_UniversalString;
 
 asn_struct_print_f UniversalString_print;	/* Human-readable output */
+xer_type_encoder_f UniversalString_encode_xer;
 
 #endif	/* _UniversalString_H_ */
diff --git a/skeletons/VideotexString.c b/skeletons/VideotexString.c
index 6d2eaeb..f313ecb 100644
--- a/skeletons/VideotexString.c
+++ b/skeletons/VideotexString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <VideotexString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_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 */
-	OCTET_STRING_print,         /* non-ascii string */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer,    /* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_VideotexString_tags,
 	sizeof(asn1_DEF_VideotexString_tags)
diff --git a/skeletons/VisibleString.c b/skeletons/VisibleString.c
index 9ddb0f1..dbd0e92 100644
--- a/skeletons/VisibleString.c
+++ b/skeletons/VisibleString.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <VisibleString.h>
 
 /*
@@ -13,11 +14,13 @@
 };
 asn1_TYPE_descriptor_t asn1_DEF_VisibleString = {
 	"VisibleString",
+	OCTET_STRING_free,
+	OCTET_STRING_print_ascii,   /* ASCII subset */
 	VisibleString_constraint,
 	OCTET_STRING_decode_ber,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
-	OCTET_STRING_print_ascii,   /* ASCII subset */
-	OCTET_STRING_free,
+	0,				/* Not implemented yet */
+	OCTET_STRING_encode_xer_ascii,/* Implemented in terms of OCTET STRING */
 	0, /* Use generic outmost tag fetcher */
 	asn1_DEF_VisibleString_tags,
 	sizeof(asn1_DEF_VisibleString_tags)
diff --git a/skeletons/asn_SEQUENCE_OF.c b/skeletons/asn_SEQUENCE_OF.c
index 7cfd45f..b2d5f1f 100644
--- a/skeletons/asn_SEQUENCE_OF.c
+++ b/skeletons/asn_SEQUENCE_OF.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * 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>
 
diff --git a/skeletons/asn_SET_OF.c b/skeletons/asn_SET_OF.c
index c6afc30..7aeafdd 100644
--- a/skeletons/asn_SET_OF.c
+++ b/skeletons/asn_SET_OF.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * 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_internal.h b/skeletons/asn_internal.h
new file mode 100644
index 0000000..6a44cab
--- /dev/null
+++ b/skeletons/asn_internal.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Declarations internally useful for the ASN.1 support code.
+ */
+#ifndef	_ASN_INTERNAL_H_
+#define	_ASN_INTERNAL_H_
+
+#define	ASN1C_ENVIRONMENT_VERSION	96	/* Compile-time version */
+int get_asn1c_environment_version(void);	/* Run-time version */
+
+#include <asn_types.h>
+#include <constr_TYPE.h>
+
+#define	CALLOC(nmemb, size)	calloc(nmemb, size)
+#define	MALLOC(size)		malloc(size)
+#define	REALLOC(oldptr, size)	realloc(oldptr, size)
+#define	FREEMEM(ptr)		free(ptr)
+
+/*
+ * A macro for debugging the ASN.1 internals.
+ * You may enable or override it.
+ */
+#ifndef	ASN_DEBUG	/* If debugging code is not defined elsewhere... */
+#if	EMIT_ASN_DEBUG == 1	/* And it was asked to emit this code... */
+#ifdef	__GNUC__
+#define	ASN_DEBUG(fmt, args...)	do {		\
+		fprintf(stderr, fmt, ##args);	\
+		fprintf(stderr, "\n");		\
+	} while(0)
+#else	/* !__GNUC__ */
+extern void ASN_DEBUG_f(const char *fmt, ...);
+#define	ASN_DEBUG	ASN_DEBUG_f
+#endif	/* __GNUC__ */
+#else	/* EMIT_ASN_DEBUG != 1 */
+#ifdef	__GNUC__
+#define	ASN_DEBUG(fmt, args...)	((void)0)	/* Emit a no-op operator */
+#else	/* __GNUC__ */
+static void ASN_DEBUG(const char *fmt, ...) { (void)fmt; };
+#endif	/* __GNUC__ */
+#endif	/* EMIT_ASN_DEBUG */
+#endif	/* ASN_DEBUG */
+
+/*
+ * Invoke the application-supplied callback and fail, if something is wrong.
+ */
+#define	__ASN_E_cbc(buf, size)	(cb((buf), (size), app_key) == -1)
+#define	_ASN_E_CALLBACK(foo)	do {					\
+		if(foo)	_ASN_ENCODE_FAILED;				\
+	} while(0)
+#define	_ASN_CALLBACK(buf, size)					\
+	_ASN_E_CALLBACK(__ASN_E_cbc(buf, size))
+#define	_ASN_CALLBACK2(buf1, size1, buf2, size2)			\
+	_ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2))
+#define	_ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3)		\
+	_ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1)			\
+		|| __ASN_E_cbc(buf2, size2)				\
+		|| __ASN_E_cbc(buf3, size3))
+
+#define	_i_ASN_TEXT_INDENT(nl, level) do {				\
+		int __level = (level);					\
+		int __nl = ((nl) != 0);					\
+		int __i;						\
+		if(__nl) _ASN_CALLBACK("\n", 1);			\
+		for(__i = 0; __i < __level; __i++)			\
+			_ASN_CALLBACK("    ", 4);			\
+		er.encoded += __nl + 4 * __level;			\
+} while(0)
+
+#endif	/* _ASN_INTERNAL_H_ */
diff --git a/skeletons/asn_types.h b/skeletons/asn_types.h
index a5620b5..80ab061 100644
--- a/skeletons/asn_types.h
+++ b/skeletons/asn_types.h
@@ -43,11 +43,6 @@
 #define	offsetof(s, m)	((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0))
 #endif	/* offsetof */
 
-#define	CALLOC(nmemb, size)	calloc(nmemb, size)
-#define	MALLOC(size)		malloc(size)
-#define	REALLOC(oldptr, size)	realloc(oldptr, size)
-#define	FREEMEM(ptr)		free(ptr)
-
 #ifndef	MIN		/* Suitable for comparing primitive types (integers) */
 #if defined(__GNUC__)
 #define	MIN(a,b)	({ __typeof a _a = a; __typeof b _b = b;	\
@@ -58,31 +53,6 @@
 #endif	/* MIN */
 
 /*
- * A macro for debugging the ASN.1 internals.
- * You may enable or override it.
- */
-#ifndef	ASN_DEBUG	/* If debugging code is not defined elsewhere... */
-#if	EMIT_ASN_DEBUG == 1	/* And it was asked to emit this code... */
-#ifdef	__GNUC__
-#define	ASN_DEBUG(fmt, args...)	do {		\
-		fprintf(stderr, fmt, ##args);	\
-		fprintf(stderr, "\n");		\
-	} while(0)
-#else	/* !__GNUC__ */
-extern void ASN_DEBUG_f(const char *fmt, ...);
-#define	ASN_DEBUG	ASN_DEBUG_f
-#endif	/* __GNUC__ */
-#else	/* EMIT_ASN_DEBUG != 1 */
-#ifdef	__GNUC__
-#define	ASN_DEBUG(fmt, args...)	((void)0)	/* Emit a no-op operator */
-#else	/* __GNUC__ */
-static void ASN_DEBUG(const char *fmt, ...) { (void)fmt; };
-#endif	/* __GNUC__ */
-#endif	/* EMIT_ASN_DEBUG */
-#endif	/* ASN_DEBUG */
-
-
-/*
  * Generic type of an application-defined callback to return various
  * types of data to the application.
  * EXPECTED RETURN VALUES:
diff --git a/skeletons/ber_decoder.c b/skeletons/ber_decoder.c
index 24a47ac..cd40728 100644
--- a/skeletons/ber_decoder.c
+++ b/skeletons/ber_decoder.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_TYPE.h>
 #include <assert.h>
 
diff --git a/skeletons/ber_tlv_length.c b/skeletons/ber_tlv_length.c
index 508bc39..7daaaef 100644
--- a/skeletons/ber_tlv_length.c
+++ b/skeletons/ber_tlv_length.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_TYPE.h>
 #include <ber_tlv_length.h>
 #include <ber_tlv_tag.h>
diff --git a/skeletons/ber_tlv_tag.c b/skeletons/ber_tlv_tag.c
index c0a0d6a..d66b788 100644
--- a/skeletons/ber_tlv_tag.c
+++ b/skeletons/ber_tlv_tag.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_TYPE.h>
 #include <ber_tlv_tag.h>
 #include <errno.h>
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
index b7d38fb..ac2bbd6 100644
--- a/skeletons/constr_CHOICE.c
+++ b/skeletons/constr_CHOICE.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_CHOICE.h>
 #include <assert.h>
 
@@ -348,14 +349,14 @@
 	RETURN(RC_OK);
 }
 
-der_enc_rval_t
+asn_enc_rval_t
 CHOICE_encode_der(asn1_TYPE_descriptor_t *td,
 		void *struct_ptr,
 		int tag_mode, ber_tlv_tag_t tag,
 		asn_app_consume_bytes_f *cb, void *app_key) {
 	asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
 	asn1_TYPE_member_t *elm;	/* CHOICE element */
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	void *memb_ptr;
 	size_t computed_size = 0;
 	int present;
@@ -536,6 +537,57 @@
 	}
 }
 
+asn_enc_rval_t
+CHOICE_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn1_CHOICE_specifics_t *specs=(asn1_CHOICE_specifics_t *)td->specifics;
+	asn_enc_rval_t er;
+	int present;
+
+	if(!sptr)
+		_ASN_ENCODE_FAILED;
+
+	/*
+	 * Figure out which CHOICE element is encoded.
+	 */
+	present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
+
+	if(present <= 0 || present > td->elements_count) {
+		_ASN_ENCODE_FAILED;
+	}  else {
+		asn_enc_rval_t tmper;
+		asn1_TYPE_member_t *elm = &td->elements[present-1];
+		void *memb_ptr;
+		const char *mname = elm->name;
+		unsigned int mlen = strlen(mname);
+
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
+			if(!memb_ptr) _ASN_ENCODE_FAILED;
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+		}
+
+		er.encoded = 0;
+
+                if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel);
+		_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
+
+		tmper = elm->type->xer_encoder(elm->type, memb_ptr,
+				ilevel + 1, flags, cb, app_key);
+		if(tmper.encoded == -1) return tmper;
+
+		_ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
+
+		er.encoded += 5 + (2 * mlen) + tmper.encoded;
+	}
+
+	if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel - 1);
+
+	return er;
+}
+
 int
 CHOICE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
@@ -550,7 +602,7 @@
 	present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
 
 	/*
-	 * Free that element.
+	 * Print that element.
 	 */
 	if(present > 0 && present <= td->elements_count) {
 		asn1_TYPE_member_t *elm = &td->elements[present-1];
diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
index 327bae2..35b9511 100644
--- a/skeletons/constr_CHOICE.h
+++ b/skeletons/constr_CHOICE.h
@@ -31,11 +31,12 @@
 /*
  * A set specialized functions dealing with the CHOICE type.
  */
+asn_struct_free_f CHOICE_free;
+asn_struct_print_f CHOICE_print;
 asn_constr_check_f CHOICE_constraint;
 ber_type_decoder_f CHOICE_decode_ber;
 der_type_encoder_f CHOICE_encode_der;
+xer_type_encoder_f CHOICE_encode_xer;
 asn_outmost_tag_f CHOICE_outmost_tag;
-asn_struct_print_f CHOICE_print;
-asn_struct_free_f CHOICE_free;
 
 #endif	/* _CONSTR_CHOICE_H_ */
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 36412a6..9057ac0 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_SEQUENCE.h>
 #include <assert.h>
 
@@ -490,12 +491,12 @@
 /*
  * The DER encoder of the SEQUENCE type.
  */
-der_enc_rval_t
+asn_enc_rval_t
 SEQUENCE_encode_der(asn1_TYPE_descriptor_t *td,
 	void *ptr, int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	size_t computed_size = 0;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	ssize_t ret;
 	int edx;
 
@@ -544,7 +545,7 @@
 	 */
 	for(edx = 0; edx < td->elements_count; edx++) {
 		asn1_TYPE_member_t *elm = &td->elements[edx];
-		der_enc_rval_t tmperval;
+		asn_enc_rval_t tmperval;
 		void *memb_ptr;
 
 		if(elm->flags & ATF_POINTER) {
@@ -575,6 +576,50 @@
 	return erval;
 }
 
+asn_enc_rval_t
+SEQUENCE_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er;
+	int xcan = (flags & XER_F_CANONICAL);
+	int edx;
+
+	if(!sptr)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_enc_rval_t tmper;
+		asn1_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;
+		const char *mname = elm->name;
+		unsigned int mlen = strlen(mname);
+
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
+			if(!memb_ptr) continue;	/* OPTIONAL element? */
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+		}
+
+		if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel);
+		_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
+
+		/* Print the member itself */
+		tmper = elm->type->xer_encoder(elm->type, memb_ptr,
+			ilevel + 1, flags, cb, app_key);
+		if(tmper.encoded == -1) return tmper;
+
+		_ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
+		er.encoded += 5 + (2 * mlen) + tmper.encoded;
+	}
+
+	if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
+
+	return er;
+}
+
 int
 SEQUENCE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h
index 1e282c2..156db8c 100644
--- a/skeletons/constr_SEQUENCE.h
+++ b/skeletons/constr_SEQUENCE.h
@@ -31,10 +31,11 @@
 /*
  * A set specialized functions dealing with the SEQUENCE type.
  */
+asn_struct_free_f SEQUENCE_free;
+asn_struct_print_f SEQUENCE_print;
 asn_constr_check_f SEQUENCE_constraint;
 ber_type_decoder_f SEQUENCE_decode_ber;
 der_type_encoder_f SEQUENCE_encode_der;
-asn_struct_print_f SEQUENCE_print;
-asn_struct_free_f SEQUENCE_free;
+xer_type_encoder_f SEQUENCE_encode_xer;
 
 #endif	/* _CONSTR_SEQUENCE_H_ */
diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c
index 0a58f09..7330f65 100644
--- a/skeletons/constr_SEQUENCE_OF.c
+++ b/skeletons/constr_SEQUENCE_OF.c
@@ -2,13 +2,14 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_SEQUENCE_OF.h>
 #include <asn_SEQUENCE_OF.h>
 
 /*
  * The DER encoder of the SEQUENCE OF type.
  */
-der_enc_rval_t
+asn_enc_rval_t
 SEQUENCE_OF_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
@@ -16,7 +17,7 @@
 	A_SEQUENCE_OF(void) *list;
 	size_t computed_size = 0;
 	ssize_t encoding_size = 0;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	int edx;
 
 	ASN_DEBUG("Estimating size of SEQUENCE OF %s", td->name);
@@ -82,3 +83,50 @@
 	return erval;
 }
 
+asn_enc_rval_t
+SEQUENCE_OF_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er;
+        asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)td->specifics;
+	asn1_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);
+	unsigned int mlen = mname ? strlen(mname) : 0;
+	int xcan = (flags & XER_F_CANONICAL);
+	int i;
+
+	if(!sptr) _ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	(void *)list = sptr;
+	for(i = 0; i < list->count; i++) {
+		asn_enc_rval_t tmper;
+
+		void *memb_ptr = list->array[i];
+		if(!memb_ptr) continue;
+
+		if(mname) {
+			if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel);
+			_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
+		}
+
+		tmper = element->type->xer_encoder(element->type, memb_ptr,
+				ilevel + 1, flags, cb, app_key);
+		if(tmper.encoded == -1) return tmper;
+
+		if(mname) {
+			_ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
+			er.encoded += 5;
+		}
+
+		er.encoded += (2 * mlen) + tmper.encoded;
+	}
+
+	if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
+
+	return er;
+}
+
diff --git a/skeletons/constr_SEQUENCE_OF.h b/skeletons/constr_SEQUENCE_OF.h
index d2560c6..ee11750 100644
--- a/skeletons/constr_SEQUENCE_OF.h
+++ b/skeletons/constr_SEQUENCE_OF.h
@@ -12,10 +12,11 @@
  * A set specialized functions dealing with the SEQUENCE OF type.
  * Implemented using SET OF.
  */
+#define	SEQUENCE_OF_free	SET_OF_free
+#define	SEQUENCE_OF_print	SET_OF_print
 #define	SEQUENCE_OF_constraint	SET_OF_constraint
 #define	SEQUENCE_OF_decode_ber	SET_OF_decode_ber
 der_type_encoder_f SEQUENCE_OF_encode_der;
-#define	SEQUENCE_OF_print	SET_OF_print
-#define	SEQUENCE_OF_free	SET_OF_free
+xer_type_encoder_f SEQUENCE_OF_encode_xer;
 
 #endif	/* _CONSTR_SET_OF_H_ */
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index 7a31334..4c0c3b7 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_SET.h>
 #include <assert.h>	/* for assert() */
 
@@ -430,13 +431,13 @@
 /*
  * The DER encoder of the SET type.
  */
-der_enc_rval_t
+asn_enc_rval_t
 SET_encode_der(asn1_TYPE_descriptor_t *td,
 	void *ptr, int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
 	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
 	size_t computed_size = 0;
-	der_enc_rval_t my_erval;
+	asn_enc_rval_t my_erval;
 	int t2m_build_own = (specs->tag2el_count != td->elements_count);
 	asn1_TYPE_tag2member_t *t2m;
 	int t2m_count;
@@ -469,7 +470,7 @@
 	 */
 	for(edx = 0; edx < td->elements_count; edx++) {
 		asn1_TYPE_member_t *elm = &td->elements[edx];
-		der_enc_rval_t erval;
+		asn_enc_rval_t erval;
 		void *memb_ptr;
 
 		/*
@@ -545,7 +546,7 @@
 	 */
 	for(edx = 0; edx < td->elements_count; edx++) {
 		asn1_TYPE_member_t *elm;
-		der_enc_rval_t erval;
+		asn_enc_rval_t erval;
 		void *memb_ptr;
 
 		/* Encode according to the tag order */
@@ -577,6 +578,52 @@
 	return my_erval;
 }
 
+asn_enc_rval_t
+SET_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er;
+	int xcan = (flags & XER_F_CANONICAL);
+	int edx;
+
+	if(!sptr)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_enc_rval_t tmper;
+		asn1_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;
+		const char *mname = elm->name;
+		unsigned int mlen = strlen(elm->name);
+
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
+			if(!memb_ptr) continue;	/* OPTIONAL element? */
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+		}
+
+		if(!xcan)
+			_i_ASN_TEXT_INDENT(1, ilevel);
+		_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
+
+		/* Print the member itself */
+		tmper = elm->type->xer_encoder(elm->type, memb_ptr,
+				ilevel + 1, flags, cb, app_key);
+		if(tmper.encoded == -1) return tmper;
+
+		_ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
+
+		er.encoded += 5 + (2 * mlen) + tmper.encoded;
+	}
+
+	if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
+
+	return er;
+}
+
 int
 SET_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h
index eab2c30..eaf7df0 100644
--- a/skeletons/constr_SET.h
+++ b/skeletons/constr_SET.h
@@ -32,11 +32,12 @@
 /*
  * A set specialized functions dealing with the SET type.
  */
+asn_struct_free_f SET_free;
+asn_struct_print_f SET_print;
 asn_constr_check_f SET_constraint;
 ber_type_decoder_f SET_decode_ber;
 der_type_encoder_f SET_encode_der;
-asn_struct_print_f SET_print;
-asn_struct_free_f SET_free;
+xer_type_encoder_f SET_encode_xer;
 
 /***********************
  * Some handy helpers. *
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index d8dadf5..0a8ee28 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_SET_OF.h>
 #include <asn_SET_OF.h>
 
@@ -304,7 +305,7 @@
 /*
  * The DER encoder of the SET OF type.
  */
-der_enc_rval_t
+asn_enc_rval_t
 SET_OF_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
@@ -316,7 +317,7 @@
 	ssize_t encoding_size = 0;
 	struct _el_buffer *encoded_els;
 	size_t max_encoded_len = 1;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	int ret;
 	int edx;
 
@@ -444,6 +445,53 @@
 	return erval;
 }
 
+asn_enc_rval_t
+SET_OF_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
+	int ilevel, enum xer_encoder_flags_e flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er;
+	asn1_SET_OF_specifics_t *specs=(asn1_SET_OF_specifics_t *)td->specifics;
+	asn1_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);
+	size_t mlen = mname ? strlen(mname) : 0;
+	int xcan = (flags & XER_F_CANONICAL);
+	int i;
+
+	if(!sptr) _ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	(void *)list = sptr;
+	for(i = 0; i < list->count; i++) {
+		asn_enc_rval_t tmper;
+
+		void *memb_ptr = list->array[i];
+		if(!memb_ptr) continue;
+
+		if(mname) {
+			if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel);
+			_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
+		}
+
+		tmper = element->type->xer_encoder(element->type, memb_ptr,
+				ilevel + 1, flags, cb, app_key);
+		if(tmper.encoded == -1) return tmper;
+
+		if(mname) {
+			_ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
+			er.encoded += 5;
+		}
+
+		er.encoded += (2 * mlen) + tmper.encoded;
+	}
+
+	if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
+
+	return er;
+}
+
 int
 SET_OF_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h
index 0dd6040..1a1384d 100644
--- a/skeletons/constr_SET_OF.h
+++ b/skeletons/constr_SET_OF.h
@@ -13,15 +13,19 @@
 	 */
 	int struct_size;	/* Size of the target structure. */
 	int ctx_offset;		/* Offset of the ber_dec_ctx_t member */
+
+	/* XER-specific stuff */
+	int as_XMLValueList;	/* The member type must be encoded like this */
 } asn1_SET_OF_specifics_t;
 
 /*
  * A set specialized functions dealing with the SET OF type.
  */
+asn_struct_free_f SET_OF_free;
+asn_struct_print_f SET_OF_print;
 asn_constr_check_f SET_OF_constraint;
 ber_type_decoder_f SET_OF_decode_ber;
 der_type_encoder_f SET_OF_encode_der;
-asn_struct_print_f SET_OF_print;
-asn_struct_free_f SET_OF_free;
+xer_type_encoder_f SET_OF_encode_xer;
 
 #endif	/* _CONSTR_SET_OF_H_ */
diff --git a/skeletons/constr_TYPE.c b/skeletons/constr_TYPE.c
index 68cc50f..5085e4a 100644
--- a/skeletons/constr_TYPE.c
+++ b/skeletons/constr_TYPE.c
@@ -2,9 +2,15 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_TYPE.h>
 #include <errno.h>
 
+/*
+ * Version of the ASN.1 infrastructure shipped with compiler.
+ */
+int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; }
+
 static asn_app_consume_bytes_f _print2fp;
 
 /*
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index 15a6726..28e8e2c 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -2,19 +2,53 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
-#ifndef	_CONSTR_TYPE_H_
-#define	_CONSTR_TYPE_H_
+/*
+ * This file contains the declaration structure called "ASN.1 Type Definition",
+ * which holds all information necessary for encoding and decoding routines.
+ * 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
 
 #include <asn_types.h>		/* System-dependent types */
+
+struct asn1_TYPE_descriptor_s;	/* Forward declaration */
+struct asn1_TYPE_member_s;	/* Forward declaration */
+
+/*
+ * 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 asn1_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_tlv_length.h>
 #include <ber_tlv_tag.h>
 #include <ber_decoder.h>
 #include <der_encoder.h>
+#include <xer_encoder.h>
 #include <constraints.h>
 
-struct asn1_TYPE_descriptor_s;	/* Forward declaration */
-struct asn1_TYPE_member_s;	/* Forward declaration */
-
 /*
  * Free the structure according to its specification.
  * If (free_contents_only) is set, the wrapper structure itself (struct_ptr)
@@ -58,11 +92,13 @@
 	 * Generalized functions for dealing with the specific type.
 	 * May be directly invoked by applications.
 	 */
+	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 */
 	der_type_encoder_f *der_encoder;	/* Canonical DER encoder */
-	asn_struct_print_f *print_struct;	/* Human readable output */
-	asn_struct_free_f  *free_struct;	/* Free the structure */
+	int (*xer_decoder);/* PLACEHOLDER */ /* Free-form XER decoder */
+	xer_type_encoder_f *xer_encoder;	/* [Canonical] XER encoder */
 
 	/*
 	 * Functions used internally. Should not be used by applications.
@@ -129,6 +165,7 @@
  * RETURN VALUES:
  * 	 0: The structure is printed.
  * 	-1: Problem dumping the structure.
+ * (See also xer_fprint() in xer_encoder.h)
  */
 int asn_fprint(FILE *stream,		/* Destination stream descriptor */
 	asn1_TYPE_descriptor_t *td,	/* ASN.1 type descriptor */
diff --git a/skeletons/constraints.c b/skeletons/constraints.c
index 862d8f1..d95e3cb 100644
--- a/skeletons/constraints.c
+++ b/skeletons/constraints.c
@@ -1,3 +1,4 @@
+#include <asn_internal.h>
 #include <constraints.h>
 #include <constr_TYPE.h>
 
diff --git a/skeletons/der_encoder.c b/skeletons/der_encoder.c
index be71492..4f1936f 100644
--- a/skeletons/der_encoder.c
+++ b/skeletons/der_encoder.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
+#include <asn_internal.h>
 #include <constr_TYPE.h>
 #include <assert.h>
 #include <errno.h>
@@ -12,7 +13,7 @@
 /*
  * The DER encoder of any type.
  */
-der_enc_rval_t
+asn_enc_rval_t
 der_encode(asn1_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
 	asn_app_consume_bytes_f *consume_bytes, void *app_key) {
 
diff --git a/skeletons/der_encoder.h b/skeletons/der_encoder.h
index 052d9f4..fe64bcc 100644
--- a/skeletons/der_encoder.h
+++ b/skeletons/der_encoder.h
@@ -10,32 +10,9 @@
 struct asn1_TYPE_descriptor_s;	/* Forward declaration */
 
 /*
- * Type of the return value of the der_encode function.
- */
-typedef struct der_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 asn1_TYPE_descriptor_s *failed_type;
-
-	/* Pointer to the structure of that type */
-	void *structure_ptr;
-} der_enc_rval_t;
-
-
-/*
  * The DER encoder of any type. May be invoked by the application.
  */
-der_enc_rval_t der_encode(struct asn1_TYPE_descriptor_s *type_descriptor,
+asn_enc_rval_t der_encode(struct asn1_TYPE_descriptor_s *type_descriptor,
 		void *struct_ptr,	/* Structure to be encoded */
 		asn_app_consume_bytes_f *consume_bytes_cb,
 		void *app_key		/* Arbitrary callback argument */
@@ -44,7 +21,7 @@
 /*
  * Type of the generic DER encoder.
  */
-typedef der_enc_rval_t (der_type_encoder_f)(
+typedef asn_enc_rval_t (der_type_encoder_f)(
 		struct asn1_TYPE_descriptor_s *type_descriptor,
 		void *struct_ptr,	/* Structure to be encoded */
 		int tag_mode,		/* {-1,0,1}: IMPLICIT, no, EXPLICIT */
diff --git a/skeletons/file-dependencies b/skeletons/file-dependencies
index 2fdb581..25d10a0 100644
--- a/skeletons/file-dependencies
+++ b/skeletons/file-dependencies
@@ -44,6 +44,7 @@
 
 COMMON-FILES:	# This is a special section
 asn_types.h
+asn_internal.h
 OCTET_STRING.h OCTET_STRING.c	# This one is used too widely
 ber_decoder.h ber_decoder.c
 ber_tlv_length.h ber_tlv_length.c
@@ -51,3 +52,4 @@
 constr_TYPE.h constr_TYPE.c
 constraints.h constraints.c
 der_encoder.h der_encoder.c
+xer_encoder.h xer_encoder.c
diff --git a/skeletons/tests/check-GeneralizedTime.c b/skeletons/tests/check-GeneralizedTime.c
index 59474e4..40008f0 100644
--- a/skeletons/tests/check-GeneralizedTime.c
+++ b/skeletons/tests/check-GeneralizedTime.c
@@ -97,9 +97,9 @@
  * Dummy function.
  */
 
-der_enc_rval_t
+asn_enc_rval_t
 OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 
 	(void)td;
 	(void)ptr;
@@ -110,3 +110,17 @@
 
 	return erval;
 }
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer_ascii(asn1_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;
+	(void)ptr;
+	(void)ilevel;
+	(void)flags;
+	(void)cb;
+	(void)app_key;
+
+	return erval;
+}
diff --git a/skeletons/tests/check-UTCTime.c b/skeletons/tests/check-UTCTime.c
index 1bd49b3..b8ad57b 100644
--- a/skeletons/tests/check-UTCTime.c
+++ b/skeletons/tests/check-UTCTime.c
@@ -64,9 +64,9 @@
  * Dummy function.
  */
 
-der_enc_rval_t
+asn_enc_rval_t
 OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) {
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 
 	(void)td;
 	(void)ptr;
@@ -77,3 +77,17 @@
 
 	return erval;
 }
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer_ascii(asn1_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;
+	(void)ptr;
+	(void)ilevel;
+	(void)flags;
+	(void)cb;
+	(void)app_key;
+
+	return erval;
+}
diff --git a/skeletons/tests/check-length.c b/skeletons/tests/check-length.c
index 7746bcf..6176ddd 100644
--- a/skeletons/tests/check-length.c
+++ b/skeletons/tests/check-length.c
@@ -36,7 +36,7 @@
 check(int size) {
 	OCTET_STRING_t *os;
 	OCTET_STRING_t *nos = 0;
-	der_enc_rval_t erval;
+	asn_enc_rval_t erval;
 	ber_dec_rval_t rval;
 	int i;
 
diff --git a/skeletons/xer_encoder.c b/skeletons/xer_encoder.c
new file mode 100644
index 0000000..51f8d1d
--- /dev/null
+++ b/skeletons/xer_encoder.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <constr_TYPE.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+/*
+ * The XER encoder of any type. May be invoked by the application.
+ */
+asn_enc_rval_t
+xer_encode(asn1_TYPE_descriptor_t *td, void *sptr,
+	enum xer_encoder_flags_e xer_flags,
+		asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_enc_rval_t er, tmper;
+	const char *mname;
+	size_t mlen;
+	int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2;
+
+	if(!td || !sptr) {
+		er.encoded = -1;
+		er.failed_type = td;
+		er.structure_ptr = sptr;
+		return er;
+	}
+
+	mname = td->name;
+	mlen = strlen(mname);
+
+	_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
+
+	tmper = td->xer_encoder(td, sptr, 1, xer_flags, cb, app_key);
+	if(tmper.encoded == -1) return tmper;
+
+	_ASN_CALLBACK3("</", xcan, mname, mlen, ">\n",xcan);
+
+	er.encoded = 2 + (2 * xcan) + (2 * mlen) + tmper.encoded;
+
+	return er;
+}
+
+static int _print2fp(const void *buffer, size_t size, void *app_key);
+
+int
+xer_fprint(FILE *stream, asn1_TYPE_descriptor_t *td, void *sptr) {
+	asn_enc_rval_t er;
+
+	if(!stream) stream = stdout;
+	if(!td || !sptr)
+		return -1;
+
+	er = xer_encode(td, sptr, XER_F_BASIC, _print2fp, stream);
+	if(er.encoded == -1)
+		return -1;
+
+	return fflush(stream);
+}
+
+static int
+_print2fp(const void *buffer, size_t size, void *app_key) {
+	FILE *stream = (FILE *)app_key;
+
+	if(fwrite(buffer, 1, size, stream) != size)
+		return -1;
+
+	return 0;
+}
+
diff --git a/skeletons/xer_encoder.h b/skeletons/xer_encoder.h
new file mode 100644
index 0000000..43c192d
--- /dev/null
+++ b/skeletons/xer_encoder.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_XER_ENCODER_H_
+#define	_XER_ENCODER_H_
+
+#include <constr_TYPE.h>
+
+struct asn1_TYPE_descriptor_s;	/* Forward declaration */
+
+/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */
+enum xer_encoder_flags_e {
+	/* Mode of encoding */
+	XER_F_BASIC	= 0x01,	/* BASIC-XER (pretty-printing) */
+	XER_F_CANONICAL	= 0x02,	/* Canonical XER (strict rules, unreadable) */
+};
+
+/*
+ * The XER encoder of any type. May be invoked by the application.
+ */
+asn_enc_rval_t xer_encode(struct asn1_TYPE_descriptor_s *type_descriptor,
+		void *struct_ptr,	/* Structure to be encoded */
+		enum xer_encoder_flags_e xer_flags,
+		asn_app_consume_bytes_f *consume_bytes_cb,
+		void *app_key		/* Arbitrary callback argument */
+	);
+
+/*
+ * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC)
+ * output into the chosen file pointer.
+ * RETURN VALUES:
+ * 	 0: The structure is printed.
+ * 	-1: Problem printing the structure.
+ * WARNING: No sensible errno value is returned.
+ */
+int xer_fprint(FILE *stream, struct asn1_TYPE_descriptor_s *td, void *sptr);
+
+/*
+ * Type of the generic XER encoder.
+ */
+typedef asn_enc_rval_t (xer_type_encoder_f)(
+		struct asn1_TYPE_descriptor_s *type_descriptor,
+		void *struct_ptr,	/* Structure to be encoded */
+		int ilevel,		/* Level of indentation */
+		enum xer_encoder_flags_e xer_flags,
+		asn_app_consume_bytes_f *consume_bytes_cb,	/* Callback */
+		void *app_key		/* Arbitrary callback argument */
+	);
+
+#endif	/* _XER_ENCODER_H_ */