relaxed XER processing rules for whitespace


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@769 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index ad7321c..04e6560 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -133,16 +133,14 @@
 /*
  * Decode the chunk of XML text encoding INTEGER.
  */
-static ssize_t
-BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+static enum xer_pbd_rval
+BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	BOOLEAN_t *st = (BOOLEAN_t *)sptr;
-	char *p = (char *)chunk_buf;
+	const char *p = (const char *)chunk_buf;
 
 	(void)td;
 
-	if(chunk_size == 0) return -1;
-
-	if(p[0] == 0x3c /* '<' */) {
+	if(chunk_size && p[0] == 0x3c /* '<' */) {
 		switch(xer_check_tag(chunk_buf, chunk_size, "false")) {
 		case XCT_BOTH:
 			/* "<false/>" */
@@ -151,19 +149,20 @@
 		case XCT_UNKNOWN_BO:
 			if(xer_check_tag(chunk_buf, chunk_size, "true")
 					!= XCT_BOTH)
-				return -1;
+				return XPBD_BROKEN_ENCODING;
 			/* "<true/>" */
 			*st = 1;	/* Or 0xff as in DER?.. */
 			break;
 		default:
-			return -1;
+			return XPBD_BROKEN_ENCODING;
 		}
+		return XPBD_BODY_CONSUMED;
 	} else {
-		if(!xer_is_whitespace(chunk_buf, chunk_size))
-			return -1;
+		if(xer_is_whitespace(chunk_buf, chunk_size))
+			return XPBD_NOT_BODY_IGNORE;
+		else
+			return XPBD_BROKEN_ENCODING;
 	}
-
-	return chunk_size;
 }
 
 
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 246a02d..a20bee1 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -299,8 +299,8 @@
 /*
  * Decode the chunk of XML text encoding INTEGER.
  */
-static ssize_t
-INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+static enum xer_pbd_rval
+INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	INTEGER_t *st = (INTEGER_t *)sptr;
 	long sign = 1;
 	long value;
@@ -345,7 +345,7 @@
 
 			if(new_value / 10 != value)
 				/* Overflow */
-				return -1;
+				return XPBD_DECODER_LIMIT;
 
 			value = new_value + (lv - 0x30);
 			/* Check for two's complement overflow */
@@ -357,7 +357,7 @@
 					sign = 1;
 				} else {
 					/* Overflow */
-					return -1;
+					return XPBD_DECODER_LIMIT;
 				}
 			}
 		    }
@@ -377,20 +377,26 @@
 				}
 				ASN_DEBUG("Unknown identifier for INTEGER");
 			}
-			return -1;
+			return XPBD_BROKEN_ENCODING;
 		}
 		break;
 	}
 
-	if(state != ST_DIGITS)
-		return -1;	/* No digits */
+	if(state != ST_DIGITS) {
+		if(xer_is_whitespace(chunk_buf, chunk_size)) {
+			return XPBD_NOT_BODY_IGNORE;
+		} else {
+			ASN_DEBUG("No useful digits in output");
+			return XPBD_BROKEN_ENCODING;	/* No digits */
+		}
+	}
 
 	value *= sign;	/* Change sign, if needed */
 
 	if(asn_long2INTEGER(st, value))
-		return -1;
+		return XPBD_SYSTEM_FAILURE;
 
-	return lp - lstart;
+	return XPBD_BODY_CONSUMED;
 }
 
 asn_dec_rval_t
diff --git a/skeletons/NULL.c b/skeletons/NULL.c
index 6a813fc..d5d98d9 100644
--- a/skeletons/NULL.c
+++ b/skeletons/NULL.c
@@ -67,13 +67,15 @@
 }
 
 
-static ssize_t
-NULL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+static enum xer_pbd_rval
+NULL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	(void)td;
 	(void)sptr;
+
 	if(xer_is_whitespace(chunk_buf, chunk_size))
-		return chunk_size;
-	return -1;
+		return XPBD_BODY_CONSUMED;
+	else
+		return XPBD_BROKEN_ENCODING;
 }
 
 asn_dec_rval_t
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index 4128e76..eeb9e5f 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -263,8 +263,8 @@
 	return wrote_len;
 }
 
-static ssize_t
-OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+static enum xer_pbd_rval
+OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
 	char *endptr;
 	long s_arcs[10];
@@ -275,27 +275,31 @@
 	(void)td;
 
 	arcs_count = OBJECT_IDENTIFIER_parse_arcs(
-		(const char *)chunk_buf, chunk_size, arcs, 10, &endptr);
-	if(arcs_count <= 0)
-		return -1;	/* Expecting more than zero arcs */
-	if(arcs_count > 10) {
+		(const char *)chunk_buf, chunk_size, arcs,
+			sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
+	if(arcs_count <= 0) {
+		/* Expecting more than zero arcs */
+		return XPBD_BROKEN_ENCODING;
+	}
+
+	if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
 		arcs = (long *)MALLOC(arcs_count * sizeof(long));
-		if(!arcs) return -1;
+		if(!arcs) return XPBD_SYSTEM_FAILURE;
 		ret = OBJECT_IDENTIFIER_parse_arcs(
 			(const char *)chunk_buf, chunk_size,
 			arcs, arcs_count, &endptr);
 		if(ret != arcs_count)
-			return -1;	/* assert?.. */
+			return XPBD_SYSTEM_FAILURE;	/* assert?.. */
 	}
 
 	/*
 	 * Convert arcs into BER representation.
 	 */
 	ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(*arcs), arcs_count);
-	if(ret) return -1;
+	if(ret) return XPBD_BROKEN_ENCODING;
 	if(arcs != s_arcs) FREEMEM(arcs);
 
-	return endptr - (char *)chunk_buf;
+	return XPBD_BODY_CONSUMED;
 }
 
 asn_dec_rval_t
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
index a020339..26df4bc 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -691,7 +691,7 @@
 };
 
 static int
-OS__check_escaped_control_char(void *buf, int size) {
+OS__check_escaped_control_char(const void *buf, int size) {
 	size_t i;
 	/*
 	 * Inefficient algorithm which translates the escape sequences
@@ -709,7 +709,7 @@
 }
 
 static int
-OCTET_STRING__handle_control_chars(void *struct_ptr, void *chunk_buf, size_t chunk_size) {
+OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {
 	/*
 	 * This might be one of the escape sequences
 	 * for control characters. Check it out.
@@ -778,11 +778,11 @@
 /*
  * Convert from hexadecimal format (cstring): "AB CD EF"
  */
-static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, void *chunk_buf, size_t chunk_size, int have_more) {
+static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
 	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
-	char *chunk_stop = (char *)chunk_buf;
-	char *p = chunk_stop;
-	char *pend = p + chunk_size;
+	const char *chunk_stop = (const char *)chunk_buf;
+	const char *p = chunk_stop;
+	const char *pend = p + chunk_size;
 	unsigned int clv = 0;
 	int half = 0;	/* Half bit */
 	uint8_t *buf;
@@ -800,7 +800,7 @@
 	 * than chunk_size, then it'll be equivalent to "ABC0".
 	 */
 	for(; p < pend; p++) {
-		int ch = *(unsigned char *)p;
+		int ch = *(const unsigned char *)p;
 		switch(ch) {
 		case 0x09: case 0x0a: case 0x0c: case 0x0d:
 		case 0x20:
@@ -849,16 +849,16 @@
 	assert(st->size <= _ns);
 	st->buf[st->size] = 0;		/* Courtesy termination */
 
-	return (chunk_stop - (char *)chunk_buf);	/* Converted size */
+	return (chunk_stop - (const char *)chunk_buf);	/* Converted size */
 }
 
 /*
  * Convert from binary format: "00101011101"
  */
-static ssize_t OCTET_STRING__convert_binary(void *sptr, void *chunk_buf, size_t chunk_size, int have_more) {
+static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
 	BIT_STRING_t *st = (BIT_STRING_t *)sptr;
-	char *p = (char *)chunk_buf;
-	char *pend = p + chunk_size;
+	const char *p = (const char *)chunk_buf;
+	const char *pend = p + chunk_size;
 	int bits_unused = st->bits_unused & 0x7;
 	uint8_t *buf;
 
@@ -880,7 +880,7 @@
 	 * Convert series of 0 and 1 into the octet string.
 	 */
 	for(; p < pend; p++) {
-		int ch = *(unsigned char *)p;
+		int ch = *(const unsigned char *)p;
 		switch(ch) {
 		case 0x09: case 0x0a: case 0x0c: case 0x0d:
 		case 0x20:
@@ -918,9 +918,9 @@
  * Something like strtod(), but with stricter rules.
  */
 static int
-OS__strtoent(int base, char *buf, char *end, int32_t *return_value) {
+OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {
 	int32_t val = 0;
-	char *p;
+	const char *p;
 
 	for(p = buf; p < end; p++) {
 		int ch = *p;
@@ -939,7 +939,7 @@
 			val = val * base + (ch - 0x61 + 10);
 			break;
 		case 0x3b:	/* ';' */
-			*return_value = val;
+			*ret_value = val;
 			return (p - buf) + 1;
 		default:
 			return -1;	/* Character set error */
@@ -953,10 +953,10 @@
 /*
  * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"
  */
-static ssize_t OCTET_STRING__convert_entrefs(void *sptr, void *chunk_buf, size_t chunk_size, int have_more) {
+static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
 	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
-	char *p = (char *)chunk_buf;
-	char *pend = p + chunk_size;
+	const char *p = (const char *)chunk_buf;
+	const char *pend = p + chunk_size;
 	uint8_t *buf;
 
 	/* Reallocate buffer */
@@ -970,7 +970,7 @@
 	 * Convert series of 0 and 1 into the octet string.
 	 */
 	for(; p < pend; p++) {
-		int ch = *(unsigned char *)p;
+		int ch = *(const unsigned char *)p;
 		int len;	/* Length of the rest of the chunk */
 
 		if(ch != 0x26 /* '&' */) {
@@ -981,11 +981,11 @@
 		/*
 		 * Process entity reference.
 		 */
-		len = chunk_size - (p - (char *)chunk_buf);
+		len = chunk_size - (p - (const char *)chunk_buf);
 		if(len == 1 /* "&" */) goto want_more;
 		if(p[1] == 0x23 /* '#' */) {
-			char *pval;	/* Pointer to start of digits */
-			int32_t val;	/* Entity reference value */
+			const char *pval;	/* Pointer to start of digits */
+			int32_t val;		/* Entity reference value */
 			int base;
 
 			if(len == 2 /* "&#" */) goto want_more;
@@ -1078,7 +1078,7 @@
 			*buf++ = ch;
 			continue;
 		}
-		chunk_size = (p - (char *)chunk_buf);
+		chunk_size = (p - (const char *)chunk_buf);
 		/* Processing stalled: need more data */
 		break;
 	}
@@ -1098,9 +1098,9 @@
 	asn_TYPE_descriptor_t *td, void **sptr,
 	const char *opt_mname, void *buf_ptr, size_t size,
 	int (*opt_unexpected_tag_decoder)
-		(void *struct_ptr, void *chunk_buf, size_t chunk_size),
+		(void *struct_ptr, const void *chunk_buf, size_t chunk_size),
 	ssize_t (*body_receiver)
-		(void *struct_ptr, void *chunk_buf, size_t chunk_size,
+		(void *struct_ptr, const void *chunk_buf, size_t chunk_size,
 			int have_more)
 ) {
 	OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index 717db89..4b73f4b 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -257,17 +257,17 @@
 /*
  * Decode the chunk of XML text encoding REAL.
  */
-static ssize_t
-REAL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+static enum xer_pbd_rval
+REAL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	REAL_t *st = (REAL_t *)sptr;
 	double value;
-	char *xerdata = (char *)chunk_buf;
+	const char *xerdata = (const char *)chunk_buf;
 	char *endptr = 0;
 	char *b;
 
 	(void)td;
 
-	if(!chunk_size) return -1;
+	if(!chunk_size) return XPBD_BROKEN_ENCODING;
 
 	/*
 	 * Decode an XMLSpecialRealValue: <MINUS-INFINITY>, etc.
@@ -292,33 +292,34 @@
 			case -1: dv = - INFINITY; break;
 			case 0: dv = NAN;	break;
 			case 1: dv = INFINITY;	break;
-			default: return -1;
+			default: return XPBD_SYSTEM_FAILURE;
 			}
 
-			if(asn_double2REAL(st, dv)) return -1;
+			if(asn_double2REAL(st, dv))
+				return XPBD_SYSTEM_FAILURE;
 
-			return chunk_size;
+			return XPBD_BODY_CONSUMED;
 		}
 		ASN_DEBUG("Unknown XMLSpecialRealValue");
-		return -1;
+		return XPBD_BROKEN_ENCODING;
 	}
 
 	/*
 	 * Copy chunk into the nul-terminated string, and run strtod.
 	 */
 	b = (char *)MALLOC(chunk_size + 1);
-	if(!b) return -1;
+	if(!b) return XPBD_SYSTEM_FAILURE;
 	memcpy(b, chunk_buf, chunk_size);
 	b[chunk_size] = 0;	/* nul-terminate */
 
 	value = strtod(b, &endptr);
 	free(b);
-	if(endptr == b) return -1;
+	if(endptr == b) return XPBD_BROKEN_ENCODING;
 
 	if(asn_double2REAL(st, value))
-		return -1;
+		return XPBD_SYSTEM_FAILURE;
 
-	return endptr - b;
+	return XPBD_BODY_CONSUMED;
 }
 
 asn_dec_rval_t
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index 70291e2..6a064d0 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -86,8 +86,8 @@
 	return (cb(" }", 2, app_key) < 0) ? -1 : 0;
 }
 
-static ssize_t
-RELATIVE_OID__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
+static enum xer_pbd_rval
+RELATIVE_OID__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr;
 	char *endptr;
 	long s_arcs[6];
@@ -99,27 +99,30 @@
 
 	arcs_count = OBJECT_IDENTIFIER_parse_arcs(
 		(const char *)chunk_buf, chunk_size,
-		arcs, 6, &endptr);
-	if(arcs_count < 0)
-		return -1;	/* Expecting at least zero arcs */
-	if(arcs_count > 6) {
+		arcs, sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
+	if(arcs_count < 0) {
+		/* Expecting at least zero arcs */
+		return XPBD_BROKEN_ENCODING;
+	}
+
+	if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
 		arcs = (long *)MALLOC(arcs_count * sizeof(long));
-		if(!arcs) return -1;
+		if(!arcs) return XPBD_SYSTEM_FAILURE;
 		ret = OBJECT_IDENTIFIER_parse_arcs(
 			(const char *)chunk_buf, chunk_size,
 			arcs, arcs_count, &endptr);
 		if(ret != arcs_count)
-			return -1;	/* assert?.. */
+			return XPBD_SYSTEM_FAILURE;	/* assert?.. */
 	}
 
 	/*
 	 * Convert arcs into BER representation.
 	 */
 	ret = RELATIVE_OID_set_arcs(st, arcs, sizeof(*arcs), arcs_count);
-	if(ret) return -1;
+	if(ret) return XPBD_BROKEN_ENCODING;
 	if(arcs != s_arcs) FREEMEM(arcs);
 
-	return endptr - (char *)chunk_buf;
+	return XPBD_BODY_CONSUMED;
 }
 
 asn_dec_rval_t
diff --git a/skeletons/asn_codecs_prim.c b/skeletons/asn_codecs_prim.c
index 42f5a40..a2aeeee 100644
--- a/skeletons/asn_codecs_prim.c
+++ b/skeletons/asn_codecs_prim.c
@@ -148,17 +148,16 @@
 struct xdp_arg_s {
 	asn_TYPE_descriptor_t *type_descriptor;
 	void *struct_key;
-	ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
-		void *struct_key, void *chunk_buf, size_t chunk_size);
+	xer_primitive_body_decoder_f *prim_body_decoder;
 	int decoded_something;
 	int want_more;
 };
 
 
-static ssize_t
-xer_decode__unexpected_tag(void *key, void *chunk_buf, size_t chunk_size) {
+static int
+xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
-	ssize_t decoded;
+	enum xer_pbd_rval bret;
 
 	if(arg->decoded_something) {
 		if(xer_is_whitespace(chunk_buf, chunk_size))
@@ -169,21 +168,28 @@
 		return -1;
 	}
 
-	decoded = arg->prim_body_decode(arg->type_descriptor,
+	bret = arg->prim_body_decoder(arg->type_descriptor,
 		arg->struct_key, chunk_buf, chunk_size);
-	if(decoded < 0) {
-		return -1;
-	} else {
+	switch(bret) {
+	case XPBD_SYSTEM_FAILURE:
+	case XPBD_DECODER_LIMIT:
+	case XPBD_BROKEN_ENCODING:
+		break;
+	case XPBD_BODY_CONSUMED:
 		/* Tag decoded successfully */
 		arg->decoded_something = 1;
+		/* Fall through */
+	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
 		return 0;
 	}
+
+	return -1;
 }
 
 static ssize_t
-xer_decode__body(void *key, void *chunk_buf, size_t chunk_size, int have_more) {
+xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
-	ssize_t decoded;
+	enum xer_pbd_rval bret;
 
 	if(arg->decoded_something) {
 		if(xer_is_whitespace(chunk_buf, chunk_size))
@@ -207,14 +213,22 @@
 		return -1;
 	}
 
-	decoded = arg->prim_body_decode(arg->type_descriptor,
+	bret = arg->prim_body_decoder(arg->type_descriptor,
 		arg->struct_key, chunk_buf, chunk_size);
-	if(decoded < 0) {
-		return -1;
-	} else {
+	switch(bret) {
+	case XPBD_SYSTEM_FAILURE:
+	case XPBD_DECODER_LIMIT:
+	case XPBD_BROKEN_ENCODING:
+		break;
+	case XPBD_BODY_CONSUMED:
+		/* Tag decoded successfully */
 		arg->decoded_something = 1;
-		return decoded;
+		/* Fall through */
+	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
+		return chunk_size;
 	}
+
+	return -1;
 }
 
 
@@ -225,8 +239,7 @@
 	size_t struct_size,
 	const char *opt_mname,
 	void *buf_ptr, size_t size,
-	ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
-		void *struct_key, void *chunk_buf, size_t chunk_size)
+	xer_primitive_body_decoder_f *prim_body_decoder
 ) {
 	const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
 	asn_struct_ctx_t s_ctx;
@@ -249,7 +262,7 @@
 	memset(&s_ctx, 0, sizeof(s_ctx));
 	s_arg.type_descriptor = td;
 	s_arg.struct_key = *sptr;
-	s_arg.prim_body_decode = prim_body_decode;
+	s_arg.prim_body_decoder = prim_body_decoder;
 	s_arg.decoded_something = 0;
 	s_arg.want_more = 0;
 
@@ -260,9 +273,16 @@
 	case RC_OK:
 		if(!s_arg.decoded_something) {
 			char ch;
-			/* Opportunity has come and gone. Where's the result? */
-			if(prim_body_decode(s_arg.type_descriptor,
-				s_arg.struct_key, &ch, 0) != 0) {
+			ASN_DEBUG("Primitive body is not recognized, "
+				"supplying empty one");
+			/*
+			 * Decoding opportunity has come and gone.
+			 * Where's the result?
+			 * Try to feed with empty body, see if it eats it.
+			 */
+			if(prim_body_decoder(s_arg.type_descriptor,
+				s_arg.struct_key, &ch, 0)
+					!= XPBD_BODY_CONSUMED) {
 				/*
 				 * This decoder does not like empty stuff.
 				 */
diff --git a/skeletons/asn_codecs_prim.h b/skeletons/asn_codecs_prim.h
index 7a6723d..ceadf51 100644
--- a/skeletons/asn_codecs_prim.h
+++ b/skeletons/asn_codecs_prim.h
@@ -17,6 +17,20 @@
 der_type_encoder_f der_encode_primitive;
 
 /*
+ * A callback specification for the xer_decode_primitive() function below.
+ */
+enum xer_pbd_rval {
+	XPBD_SYSTEM_FAILURE,	/* System failure (memory shortage, etc) */
+	XPBD_DECODER_LIMIT,	/* Hit some decoder limitation or deficiency */
+	XPBD_BROKEN_ENCODING,	/* Encoding of a primitive body is broken */
+	XPBD_NOT_BODY_IGNORE,	/* Not a body format, but safe to ignore */
+	XPBD_BODY_CONSUMED,	/* Body is recognized and consumed */
+};
+typedef enum xer_pbd_rval (xer_primitive_body_decoder_f)
+	(asn_TYPE_descriptor_t *td, void *struct_ptr,
+		const void *chunk_buf, size_t chunk_size);
+
+/*
  * Specific function to decode simple primitive types.
  * Also see xer_decode_general() in xer_decoder.h
  */
@@ -25,8 +39,7 @@
 	void **struct_ptr, size_t struct_size,
 	const char *opt_mname,
 	void *buf_ptr, size_t size,
-	ssize_t (*prim_body_decode)(asn_TYPE_descriptor_t *td,
-		void *struct_ptr, void *chunk_buf, size_t chunk_size)
-	);
+	xer_primitive_body_decoder_f *prim_body_decoder
+);
 
 #endif	/* ASN_CODECS_PRIM_H */
diff --git a/skeletons/xer_decoder.c b/skeletons/xer_decoder.c
index 07a1936..6456666 100644
--- a/skeletons/xer_decoder.c
+++ b/skeletons/xer_decoder.c
@@ -33,12 +33,12 @@
 struct xer__cb_arg {
 	pxml_chunk_type_e	chunk_type;
 	size_t			chunk_size;
-	void			*chunk_buf;
+	const void		*chunk_buf;
 	int callback_not_invoked;
 };
 
 static int
-xer__token_cb(pxml_chunk_type_e type, void *_chunk_data, size_t _chunk_size, void *key) {
+xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) {
 	struct xer__cb_arg *arg = (struct xer__cb_arg *)key;
 	arg->chunk_type = type;
 	arg->chunk_size = _chunk_size;
@@ -51,7 +51,7 @@
  * Fetch the next token from the XER/XML stream.
  */
 ssize_t
-xer_next_token(int *stateContext, void *buffer, size_t size, pxer_chunk_type_e *ch_type) {
+xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) {
 	struct xer__cb_arg arg;
 	int new_stateContext = *stateContext;
 	ssize_t ret;
@@ -151,7 +151,7 @@
 #undef	ADVANCE
 #define	ADVANCE(num_bytes)	do {				\
 		size_t num = (num_bytes);			\
-		buf_ptr = ((char *)buf_ptr) + num;		\
+		buf_ptr = ((const char *)buf_ptr) + num;	\
 		size -= num;					\
 		consumed_myself += num;				\
 	} while(0)
@@ -186,11 +186,11 @@
 	asn_struct_ctx_t *ctx,	/* Type decoder context */
 	void *struct_key,
 	const char *xml_tag,	/* Expected XML tag */
-	void *buf_ptr, size_t size,
+	const void *buf_ptr, size_t size,
 	int (*opt_unexpected_tag_decoder)
-		(void *struct_key, void *chunk_buf, size_t chunk_size),
+		(void *struct_key, const void *chunk_buf, size_t chunk_size),
 	ssize_t (*body_receiver)
-		(void *struct_key, void *chunk_buf, size_t chunk_size,
+		(void *struct_key, const void *chunk_buf, size_t chunk_size,
 			int have_more)
 	) {
 
@@ -301,9 +301,9 @@
 
 
 int
-xer_is_whitespace(void *chunk_buf, size_t chunk_size) {
-	char *p = (char *)chunk_buf;
-	char *pend = p + chunk_size;
+xer_is_whitespace(const void *chunk_buf, size_t chunk_size) {
+	const char *p = (const char *)chunk_buf;
+	const char *pend = p + chunk_size;
 
 	for(; p < pend; p++) {
 		switch(*p) {
diff --git a/skeletons/xer_decoder.h b/skeletons/xer_decoder.h
index fa8c3c6..4f6b537 100644
--- a/skeletons/xer_decoder.h
+++ b/skeletons/xer_decoder.h
@@ -43,11 +43,11 @@
 	asn_struct_ctx_t *ctx,	/* Type decoder context */
 	void *struct_key,	/* Treated as opaque pointer */
 	const char *xml_tag,	/* Expected XML tag name */
-	void *buf_ptr, size_t size,
+	const void *buf_ptr, size_t size,
 	int (*opt_unexpected_tag_decoder)
-		(void *struct_key, void *chunk_buf, size_t chunk_size),
+		(void *struct_key, const void *chunk_buf, size_t chunk_size),
 	ssize_t (*body_receiver)
-		(void *struct_key, void *chunk_buf, size_t chunk_size,
+		(void *struct_key, const void *chunk_buf, size_t chunk_size,
 			int have_more)
 	);
 
@@ -64,7 +64,7 @@
 	PXER_COMMENT,	/* A comment, may be part of */
   } pxer_chunk_type_e;
 ssize_t xer_next_token(int *stateContext,
-	void *buffer, size_t size, pxer_chunk_type_e *_ch_type);
+	const void *buffer, size_t size, pxer_chunk_type_e *_ch_type);
 
 /*
  * This function checks the buffer against the tag name is expected to occur.
@@ -88,7 +88,7 @@
  * 1:	Whitespace or empty string
  * 0:	Non-whitespace
  */
-int xer_is_whitespace(void *chunk_buf, size_t chunk_size);
+int xer_is_whitespace(const void *chunk_buf, size_t chunk_size);
 
 /*
  * Skip the series of anticipated extensions.
diff --git a/skeletons/xer_support.c b/skeletons/xer_support.c
index b2f542c..21c92b0 100644
--- a/skeletons/xer_support.c
+++ b/skeletons/xer_support.c
@@ -58,6 +58,7 @@
 #define	LANGLE	0x3c	/* '<' */
 #define	CEQUAL	0x3d	/* '=' */
 #define	RANGLE	0x3e	/* '>' */
+#define	CQUEST	0x3f	/* '?' */
 
 /* Invoke token callback */
 #define	TOKEN_CB_CALL(type, _ns, _current_too, _final) do {	\
@@ -88,14 +89,14 @@
 /*
  * Parser itself
  */
-ssize_t pxml_parse(int *stateContext, void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) {
+ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) {
 	pstate_e state = (pstate_e)*stateContext;
-	char *chunk_start = (char *)xmlbuf;
-	char *p = chunk_start;
-	char *end = p + size;
+	const char *chunk_start = (const char *)xmlbuf;
+	const char *p = chunk_start;
+	const char *end = p + size;
 
 	for(; p < end; p++) {
-	  int C = *(unsigned char *)p;
+	  int C = *(const unsigned char *)p;
 	  switch(state) {
 	  case ST_TEXT:
 		/*
@@ -229,6 +230,6 @@
 
 finish:
 	*stateContext = (int)state;
-	return chunk_start - (char *)xmlbuf;
+	return chunk_start - (const char *)xmlbuf;
 }
 
diff --git a/skeletons/xer_support.h b/skeletons/xer_support.h
index 2fa1ae9..e25678c 100644
--- a/skeletons/xer_support.h
+++ b/skeletons/xer_support.h
@@ -32,7 +32,7 @@
  * The chunk is NOT '\0'-terminated.
  */
 typedef int (pxml_callback_f)(pxml_chunk_type_e _type,
-	void *_chunk_data, size_t _chunk_size, void *_key);
+	const void *_chunk_data, size_t _chunk_size, void *_key);
 
 /*
  * Parse the given buffer as it were a chunk of XML data.
@@ -41,7 +41,7 @@
  * It will always be lesser than or equal to the specified _size.
  * The next invocation of this function must account the difference.
  */
-ssize_t pxml_parse(int *_stateContext, void *_buf, size_t _size,
+ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size,
 	pxml_callback_f *cb, void *_key);
 
 #endif	/* _XER_SUPPORT_H_ */