update to asn1c aper branch commit 6e00cbce7304a6972e82a12bb5fa82e41fa541be

which is closes to Lev Walkins master 62913d8b8e1eb96d74315ff748475ca818b69752
diff --git a/src/ANY.c b/src/ANY.c
index 0ad60d0..0fe63ae 100644
--- a/src/ANY.c
+++ b/src/ANY.c
@@ -21,7 +21,10 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_hex,
 	ANY_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	0, 0, 0, 0,
 	0,	/* No PER visible constraints */
@@ -87,6 +90,37 @@
 	return 0;
 }
 
+int
+ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr) {
+	uint8_t *buffer = NULL;
+	ssize_t erval;
+
+	if(!st || !td) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if(!sptr) {
+		if(st->buf) FREEMEM(st->buf);
+		st->size = 0;
+		return 0;
+	}
+
+	erval = aper_encode_to_new_buffer(td, td->per_constraints, sptr, (void**)&buffer);
+
+	if(erval == -1) {
+		if(buffer) FREEMEM(buffer);
+		return -1;
+	}
+	assert((size_t)erval > 0);
+
+	if(st->buf) FREEMEM(st->buf);
+	st->buf = buffer;
+	st->size = erval;
+
+	return 0;
+}
+
 ANY_t *
 ANY_new_fromType(asn_TYPE_descriptor_t *td, void *sptr) {
 	ANY_t tmp;
@@ -111,6 +145,30 @@
 	}
 }
 
+ANY_t *
+ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr) {
+	ANY_t tmp;
+	ANY_t *st;
+
+	if(!td || !sptr) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	if(ANY_fromType_aper(&tmp, td, sptr)) return 0;
+
+	st = (ANY_t *)CALLOC(1, sizeof(ANY_t));
+	if(st) {
+		*st = tmp;
+		return st;
+	} else {
+		FREEMEM(tmp.buf);
+		return 0;
+	}
+}
+
 int
 ANY_to_type(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) {
 	asn_dec_rval_t rval;
@@ -138,6 +196,33 @@
 	}
 }
 
+int
+ANY_to_type_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) {
+	asn_dec_rval_t rval;
+	void *newst = 0;
+
+	if(!st || !td || !struct_ptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if(st->buf == 0) {
+		/* Nothing to convert, make it empty. */
+		*struct_ptr = (void *)0;
+		return 0;
+	}
+
+	rval = aper_decode(0, td, (void **)&newst, st->buf, st->size, 0, 0);
+	if(rval.code == RC_OK) {
+		*struct_ptr = newst;
+		return 0;
+	} else {
+		/* Remove possibly partially decoded data. */
+		ASN_STRUCT_FREE(*td, newst);
+		return -1;
+	}
+}
+
 static int ANY__consume_bytes(const void *buffer, size_t size, void *key) {
 	struct _callback_arg *arg = (struct _callback_arg *)key;
 
diff --git a/src/BIT_STRING.c b/src/BIT_STRING.c
index 9b98271..ad2ca60 100644
--- a/src/BIT_STRING.c
+++ b/src/BIT_STRING.c
@@ -9,7 +9,7 @@
 /*
  * BIT STRING basic type description.
  */
-static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = {
+static const ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (3 << 2))
 };
 static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = {
@@ -29,6 +29,8 @@
 	BIT_STRING_encode_xer,
 	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
 	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
+	OCTET_STRING_decode_aper,	/* Aligned PER decoder */
+	OCTET_STRING_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_BIT_STRING_tags,
 	sizeof(asn_DEF_BIT_STRING_tags)
@@ -140,7 +142,7 @@
 int
 BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
-	static const char *h2c = "0123456789ABCDEF";
+	const char * const h2c = "0123456789ABCDEF";
 	char scratch[64];
 	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
 	uint8_t *buf;
diff --git a/src/BMPString.c b/src/BMPString.c
index 072bd07..94471f6 100644
--- a/src/BMPString.c
+++ b/src/BMPString.c
@@ -9,7 +9,7 @@
 /*
  * BMPString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_BMPString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_BMPString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (30 << 2)),	/* [UNIVERSAL 30] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -35,6 +35,8 @@
 	BMPString_encode_xer,		/* Convert to UTF-8 */
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,	/* Aligned PER decoder */
+	OCTET_STRING_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_BMPString_tags,
 	sizeof(asn_DEF_BMPString_tags)
@@ -143,7 +145,7 @@
 				return rc;
 			} else {
 				dstwc[wcs_len] = 0;	/* nul-terminate */
-				wcs = (uint32_t *)dstwc;
+				wcs = (uint32_t *)(void *)dstwc; /* Alignment OK */
 			}
 		}
 
diff --git a/src/BOOLEAN.c b/src/BOOLEAN.c
index 2c2bbcf..42374b8 100644
--- a/src/BOOLEAN.c
+++ b/src/BOOLEAN.c
@@ -9,7 +9,7 @@
 /*
  * BOOLEAN basic type description.
  */
-static ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = {
+static const ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (1 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_BOOLEAN = {
@@ -24,6 +24,8 @@
 	BOOLEAN_encode_xer,
 	BOOLEAN_decode_uper,	/* Unaligned PER decoder */
 	BOOLEAN_encode_uper,	/* Unaligned PER encoder */
+	BOOLEAN_decode_aper,	/* Aligned PER decoder */
+	BOOLEAN_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_BOOLEAN_tags,
 	sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]),
@@ -161,10 +163,7 @@
 		}
 		return XPBD_BODY_CONSUMED;
 	} else {
-		if(xer_is_whitespace(chunk_buf, chunk_size))
-			return XPBD_NOT_BODY_IGNORE;
-		else
-			return XPBD_BROKEN_ENCODING;
+		return XPBD_BROKEN_ENCODING;
 	}
 }
 
@@ -267,18 +266,63 @@
 	return rv;
 }
 
+asn_dec_rval_t
+BOOLEAN_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_dec_rval_t rv;
+	BOOLEAN_t *st = (BOOLEAN_t *)*sptr;
+
+	(void)opt_codec_ctx;
+	(void)constraints;
+
+	if(!st) {
+		st = (BOOLEAN_t *)(*sptr = MALLOC(sizeof(*st)));
+		if(!st) _ASN_DECODE_FAILED;
+	}
+
+	/*
+	 * Extract a single bit
+	 */
+	switch(per_get_few_bits(pd, 1)) {
+	case 1: *st = 1; break;
+	case 0: *st = 0; break;
+	case -1: default: _ASN_DECODE_STARVED;
+	}
+
+	ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE");
+
+	rv.code = RC_OK;
+	rv.consumed = 1;
+	return rv;
+}
 
 asn_enc_rval_t
 BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
 	const BOOLEAN_t *st = (const BOOLEAN_t *)sptr;
-	asn_enc_rval_t er;
+	asn_enc_rval_t er = { 0, 0, 0 };
 
 	(void)constraints;
 
 	if(!st) _ASN_ENCODE_FAILED;
 
-	per_put_few_bits(po, *st ? 1 : 0, 1);
+	if(per_put_few_bits(po, *st ? 1 : 0, 1))
+		_ASN_ENCODE_FAILED;
 
 	_ASN_ENCODED_OK(er);
 }
+
+asn_enc_rval_t
+BOOLEAN_encode_aper(asn_TYPE_descriptor_t *td,
+        asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+        const BOOLEAN_t *st = (const BOOLEAN_t *)sptr;
+        asn_enc_rval_t er;
+
+        (void)constraints;
+
+        if(!st) _ASN_ENCODE_FAILED;
+
+        per_put_few_bits(po, *st ? 1 : 0, 1);
+
+        _ASN_ENCODED_OK(er);
+}
diff --git a/src/ENUMERATED.c b/src/ENUMERATED.c
index 90761a2..f313f96 100644
--- a/src/ENUMERATED.c
+++ b/src/ENUMERATED.c
@@ -11,7 +11,7 @@
 /*
  * ENUMERATED basic type description.
  */
-static ber_tlv_tag_t asn_DEF_ENUMERATED_tags[] = {
+static const ber_tlv_tag_t asn_DEF_ENUMERATED_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_ENUMERATED = {
@@ -26,6 +26,8 @@
 	INTEGER_encode_xer,
 	ENUMERATED_decode_uper,	/* Unaligned PER decoder */
 	ENUMERATED_encode_uper,	/* Unaligned PER encoder */
+	ENUMERATED_decode_aper,	/* Aligned PER decoder */
+	ENUMERATED_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_ENUMERATED_tags,
 	sizeof(asn_DEF_ENUMERATED_tags) / sizeof(asn_DEF_ENUMERATED_tags[0]),
@@ -57,6 +59,27 @@
 	return rval;
 }
 
+asn_dec_rval_t
+ENUMERATED_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_dec_rval_t rval;
+	ENUMERATED_t *st = (ENUMERATED_t *)*sptr;
+	long value;
+	void *vptr = &value;
+
+	if(!st) {
+		st = (ENUMERATED_t *)(*sptr = CALLOC(1, sizeof(*st)));
+		if(!st) _ASN_DECODE_FAILED;
+	}
+
+	rval = NativeEnumerated_decode_aper(opt_codec_ctx, td, constraints,
+			(void **)&vptr, pd);
+	if(rval.code == RC_OK)
+		if(asn_long2INTEGER(st, value))
+			rval.code = RC_FAIL;
+	return rval;
+}
+
 asn_enc_rval_t
 ENUMERATED_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
@@ -69,3 +92,14 @@
 	return NativeEnumerated_encode_uper(td, constraints, &value, po);
 }
 
+asn_enc_rval_t
+ENUMERATED_encode_aper(asn_TYPE_descriptor_t *td,
+		asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+		ENUMERATED_t *st = (ENUMERATED_t *)sptr;
+		long value;
+
+		if(asn_INTEGER2long(st, &value))
+				_ASN_ENCODE_FAILED;
+
+		return NativeEnumerated_encode_aper(td, constraints, &value, po);
+}
diff --git a/src/GeneralString.c b/src/GeneralString.c
index 01b606b..934b8a2 100644
--- a/src/GeneralString.c
+++ b/src/GeneralString.c
@@ -8,7 +8,7 @@
 /*
  * GeneralString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_GeneralString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_GeneralString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (27 << 2)),	/* [UNIVERSAL 27] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -24,6 +24,8 @@
 	OCTET_STRING_encode_xer,
 	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GeneralString_tags,
 	sizeof(asn_DEF_GeneralString_tags)
diff --git a/src/GeneralizedTime.c b/src/GeneralizedTime.c
index 9d683ef..29dcc6c 100644
--- a/src/GeneralizedTime.c
+++ b/src/GeneralizedTime.c
@@ -14,7 +14,7 @@
 #include <time.h>
 #endif	/* __CYGWIN__ */
 
-#if	defined(WIN32)
+#if	defined(_WIN32)
 #pragma message( "PLEASE STOP AND READ!")
 #pragma message( "  localtime_r is implemented via localtime(), which may be not thread-safe.")
 #pragma message( "  gmtime_r is implemented via gmtime(), which may be not thread-safe.")
@@ -41,7 +41,7 @@
 #define	putenv(c)	_putenv(c)
 #define	_EMULATE_TIMEGM
 
-#endif	/* WIN32 */
+#endif	/* _WIN32 */
 
 #if	defined(sun) || defined(_sun_) || defined(__solaris__)
 #define	_EMULATE_TIMEGM
@@ -67,6 +67,14 @@
 #define	GMTOFF(tm)	(-timezone)
 #endif	/* HAVE_TM_GMTOFF */
 
+#if	defined(_WIN32)
+#pragma message( "PLEASE STOP AND READ!")
+#pragma message( "  timegm() is implemented via getenv(\"TZ\")/setenv(\"TZ\"), which may be not thread-safe.")
+#pragma message( "  ")
+#pragma message( "  You must fix the code by inserting appropriate locking")
+#pragma message( "  if you want to use asn_GT2time() or asn_UT2time().")
+#pragma message( "PLEASE STOP AND READ!")
+#else
 #if	(defined(_EMULATE_TIMEGM) || !defined(HAVE_TM_GMTOFF))
 #warning "PLEASE STOP AND READ!"
 #warning "  timegm() is implemented via getenv(\"TZ\")/setenv(\"TZ\"), which may be not thread-safe."
@@ -75,6 +83,7 @@
 #warning "  if you want to use asn_GT2time() or asn_UT2time()."
 #warning "PLEASE STOP AND READ!"
 #endif	/* _EMULATE_TIMEGM */
+#endif
 
 /*
  * Override our GMTOFF decision for other known platforms.
@@ -128,6 +137,7 @@
 	tzset();							\
 } while(0); } while(0);
 
+#ifndef HAVE_TIMEGM
 #ifdef	_EMULATE_TIMEGM
 static time_t timegm(struct tm *tm) {
 	time_t tloc;
@@ -138,6 +148,7 @@
 	return tloc;
 }
 #endif	/* _EMULATE_TIMEGM */
+#endif
 
 
 #ifndef	__ASN_INTERNAL_TEST_MODE__
@@ -145,7 +156,7 @@
 /*
  * GeneralizedTime basic type description.
  */
-static ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = {
+static const ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (24 << 2)),	/* [UNIVERSAL 24] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),  /* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))    /* ... OCTET STRING */
@@ -167,6 +178,8 @@
 	GeneralizedTime_encode_xer,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GeneralizedTime_tags,
 	sizeof(asn_DEF_GeneralizedTime_tags)
@@ -314,13 +327,14 @@
 		while(fd > frac_digits)
 			fv /= 10, fd--;
 		while(fd < frac_digits) {
-			int new_fv = fv * 10;
-			if(new_fv / 10 != fv) {
+			if(fv < INT_MAX / 10) {
+				fv *= 10;
+				fd++;
+			} else {
 				/* Too long precision request */
 				fv = 0;
 				break;
 			}
-			fv = new_fv, fd++;
 		}
 
 		*frac_value = fv;
@@ -441,16 +455,15 @@
 		 */
 		for(buf++; buf < end; buf++) {
 			int v = *buf;
-			int new_fvalue;
+			/* GCC 4.x is being too smart without volatile */
 			switch(v) {
 			case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
 			case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
-				new_fvalue = fvalue * 10 + (v - 0x30);
-				if(new_fvalue / 10 != fvalue) {
-					/* Not enough precision, ignore */
-				} else {
-					fvalue = new_fvalue;
+				if(fvalue < INT_MAX/10) {
+					fvalue = fvalue * 10 + (v - 0x30);
 					fdigits++;
+				} else {
+					/* Not enough precision, ignore */
 				}
 				continue;
 			default:
diff --git a/src/GraphicString.c b/src/GraphicString.c
index 7d59d52..5f62486 100644
--- a/src/GraphicString.c
+++ b/src/GraphicString.c
@@ -8,7 +8,7 @@
 /*
  * GraphicString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_GraphicString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_GraphicString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (25 << 2)),	/* [UNIVERSAL 25] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -24,6 +24,8 @@
 	OCTET_STRING_encode_xer,	/* Can't expect it to be ASCII/UTF8 */
 	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GraphicString_tags,
 	sizeof(asn_DEF_GraphicString_tags)
diff --git a/src/IA5String.c b/src/IA5String.c
index 02ecd3e..cec61c3 100644
--- a/src/IA5String.c
+++ b/src/IA5String.c
@@ -8,7 +8,7 @@
 /*
  * IA5String basic type description.
  */
-static ber_tlv_tag_t asn_DEF_IA5String_tags[] = {
+static const ber_tlv_tag_t asn_DEF_IA5String_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (22 << 2)),	/* [UNIVERSAL 22] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -29,6 +29,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_IA5String_tags,
 	sizeof(asn_DEF_IA5String_tags)
diff --git a/src/INTEGER.c b/src/INTEGER.c
index f016131..c74c5b4 100644
--- a/src/INTEGER.c
+++ b/src/INTEGER.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
+ * Copyright (c) 2003-2014 Lev Walkin <vlm@lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
@@ -11,7 +11,7 @@
 /*
  * INTEGER basic type description.
  */
-static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = {
+static const ber_tlv_tag_t asn_DEF_INTEGER_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_INTEGER = {
@@ -24,8 +24,17 @@
 	INTEGER_encode_der,
 	INTEGER_decode_xer,
 	INTEGER_encode_xer,
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+	0,
+	0,
+#else
 	INTEGER_decode_uper,	/* Unaligned PER decoder */
 	INTEGER_encode_uper,	/* Unaligned PER encoder */
+	INTEGER_decode_aper,
+	INTEGER_encode_aper,
+#endif	/* ASN_DISABLE_PER_SUPPORT */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_INTEGER_tags,
 	sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
@@ -101,52 +110,35 @@
  * INTEGER specific human-readable output.
  */
 static ssize_t
-INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {
+INTEGER__dump(const asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {
 	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
 	char scratch[32];	/* Enough for 64-bit integer */
 	uint8_t *buf = st->buf;
 	uint8_t *buf_end = st->buf + st->size;
-	signed long accum;
+	signed long value;
 	ssize_t wrote = 0;
 	char *p;
 	int ret;
 
-	/*
-	 * Advance buf pointer until the start of the value's body.
-	 * This will make us able to process large integers using simple case,
-	 * when the actual value is small
-	 * (0x0000000000abcdef would yield a fine 0x00abcdef)
-	 */
-	/* Skip the insignificant leading bytes */
-	for(; buf < buf_end-1; buf++) {
-		switch(*buf) {
-		case 0x00: if((buf[1] & 0x80) == 0) continue; break;
-		case 0xff: if((buf[1] & 0x80) != 0) continue; break;
-		}
-		break;
-	}
+	if(specs && specs->field_unsigned)
+		ret = asn_INTEGER2ulong(st, (unsigned long *)&value);
+	else
+		ret = asn_INTEGER2long(st, &value);
 
 	/* Simple case: the integer size is small */
-	if((size_t)(buf_end - buf) <= sizeof(accum)) {
+	if(ret == 0) {
 		const asn_INTEGER_enum_map_t *el;
 		size_t scrsize;
 		char *scr;
 
-		if(buf == buf_end) {
-			accum = 0;
-		} else {
-			accum = (*buf & 0x80) ? -1 : 0;
-			for(; buf < buf_end; buf++)
-				accum = (accum << 8) | *buf;
-		}
-
-		el = INTEGER_map_value2enum(specs, accum);
+		el = (value >= 0 || !specs || !specs->field_unsigned)
+			? INTEGER_map_value2enum(specs, value) : 0;
 		if(el) {
 			scrsize = el->enum_len + 32;
 			scr = (char *)alloca(scrsize);
 			if(plainOrXER == 0)
 				ret = snprintf(scr, scrsize,
-					"%ld (%s)", accum, el->enum_name);
+					"%ld (%s)", value, el->enum_name);
 			else
 				ret = snprintf(scr, scrsize,
 					"<%s/>", el->enum_name);
@@ -160,7 +152,7 @@
 			scr = scratch;
 			ret = snprintf(scr, scrsize,
 				(specs && specs->field_unsigned)
-				?"%lu":"%ld", accum);
+				?"%lu":"%ld", value);
 		}
 		assert(ret > 0 && (size_t)ret < scrsize);
 		return (cb(scr, ret, app_key) < 0) ? -1 : ret;
@@ -178,7 +170,7 @@
 	/* Output in the long xx:yy:zz... format */
 	/* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */
 	for(p = scratch; buf < buf_end; buf++) {
-		static const char *h2c = "0123456789ABCDEF";
+		const char * const h2c = "0123456789ABCDEF";
 		if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) {
 			/* Flush buffer */
 			if(cb(scratch, p - scratch, app_key) < 0)
@@ -220,8 +212,8 @@
 struct e2v_key {
 	const char *start;
 	const char *stop;
-	asn_INTEGER_enum_map_t *vemap;
-	unsigned int *evmap;
+	const asn_INTEGER_enum_map_t *vemap;
+	const unsigned int *evmap;
 };
 static int
 INTEGER__compar_enum2value(const void *kp, const void *am) {
@@ -244,7 +236,7 @@
 
 static const asn_INTEGER_enum_map_t *
 INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) {
-	asn_INTEGER_enum_map_t *el_found;
+	const asn_INTEGER_enum_map_t *el_found;
 	int count = specs ? specs->map_count : 0;
 	struct e2v_key key;
 	const char *lp;
@@ -319,57 +311,71 @@
 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;
+	long dec_value;
+	long hex_value = 0;
 	const char *lp;
 	const char *lstart = (const char *)chunk_buf;
 	const char *lstop = lstart + chunk_size;
 	enum {
-		ST_SKIPSPACE,
+		ST_LEADSPACE,
 		ST_SKIPSPHEX,
 		ST_WAITDIGITS,
 		ST_DIGITS,
+		ST_DIGITS_TRAILSPACE,
 		ST_HEXDIGIT1,
 		ST_HEXDIGIT2,
+		ST_HEXDIGITS_TRAILSPACE,
 		ST_HEXCOLON,
-		ST_EXTRASTUFF
-	} state = ST_SKIPSPACE;
+		ST_END_ENUM,
+		ST_UNEXPECTED
+	} state = ST_LEADSPACE;
+	const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */
+	const char *dec_value_end = 0;
 
 	if(chunk_size)
 		ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x",
 			(long)chunk_size, *lstart, lstop[-1]);
 
+	if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
+		return XPBD_SYSTEM_FAILURE;
+
 	/*
 	 * We may have received a tag here. It will be processed inline.
 	 * Use strtoul()-like code and serialize the result.
 	 */
-	for(value = 0, lp = lstart; lp < lstop; lp++) {
+	for(lp = lstart; lp < lstop; lp++) {
 		int lv = *lp;
 		switch(lv) {
 		case 0x09: case 0x0a: case 0x0d: case 0x20:
 			switch(state) {
-			case ST_SKIPSPACE:
+			case ST_LEADSPACE:
+			case ST_DIGITS_TRAILSPACE:
+			case ST_HEXDIGITS_TRAILSPACE:
 			case ST_SKIPSPHEX:
 				continue;
+			case ST_DIGITS:
+				dec_value_end = lp;
+				state = ST_DIGITS_TRAILSPACE;
+				continue;
 			case ST_HEXCOLON:
-				if(xer_is_whitespace(lp, lstop - lp)) {
-					lp = lstop - 1;
-					continue;
-				}
-				break;
+				state = ST_HEXDIGITS_TRAILSPACE;
+				continue;
 			default:
 				break;
 			}
 			break;
 		case 0x2d:	/* '-' */
-			if(state == ST_SKIPSPACE) {
-				sign = -1;
+			if(state == ST_LEADSPACE) {
+				dec_value = 0;
+				dec_value_start = lp;
 				state = ST_WAITDIGITS;
 				continue;
 			}
 			break;
 		case 0x2b:	/* '+' */
-			if(state == ST_SKIPSPACE) {
+			if(state == ST_LEADSPACE) {
+				dec_value = 0;
+				dec_value_start = lp;
 				state = ST_WAITDIGITS;
 				continue;
 			}
@@ -377,57 +383,41 @@
 		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
 		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
 			switch(state) {
-			case ST_DIGITS: break;
+			case ST_DIGITS: continue;
 			case ST_SKIPSPHEX:	/* Fall through */
 			case ST_HEXDIGIT1:
-				value = (lv - 0x30) << 4;
+				hex_value = (lv - 0x30) << 4;
 				state = ST_HEXDIGIT2;
 				continue;
 			case ST_HEXDIGIT2:
-				value += (lv - 0x30);
+				hex_value += (lv - 0x30);
 				state = ST_HEXCOLON;
-				st->buf[st->size++] = (uint8_t)value;
+				st->buf[st->size++] = (uint8_t)hex_value;
 				continue;
 			case ST_HEXCOLON:
 				return XPBD_BROKEN_ENCODING;
-			default:
+			case ST_LEADSPACE:
+				dec_value = 0;
+				dec_value_start = lp;
+				/* FALL THROUGH */
+			case ST_WAITDIGITS:
 				state = ST_DIGITS;
+				continue;
+			default:
 				break;
 			}
-
-		    {
-			long new_value = value * 10;
-
-			if(new_value / 10 != value)
-				/* Overflow */
-				return XPBD_DECODER_LIMIT;
-
-			value = new_value + (lv - 0x30);
-			/* Check for two's complement overflow */
-			if(value < 0) {
-				/* Check whether it is a LONG_MIN */
-				if(sign == -1
-				&& (unsigned long)value
-						== ~((unsigned long)-1 >> 1)) {
-					sign = 1;
-				} else {
-					/* Overflow */
-					return XPBD_DECODER_LIMIT;
-				}
-			}
-		    }
-			continue;
-		case 0x3c:	/* '<' */
-			if(state == ST_SKIPSPACE) {
+			break;
+		case 0x3c:	/* '<', start of XML encoded enumeration */
+			if(state == ST_LEADSPACE) {
 				const asn_INTEGER_enum_map_t *el;
 				el = INTEGER_map_enum2value(
 					(asn_INTEGER_specifics_t *)
 					td->specifics, lstart, lstop);
 				if(el) {
-					ASN_DEBUG("Found \"%s\" => %ld",
+					ASN_DEBUG("Found \"%s\" => %lld",
 						el->enum_name, el->nat_value);
-					state = ST_DIGITS;
-					value = el->nat_value;
+					dec_value = el->nat_value;
+					state = ST_END_ENUM;
 					lp = lstop - 1;
 					continue;
 				}
@@ -445,13 +435,12 @@
 				 * places as a decimal value.
 				 * Switch decoding mode. */
 				ASN_DEBUG("INTEGER re-evaluate as hex form");
-				if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
-					return XPBD_SYSTEM_FAILURE;
 				state = ST_SKIPSPHEX;
+				dec_value_start = 0;
 				lp = lstart - 1;
 				continue;
 			} else {
-				ASN_DEBUG("state %d at %d", state, lp - lstart);
+				ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart));
 				break;
 			}
 		/* [A-Fa-f] */
@@ -459,24 +448,23 @@
 		case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:
 			switch(state) {
 			case ST_SKIPSPHEX:
-			case ST_SKIPSPACE: /* Fall through */
+			case ST_LEADSPACE: /* Fall through */
 			case ST_HEXDIGIT1:
-				value = lv - ((lv < 0x61) ? 0x41 : 0x61);
-				value += 10;
-				value <<= 4;
+				hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61);
+				hex_value += 10;
+				hex_value <<= 4;
 				state = ST_HEXDIGIT2;
 				continue;
 			case ST_HEXDIGIT2:
-				value += lv - ((lv < 0x61) ? 0x41 : 0x61);
-				value += 10;
-				st->buf[st->size++] = (uint8_t)value;
+				hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61);
+				hex_value += 10;
+				st->buf[st->size++] = (uint8_t)hex_value;
 				state = ST_HEXCOLON;
 				continue;
 			case ST_DIGITS:
 				ASN_DEBUG("INTEGER re-evaluate as hex form");
-				if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
-					return XPBD_SYSTEM_FAILURE;
 				state = ST_SKIPSPHEX;
+				dec_value_start = 0;
 				lp = lstart - 1;
 				continue;
 			default:
@@ -486,39 +474,54 @@
 		}
 
 		/* Found extra non-numeric stuff */
-		ASN_DEBUG("Found non-numeric 0x%2x at %d",
-			lv, lp - lstart);
-		state = ST_EXTRASTUFF;
+		ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld",
+			lv, (long)(lp - lstart));
+		state = ST_UNEXPECTED;
 		break;
 	}
 
 	switch(state) {
+	case ST_END_ENUM:
+		/* Got a complete and valid enumeration encoded as a tag. */
+		break;
 	case ST_DIGITS:
-		/* Everything is cool */
+		dec_value_end = lstop;
+		/* FALL THROUGH */
+	case ST_DIGITS_TRAILSPACE:
+		/* The last symbol encountered was a digit. */
+		switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) {
+		case ASN_STRTOL_OK:
+			break;
+		case ASN_STRTOL_ERROR_RANGE:
+			return XPBD_DECODER_LIMIT;
+		case ASN_STRTOL_ERROR_INVAL:
+		case ASN_STRTOL_EXPECT_MORE:
+		case ASN_STRTOL_EXTRA_DATA:
+			return XPBD_BROKEN_ENCODING;
+		}
 		break;
 	case ST_HEXCOLON:
+	case ST_HEXDIGITS_TRAILSPACE:
 		st->buf[st->size] = 0;	/* Just in case termination */
 		return XPBD_BODY_CONSUMED;
 	case ST_HEXDIGIT1:
 	case ST_HEXDIGIT2:
 	case ST_SKIPSPHEX:
 		return XPBD_BROKEN_ENCODING;
-	default:
-		if(xer_is_whitespace(lp, lstop - lp)) {
-			if(state != ST_EXTRASTUFF)
-				return XPBD_NOT_BODY_IGNORE;
-			break;
-		} else {
-			ASN_DEBUG("INTEGER: No useful digits (state %d)",
-				state);
-			return XPBD_BROKEN_ENCODING;	/* No digits */
-		}
-		break;
+	case ST_LEADSPACE:
+		/* Content not found */
+		return XPBD_NOT_BODY_IGNORE;
+	case ST_WAITDIGITS:
+	case ST_UNEXPECTED:
+		ASN_DEBUG("INTEGER: No useful digits (state %d)", state);
+		return XPBD_BROKEN_ENCODING;	/* No digits */
 	}
 
-	value *= sign;	/* Change sign, if needed */
-
-	if(asn_long2INTEGER(st, value))
+	/*
+	 * Convert the result of parsing of enumeration or a straight
+	 * decimal value into a BER representation.
+	 */
+	if(asn_long2INTEGER(st, dec_value))
 		return XPBD_SYSTEM_FAILURE;
 
 	return XPBD_BODY_CONSUMED;
@@ -553,6 +556,8 @@
 	_ASN_ENCODED_OK(er);
 }
 
+#ifndef	ASN_DISABLE_PER_SUPPORT
+
 asn_dec_rval_t
 INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
@@ -594,31 +599,179 @@
 		}
 	}
 
+	/* X.691-2008/11, #13.2.2, constrained whole number */
+	if(ct && ct->flags != APC_UNCONSTRAINED) {
+		/* #11.5.6 */
+		ASN_DEBUG("Integer with range %d bits", ct->range_bits);
+		if(ct->range_bits >= 0) {
+			if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
+				_ASN_DECODE_FAILED;
+
+			if(specs && specs->field_unsigned) {
+				unsigned long uvalue;
+				if(uper_get_constrained_whole_number(pd,
+					&uvalue, ct->range_bits))
+					_ASN_DECODE_STARVED;
+				ASN_DEBUG("Got value %lu + low %lld",
+					uvalue, ct->lower_bound);
+				uvalue += ct->lower_bound;
+				if(asn_ulong2INTEGER(st, uvalue))
+					_ASN_DECODE_FAILED;
+			} else {
+				unsigned long svalue;
+				if(uper_get_constrained_whole_number(pd,
+					&svalue, ct->range_bits))
+					_ASN_DECODE_STARVED;
+				ASN_DEBUG("Got value %ld + low %ld",
+					svalue, ct->lower_bound);
+				svalue += ct->lower_bound;
+				if(asn_long2INTEGER(st, svalue))
+					_ASN_DECODE_FAILED;
+			}
+			return rval;
+		}
+	} else {
+		ASN_DEBUG("Decoding unconstrained integer %s", td->name);
+	}
+
+	/* X.691, #12.2.3, #12.2.4 */
+	do {
+		ssize_t len;
+		void *p;
+		int ret;
+
+		/* Get the PER length */
+		len = uper_get_length(pd, -1, &repeat);
+		if(len < 0) _ASN_DECODE_STARVED;
+
+		p = REALLOC(st->buf, st->size + len + 1);
+		if(!p) _ASN_DECODE_FAILED;
+		st->buf = (uint8_t *)p;
+
+		ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);
+		if(ret < 0) _ASN_DECODE_STARVED;
+		st->size += len;
+	} while(repeat);
+	st->buf[st->size] = 0;	/* JIC */
+
+	/* #12.2.3 */
+	if(ct && ct->lower_bound) {
+		/*
+		 * TODO: replace by in-place arithmetics.
+		 */
+		long value;
+		if(asn_INTEGER2long(st, &value))
+			_ASN_DECODE_FAILED;
+		if(asn_long2INTEGER(st, value + ct->lower_bound))
+			_ASN_DECODE_FAILED;
+	}
+
+	return rval;
+}
+
+asn_dec_rval_t
+INTEGER_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
+	asn_dec_rval_t rval = { RC_OK, 0 };
+	INTEGER_t *st = (INTEGER_t *)*sptr;
+	asn_per_constraint_t *ct;
+	int repeat;
+
+	(void)opt_codec_ctx;
+
+	if(!st) {
+		st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
+		if(!st) _ASN_DECODE_FAILED;
+	}
+
+	if(!constraints) constraints = td->per_constraints;
+	ct = constraints ? &constraints->value : 0;
+
+	if(ct && ct->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) _ASN_DECODE_STARVED;
+		if(inext) ct = 0;
+	}
+
+	FREEMEM(st->buf);
+	st->buf = 0;
+	st->size = 0;
+	if(ct) {
+		if(ct->flags & APC_SEMI_CONSTRAINED) {
+			st->buf = (uint8_t *)CALLOC(1, 2);
+			if(!st->buf) _ASN_DECODE_FAILED;
+			st->size = 1;
+		} else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {
+			size_t size = (ct->range_bits + 7) >> 3;
+			st->buf = (uint8_t *)MALLOC(1 + size + 1);
+			if(!st->buf) _ASN_DECODE_FAILED;
+			st->size = size;
+		}
+	}
+
 	/* X.691, #12.2.2 */
 	if(ct && ct->flags != APC_UNCONSTRAINED) {
 		/* #10.5.6 */
 		ASN_DEBUG("Integer with range %d bits", ct->range_bits);
 		if(ct->range_bits >= 0) {
-			long value;
-			if(ct->range_bits == 32) {
-				long lhalf;
-				value = per_get_few_bits(pd, 16);
-				if(value < 0) _ASN_DECODE_STARVED;
-				lhalf = per_get_few_bits(pd, 16);
-				if(lhalf < 0) _ASN_DECODE_STARVED;
-				value = (value << 16) | lhalf;
+			if (ct->range_bits > 16) {
+				int max_range_bytes = (ct->range_bits >> 3) + 1;
+				int length, i;
+				int64_t value = 0;
+
+				for (i = 0; i < max_range_bytes; i++) {
+					int upper = 1 << (i + 1);
+					if (upper > max_range_bytes)
+						break;
+				}
+				if ((length = per_get_few_bits(pd, i + 1)) < 0)
+					_ASN_DECODE_STARVED;
+				if (aper_get_align(pd) != 0)
+					_ASN_DECODE_STARVED;
+				ASN_DEBUG("Got length %d", length + 1);
+				for (i = 0; i < length + 1; i++) {
+					int buf = per_get_few_bits(pd, 8);
+					if (buf < 0)
+						_ASN_DECODE_STARVED;
+					value += (((int64_t)buf) << (8 * i));
+				}
+
+				if((specs && specs->field_unsigned)
+					? asn_uint642INTEGER(st, value)
+					: asn_int642INTEGER(st, value))
+					_ASN_DECODE_FAILED;
+				ASN_DEBUG("Got value %lld + low %lld",
+						  value, ct->lower_bound);
+				value += ct->lower_bound;
 			} else {
-				value = per_get_few_bits(pd, ct->range_bits);
-				if(value < 0) _ASN_DECODE_STARVED;
+				long value = 0;
+				if (ct->range_bits < 8) {
+					value = per_get_few_bits(pd, ct->range_bits);
+					if(value < 0) _ASN_DECODE_STARVED;
+				} else if (ct->range_bits == 8) {
+					if (aper_get_align(pd) < 0)
+						_ASN_DECODE_FAILED;
+					value = per_get_few_bits(pd, ct->range_bits);
+					if(value < 0) _ASN_DECODE_STARVED;
+				} else {
+					/* Align */
+					if (aper_get_align(pd) < 0)
+						_ASN_DECODE_FAILED;
+					value = per_get_few_bits(pd, 16);
+					if(value < 0) _ASN_DECODE_STARVED;
+				}
+				if((specs && specs->field_unsigned)
+					? asn_ulong2INTEGER(st, value)
+					: asn_long2INTEGER(st, value))
+					_ASN_DECODE_FAILED;
+					ASN_DEBUG("Got value %ld + low %lld",
+							  value, ct->lower_bound);
+				value += ct->lower_bound;
 			}
-			ASN_DEBUG("Got value %ld + low %ld",
-				value, ct->lower_bound);
-			value += ct->lower_bound;
-			if((specs && specs->field_unsigned)
-				? asn_ulong2INTEGER(st, value)
-				: asn_long2INTEGER(st, value))
-				_ASN_DECODE_FAILED;
 			return rval;
+		} else {
+			_ASN_DECODE_FAILED;
 		}
 	} else {
 		ASN_DEBUG("Decoding unconstrained integer %s", td->name);
@@ -631,7 +784,7 @@
 		int ret;
 
 		/* Get the PER length */
-		len = uper_get_length(pd, -1, &repeat);
+		len = aper_get_length(pd, -1, -1, &repeat);
 		if(len < 0) _ASN_DECODE_STARVED;
 
 		p = REALLOC(st->buf, st->size + len + 1);
@@ -692,7 +845,7 @@
 				|| uval > (unsigned long)ct->upper_bound)
 					inext = 1;
 			}
-			ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s",
+			ASN_DEBUG("Value %lu (%02x/%d) lb %llu ub %llu %s",
 				uval, st->buf[0], st->size,
 				ct->lower_bound, ct->upper_bound,
 				inext ? "ext" : "fix");
@@ -709,7 +862,7 @@
 				|| value > ct->upper_bound)
 					inext = 1;
 			}
-			ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s",
+			ASN_DEBUG("Value %ld (%02x/%d) lb %lld ub %lld %s",
 				value, st->buf[0], st->size,
 				ct->lower_bound, ct->upper_bound,
 				inext ? "ext" : "fix");
@@ -724,27 +877,19 @@
 	}
 
 
-	/* X.691, #12.2.2 */
+	/* X.691-11/2008, #13.2.2, test if constrained whole number */
 	if(ct && ct->range_bits >= 0) {
-		/* #10.5.6 */
-		ASN_DEBUG("Encoding integer with range %d bits",
-			ct->range_bits);
-		if(ct->range_bits == 32) {
-			/* TODO: extend to >32 bits */
-			long v = value - ct->lower_bound;
-			if(per_put_few_bits(po, v >> 1, 31)
-			|| per_put_few_bits(po, v, 1))
-				_ASN_ENCODE_FAILED;
-		} else {
-			if(per_put_few_bits(po, value - ct->lower_bound,
-				ct->range_bits))
-				_ASN_ENCODE_FAILED;
-		}
+		/* #11.5.6 -> #11.3 */
+		ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",
+			value, value - ct->lower_bound, ct->range_bits);
+		unsigned long v = value - ct->lower_bound;
+		if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))
+			_ASN_ENCODE_FAILED;
 		_ASN_ENCODED_OK(er);
 	}
 
 	if(ct && ct->lower_bound) {
-		ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);
+		ASN_DEBUG("Adjust lower bound to %lld", ct->lower_bound);
 		/* TODO: adjust lower bound */
 		_ASN_ENCODE_FAILED;
 	}
@@ -761,6 +906,131 @@
 	_ASN_ENCODED_OK(er);
 }
 
+asn_enc_rval_t
+INTEGER_encode_aper(asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
+	asn_enc_rval_t er;
+	INTEGER_t *st = (INTEGER_t *)sptr;
+	const uint8_t *buf;
+	const uint8_t *end;
+	asn_per_constraint_t *ct;
+	int64_t value = 0;
+
+	if(!st || st->size == 0) _ASN_ENCODE_FAILED;
+
+	if(!constraints) constraints = td->per_constraints;
+	ct = constraints ? &constraints->value : 0;
+
+	er.encoded = 0;
+
+	if(ct) {
+		int inext = 0;
+		if(specs && specs->field_unsigned) {
+			uint64_t uval;
+			if(asn_INTEGER2uint64(st, &uval))
+				_ASN_ENCODE_FAILED;
+			/* Check proper range */
+			if(ct->flags & APC_SEMI_CONSTRAINED) {
+				if(uval < (unsigned long long)ct->lower_bound)
+					inext = 1;
+			} else if(ct->range_bits >= 0) {
+				if(uval < (unsigned long long)ct->lower_bound
+					|| uval > (unsigned long long)ct->upper_bound)
+					inext = 1;
+			}
+			ASN_DEBUG("Value %llu (%02x/%d) lb %llu ub %llu %s",
+								uval, st->buf[0], st->size,
+								ct->lower_bound, ct->upper_bound,
+								inext ? "ext" : "fix");
+						value = uval;
+		} else {
+			if(asn_INTEGER2int64(st, &value)) _ASN_ENCODE_FAILED;
+			/* Check proper range */
+			if(ct->flags & APC_SEMI_CONSTRAINED) {
+				if(value < ct->lower_bound)
+					inext = 1;
+			} else if(ct->range_bits >= 0) {
+				if(value < ct->lower_bound
+					|| value > ct->upper_bound)
+					inext = 1;
+			}
+			ASN_DEBUG("Value %lld (%02x/%d) lb %lld ub %lld %s",
+					  value, st->buf[0], st->size,
+					  ct->lower_bound, ct->upper_bound,
+					  inext ? "ext" : "fix");
+		}
+		if(ct->flags & APC_EXTENSIBLE) {
+			if(per_put_few_bits(po, inext, 1))
+				_ASN_ENCODE_FAILED;
+			if(inext) ct = 0;
+		} else if(inext) {
+			_ASN_ENCODE_FAILED;
+		}
+	}
+
+	/* X.691, #12.2.2 */
+	if(ct && ct->range_bits >= 0) {
+		/* #10.5.6 */
+		ASN_DEBUG("Encoding integer with range %d bits",
+				  ct->range_bits);
+
+		/* #12 <= 8 -> alignment ? */
+		if (ct->range_bits < 8) {
+			if(per_put_few_bits(po, 0x00 | value, ct->range_bits))
+				_ASN_ENCODE_FAILED;
+		} else if (ct->range_bits == 8) {
+			if(aper_put_align(po) < 0)
+				_ASN_ENCODE_FAILED;
+			if(per_put_few_bits(po, 0x00 | value, ct->range_bits))
+				_ASN_ENCODE_FAILED;
+		} else if (ct->range_bits <= 16) {
+			// Consume the bytes to align on octet
+			if(aper_put_align(po) < 0)
+				_ASN_ENCODE_FAILED;
+			if(per_put_few_bits(po, 0x0000 | value,
+				16))
+				_ASN_ENCODE_FAILED;
+		} else {
+			/* TODO: extend to >64 bits */
+			int64_t v = value;
+			int i;
+
+			/* Putting length - 1 in the minimum number of bits ex: 5 = 3bits */
+			if (per_put_few_bits(po, st->size - 1, (ct->range_bits >> 3)-1))
+				_ASN_ENCODE_FAILED;
+
+			// Consume the bits to align on octet
+			if (aper_put_align(po) < 0)
+				_ASN_ENCODE_FAILED;
+			/* Put the value */
+			for (i = 0; i < st->size; i++) {
+				if(per_put_few_bits(po, (v >> (8 * (st->size - i - 1))) & 0xff, 8)) _ASN_ENCODE_FAILED;
+			}
+		}
+		_ASN_ENCODED_OK(er);
+	}
+
+	if(ct && ct->lower_bound) {
+		ASN_DEBUG("Adjust lower bound to %lld", ct->lower_bound);
+		/* TODO: adjust lower bound */
+		_ASN_ENCODE_FAILED;
+	}
+
+	for(buf = st->buf, end = st->buf + st->size; buf < end;) {
+		ssize_t mayEncode = aper_put_length(po, -1, end - buf);
+		if(mayEncode < 0)
+			_ASN_ENCODE_FAILED;
+		if(per_put_many_bits(po, buf, 8 * mayEncode))
+			_ASN_ENCODE_FAILED;
+		buf += mayEncode;
+	}
+
+	_ASN_ENCODED_OK(er);
+}
+
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+
 int
 asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
 	uint8_t *b, *end;
@@ -822,6 +1092,66 @@
 }
 
 int
+asn_INTEGER2int64(const INTEGER_t *iptr, int64_t *lptr) {
+	uint8_t *b, *end;
+	size_t size;
+	int64_t l;
+
+	/* Sanity checking */
+	if(!iptr || !iptr->buf || !lptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Cache the begin/end of the buffer */
+	b = iptr->buf;	/* Start of the INTEGER buffer */
+	size = iptr->size;
+	end = b + size;	/* Where to stop */
+
+	if(size > sizeof(int64_t)) {
+		uint8_t *end1 = end - 1;
+		/*
+		 * Slightly more advanced processing,
+		 * able to >sizeof(int64_t) bytes,
+		 * when the actual value is small
+		 * (0x0000000000abcdef would yield a fine 0x00abcdef)
+		 */
+		/* Skip out the insignificant leading bytes */
+		for(; b < end1; b++) {
+			switch(*b) {
+				case 0x00: if((b[1] & 0x80) == 0) continue; break;
+				case 0xff: if((b[1] & 0x80) != 0) continue; break;
+			}
+			break;
+		}
+
+		size = end - b;
+		if(size > sizeof(int64_t)) {
+			/* Still cannot fit the int64_t */
+			errno = ERANGE;
+			return -1;
+		}
+	}
+
+	/* Shortcut processing of a corner case */
+	if(end == b) {
+		*lptr = 0;
+		return 0;
+	}
+
+	/* Perform the sign initialization */
+	/* Actually l = -(*b >> 7); gains nothing, yet unreadable! */
+	if((*b >> 7)) l = -1; else l = 0;
+
+	/* Conversion engine */
+	for(; b < end; b++)
+		l = (l << 8) | *b;
+
+	*lptr = l;
+	return 0;
+}
+
+int
 asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) {
 	uint8_t *b, *end;
 	unsigned long l;
@@ -854,6 +1184,38 @@
 }
 
 int
+asn_INTEGER2uint64(const INTEGER_t *iptr, uint64_t *lptr) {
+	uint8_t *b, *end;
+	uint64_t l;
+	size_t size;
+
+	if(!iptr || !iptr->buf || !lptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	b = iptr->buf;
+	size = iptr->size;
+	end = b + size;
+
+	/* If all extra leading bytes are zeroes, ignore them */
+	for(; size > sizeof(uint64_t); b++, size--) {
+		if(*b) {
+			/* Value won't fit unsigned long */
+			errno = ERANGE;
+			return -1;
+		}
+	}
+
+	/* Conversion engine */
+	for(l = 0; b < end; b++)
+		l = (l << 8) | *b;
+
+	*lptr = l;
+	return 0;
+}
+
+int
 asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {
 	uint8_t *buf;
 	uint8_t *end;
@@ -879,6 +1241,86 @@
 }
 
 int
+asn_uint642INTEGER(INTEGER_t *st, uint64_t value) {
+	uint8_t *buf;
+	uint8_t *end;
+	uint8_t *b;
+	int shr;
+
+	if(value <= INT64_MAX)
+		return asn_int642INTEGER(st, value);
+
+	buf = (uint8_t *)MALLOC(1 + sizeof(value));
+	if(!buf) return -1;
+
+	end = buf + (sizeof(value) + 1);
+	buf[0] = 0;
+	for(b = buf + 1, shr = (sizeof(value)-1)*8; b < end; shr -= 8, b++)
+		*b = (uint8_t)(value >> shr);
+
+	if(st->buf) FREEMEM(st->buf);
+	st->buf = buf;
+	st->size = 1 + sizeof(value);
+
+	return 0;
+}
+
+int
+asn_int642INTEGER(INTEGER_t *st, int64_t value) {
+	uint8_t *buf, *bp;
+	uint8_t *p;
+	uint8_t *pstart;
+	uint8_t *pend1;
+	int littleEndian = 1;	/* Run-time detection */
+	int add;
+
+	if(!st) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	buf = (uint8_t *)MALLOC(sizeof(value));
+	if(!buf) return -1;
+
+	if(*(char *)&littleEndian) {
+		pstart = (uint8_t *)&value + sizeof(value) - 1;
+		pend1 = (uint8_t *)&value;
+		add = -1;
+	} else {
+		pstart = (uint8_t *)&value;
+		pend1 = pstart + sizeof(value) - 1;
+		add = 1;
+	}
+
+	/*
+	 * If the contents octet consists of more than one octet,
+	 * then bits of the first octet and bit 8 of the second octet:
+	 * a) shall not all be ones; and
+	 * b) shall not all be zero.
+	 */
+	for(p = pstart; p != pend1; p += add) {
+		switch(*p) {
+		case 0x00: if((*(p+add) & 0x80) == 0)
+				continue;
+			break;
+		case 0xff: if((*(p+add) & 0x80))
+				continue;
+			break;
+		}
+		break;
+	}
+	/* Copy the integer body */
+	for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add)
+		*bp++ = *p;
+
+	if(st->buf) FREEMEM(st->buf);
+	st->buf = buf;
+	st->size = bp - buf;
+
+	return 0;
+}
+
+int
 asn_long2INTEGER(INTEGER_t *st, long value) {
 	uint8_t *buf, *bp;
 	uint8_t *p;
@@ -932,3 +1374,92 @@
 
 	return 0;
 }
+
+/*
+ * This function is going to be DEPRECATED soon.
+ */
+enum asn_strtol_result_e
+asn_strtol(const char *str, const char *end, long *lp) {
+    const char *endp = end;
+
+    switch(asn_strtol_lim(str, &endp, lp)) {
+    case ASN_STRTOL_ERROR_RANGE:
+        return ASN_STRTOL_ERROR_RANGE;
+    case ASN_STRTOL_ERROR_INVAL:
+        return ASN_STRTOL_ERROR_INVAL;
+    case ASN_STRTOL_EXPECT_MORE:
+        return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+    case ASN_STRTOL_OK:
+        return ASN_STRTOL_OK;
+    case ASN_STRTOL_EXTRA_DATA:
+        return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+    }
+
+    return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+}
+
+/*
+ * Parse the number in the given string until the given *end position,
+ * returning the position after the last parsed character back using the
+ * same (*end) pointer.
+ * WARNING: This behavior is different from the standard strtol(3).
+ */
+enum asn_strtol_result_e
+asn_strtol_lim(const char *str, const char **end, long *lp) {
+	int sign = 1;
+	long l;
+
+	const long upper_boundary = LONG_MAX / 10;
+	long last_digit_max = LONG_MAX % 10;
+
+	if(str >= *end) return ASN_STRTOL_ERROR_INVAL;
+
+	switch(*str) {
+	case '-':
+		last_digit_max++;
+		sign = -1;
+	case '+':
+		str++;
+		if(str >= *end) {
+			*end = str;
+			return ASN_STRTOL_EXPECT_MORE;
+		}
+	}
+
+	for(l = 0; str < (*end); str++) {
+		switch(*str) {
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
+			int d = *str - '0';
+			if(l < upper_boundary) {
+				l = l * 10 + d;
+			} else if(l == upper_boundary) {
+				if(d <= last_digit_max) {
+					if(sign > 0) {
+						l = l * 10 + d;
+					} else {
+						sign = 1;
+						l = -l * 10 - d;
+					}
+				} else {
+					*end = str;
+					return ASN_STRTOL_ERROR_RANGE;
+				}
+			} else {
+				*end = str;
+				return ASN_STRTOL_ERROR_RANGE;
+			}
+		    }
+		    continue;
+		default:
+		    *end = str;
+		    *lp = sign * l;
+		    return ASN_STRTOL_EXTRA_DATA;
+		}
+	}
+
+	*end = str;
+	*lp = sign * l;
+	return ASN_STRTOL_OK;
+}
+
diff --git a/src/ISO646String.c b/src/ISO646String.c
index d6ded0e..a6cc761 100644
--- a/src/ISO646String.c
+++ b/src/ISO646String.c
@@ -8,7 +8,7 @@
 /*
  * ISO646String basic type description.
  */
-static ber_tlv_tag_t asn_DEF_ISO646String_tags[] = {
+static const ber_tlv_tag_t asn_DEF_ISO646String_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),	/* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -29,6 +29,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_ISO646String_tags,
 	sizeof(asn_DEF_ISO646String_tags)
diff --git a/src/Makefile.am b/src/Makefile.am
index 1bbcfc5..633cc04 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
 # This is _NOT_ the library release version, it's an API version.
 # Please read Chapter 6 "Library interface versions" of the libtool
 # documentation before making any modification
-LIBVERSION=0:0:0
+LIBVERSION=1:0:0
 
 AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include/asn1c
 AM_CFLAGS = -fPIC -Wall $(LIBOSMOCORE_CFLAGS)
diff --git a/src/NULL.c b/src/NULL.c
index 6d3316f..f514ca2 100644
--- a/src/NULL.c
+++ b/src/NULL.c
@@ -10,7 +10,7 @@
 /*
  * NULL basic type description.
  */
-static ber_tlv_tag_t asn_DEF_NULL_tags[] = {
+static const ber_tlv_tag_t asn_DEF_NULL_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (5 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_NULL = {
@@ -25,6 +25,8 @@
 	NULL_encode_xer,
 	NULL_decode_uper,	/* Unaligned PER decoder */
 	NULL_encode_uper,	/* Unaligned PER encoder */
+	NULL_decode_aper,	/* Aligned PER decoder */
+	NULL_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NULL_tags,
 	sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]),
@@ -73,11 +75,15 @@
 NULL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
 	(void)td;
 	(void)sptr;
+	(void)chunk_buf;    /* Going to be empty according to the rules below. */
 
-	if(xer_is_whitespace(chunk_buf, chunk_size))
-		return XPBD_BODY_CONSUMED;
-	else
+	/*
+	 * There must be no content in self-terminating <NULL/> tag.
+	 */
+	if(chunk_size)
 		return XPBD_BROKEN_ENCODING;
+	else
+		return XPBD_BODY_CONSUMED;
 }
 
 asn_dec_rval_t
@@ -132,6 +138,34 @@
 	return rv;
 }
 
+asn_dec_rval_t
+NULL_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_dec_rval_t rv;
+
+	(void)opt_codec_ctx;
+	(void)td;
+	(void)constraints;
+	(void)pd;
+
+	if(!*sptr) {
+		*sptr = MALLOC(sizeof(NULL_t));
+		if(*sptr) {
+			*(NULL_t *)*sptr = 0;
+		} else {
+			_ASN_DECODE_FAILED;
+		}
+	}
+
+	/*
+	 * NULL type does not have content octets.
+	 */
+
+	rv.code = RC_OK;
+	rv.consumed = 0;
+	return rv;
+}
+
 asn_enc_rval_t
 NULL_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
 		void *sptr, asn_per_outp_t *po) {
@@ -145,3 +179,17 @@
 	er.encoded = 0;
 	_ASN_ENCODED_OK(er);
 }
+
+asn_enc_rval_t
+NULL_encode_aper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
+                void *sptr, asn_per_outp_t *po) {
+        asn_enc_rval_t er;
+
+        (void)td;
+        (void)constraints;
+        (void)sptr;
+        (void)po;
+
+        er.encoded = 0;
+        _ASN_ENCODED_OK(er);
+}
diff --git a/src/NativeEnumerated.c b/src/NativeEnumerated.c
index 3184644..124e7f0 100644
--- a/src/NativeEnumerated.c
+++ b/src/NativeEnumerated.c
@@ -15,7 +15,7 @@
 /*
  * NativeEnumerated basic type description.
  */
-static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = {
+static const ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = {
@@ -30,6 +30,8 @@
 	NativeEnumerated_encode_xer,
 	NativeEnumerated_decode_uper,
 	NativeEnumerated_encode_uper,
+	NativeEnumerated_decode_aper,
+	NativeEnumerated_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NativeEnumerated_tags,
 	sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]),
@@ -125,6 +127,61 @@
 	return rval;
 }
 
+asn_dec_rval_t
+NativeEnumerated_decode_aper(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
+	void **sptr, asn_per_data_t *pd) {
+	asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics;
+	asn_dec_rval_t rval = { RC_OK, 0 };
+	long *native = (long *)*sptr;
+	asn_per_constraint_t *ct;
+	long value;
+
+	(void)opt_codec_ctx;
+
+	if(constraints) ct = &constraints->value;
+	else if(td->per_constraints) ct = &td->per_constraints->value;
+	else _ASN_DECODE_FAILED;	/* Mandatory! */
+	if(!specs) _ASN_DECODE_FAILED;
+
+	if(!native) {
+		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
+		if(!native) _ASN_DECODE_FAILED;
+	}
+
+	ASN_DEBUG("Decoding %s as NativeEnumerated", td->name);
+
+	if(ct->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) _ASN_DECODE_STARVED;
+		if(inext) ct = 0;
+	}
+
+	if(ct && ct->range_bits >= 0) {
+		value = per_get_few_bits(pd, ct->range_bits);
+		if(value < 0) _ASN_DECODE_STARVED;
+		if(value >= (specs->extension
+			? specs->extension - 1 : specs->map_count))
+			_ASN_DECODE_FAILED;
+	} else {
+		if(!specs->extension)
+			_ASN_DECODE_FAILED;
+		/*
+		 * X.691, #10.6: normally small non-negative whole number;
+		 */
+		value = uper_get_nsnnwn(pd);
+		if(value < 0) _ASN_DECODE_STARVED;
+		value += specs->extension - 1;
+		if(value >= specs->map_count)
+			_ASN_DECODE_FAILED;
+	}
+
+	*native = specs->value2enum[value].nat_value;
+	ASN_DEBUG("Decoded %s = %ld", td->name, *native);
+
+	return rval;
+}
+
 static int
 NativeEnumerated__compar_value2enum(const void *ap, const void *bp) {
 	const asn_INTEGER_enum_map_t *a = ap;
@@ -145,7 +202,7 @@
 	asn_per_constraint_t *ct;
 	int inext = 0;
 	asn_INTEGER_enum_map_t key;
-	asn_INTEGER_enum_map_t *kf;
+	const asn_INTEGER_enum_map_t *kf;
 
 	if(!sptr) _ASN_ENCODE_FAILED;
 	if(!specs) _ASN_ENCODE_FAILED;
@@ -205,6 +262,75 @@
 	_ASN_ENCODED_OK(er);
 }
 
+asn_enc_rval_t
+NativeEnumerated_encode_aper(asn_TYPE_descriptor_t *td,
+        asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+        asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics;
+        asn_enc_rval_t er;
+        long native, value;
+        asn_per_constraint_t *ct;
+        int inext = 0;
+        asn_INTEGER_enum_map_t key;
+        asn_INTEGER_enum_map_t *kf;
+
+        if(!sptr) _ASN_ENCODE_FAILED;
+        if(!specs) _ASN_ENCODE_FAILED;
+
+        if(constraints) ct = &constraints->value;
+        else if(td->per_constraints) ct = &td->per_constraints->value;
+        else _ASN_ENCODE_FAILED;        /* Mandatory! */
+
+        ASN_DEBUG("Encoding %s as NativeEnumerated", td->name);
+
+        er.encoded = 0;
+
+        native = *(long *)sptr;
+        if(native < 0) _ASN_ENCODE_FAILED;
+
+        key.nat_value = native;
+        kf = bsearch(&key, specs->value2enum, specs->map_count,
+                sizeof(key), NativeEnumerated__compar_value2enum);
+        if(!kf) {
+                ASN_DEBUG("No element corresponds to %ld", native);
+                _ASN_ENCODE_FAILED;
+        }
+        value = kf - specs->value2enum;
+
+        if(ct->range_bits >= 0) {
+                int cmpWith = specs->extension
+                                ? specs->extension - 1 : specs->map_count;
+                if(value >= cmpWith)
+                        inext = 1;
+        }
+        if(ct->flags & APC_EXTENSIBLE) {
+                if(per_put_few_bits(po, inext, 1))
+                        _ASN_ENCODE_FAILED;
+                if(inext) ct = 0;
+        } else if(inext) {
+                _ASN_ENCODE_FAILED;
+        }
+
+        if(ct && ct->range_bits >= 0) {
+                if(per_put_few_bits(po, value, ct->range_bits))
+                        _ASN_ENCODE_FAILED;
+                _ASN_ENCODED_OK(er);
+        }
+
+        if(!specs->extension)
+                _ASN_ENCODE_FAILED;
+
+        /*
+         * X.691, #10.6: normally small non-negative whole number;
+         */
+        ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld",
+                value, specs->extension, inext,
+                value - (inext ? (specs->extension - 1) : 0));
+        if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0)))
+                _ASN_ENCODE_FAILED;
+
+        _ASN_ENCODED_OK(er);
+}
+
 int
 NativeEnumerated_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
diff --git a/src/NativeInteger.c b/src/NativeInteger.c
index abdb71a..ef17bee 100644
--- a/src/NativeInteger.c
+++ b/src/NativeInteger.c
@@ -16,7 +16,7 @@
 /*
  * NativeInteger basic type description.
  */
-static ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = {
+static const ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_NativeInteger = {
@@ -31,6 +31,8 @@
 	NativeInteger_encode_xer,
 	NativeInteger_decode_uper,	/* Unaligned PER decoder */
 	NativeInteger_encode_uper,	/* Unaligned PER encoder */
+	NativeInteger_decode_aper,	/* Aligned PER decoder */
+	NativeInteger_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NativeInteger_tags,
 	sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]),
@@ -107,7 +109,7 @@
 		tmp.size = length;
 
 		if((specs&&specs->field_unsigned)
-			? asn_INTEGER2ulong(&tmp, &l)
+			? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */
 			: asn_INTEGER2long(&tmp, &l)) {
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
@@ -187,7 +189,7 @@
 	if(rval.code == RC_OK) {
 		long l;
 		if((specs&&specs->field_unsigned)
-			? asn_INTEGER2ulong(&st, &l)
+			? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */
 			: asn_INTEGER2long(&st, &l)) {
 			rval.code = RC_FAIL;
 			rval.consumed = 0;
@@ -255,7 +257,43 @@
 				   &tmpintptr, pd);
 	if(rval.code == RC_OK) {
 		if((specs&&specs->field_unsigned)
-			? asn_INTEGER2ulong(&tmpint, native)
+			? asn_INTEGER2ulong(&tmpint, (unsigned long *)native)
+			: asn_INTEGER2long(&tmpint, native))
+			rval.code = RC_FAIL;
+		else
+			ASN_DEBUG("NativeInteger %s got value %ld",
+				td->name, *native);
+	}
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+
+	return rval;
+}
+
+asn_dec_rval_t
+NativeInteger_decode_aper(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
+	asn_dec_rval_t rval;
+	long *native = (long *)*sptr;
+	INTEGER_t tmpint;
+	void *tmpintptr = &tmpint;
+
+	(void)opt_codec_ctx;
+	ASN_DEBUG("Decoding NativeInteger %s (APER)", td->name);
+
+	if(!native) {
+		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
+		if(!native) _ASN_DECODE_FAILED;
+	}
+
+	memset(&tmpint, 0, sizeof tmpint);
+	rval = INTEGER_decode_aper(opt_codec_ctx, td, constraints,
+				   &tmpintptr, pd);
+	if(rval.code == RC_OK) {
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&tmpint, (unsigned long *)native)
 			: asn_INTEGER2long(&tmpint, native))
 			rval.code = RC_FAIL;
 		else
@@ -291,6 +329,32 @@
 	return er;
 }
 
+asn_enc_rval_t
+NativeInteger_encode_aper(
+	asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+
+	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
+	asn_enc_rval_t er;
+	long native;
+	INTEGER_t tmpint;
+
+	if(!sptr) _ASN_ENCODE_FAILED;
+
+	native = *(long *)sptr;
+
+	ASN_DEBUG("Encoding NativeInteger %s %ld (APER)", td->name, native);
+
+	memset(&tmpint, 0, sizeof(tmpint));
+	if((specs&&specs->field_unsigned)
+		? asn_ulong2INTEGER(&tmpint, native)
+		: asn_long2INTEGER(&tmpint, native))
+		_ASN_ENCODE_FAILED;
+	er = INTEGER_encode_aper(td, constraints, &tmpint, po);
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+	return er;
+}
+
 /*
  * INTEGER specific human-readable output.
  */
diff --git a/src/NativeReal.c b/src/NativeReal.c
index a1ff91e..3bd5a28 100644
--- a/src/NativeReal.c
+++ b/src/NativeReal.c
@@ -17,7 +17,7 @@
 /*
  * NativeReal basic type description.
  */
-static ber_tlv_tag_t asn_DEF_NativeReal_tags[] = {
+static const ber_tlv_tag_t asn_DEF_NativeReal_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (9 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_NativeReal = {
@@ -32,6 +32,8 @@
 	NativeReal_encode_xer,
 	NativeReal_decode_uper,
 	NativeReal_encode_uper,
+	NativeReal_decode_aper,
+	NativeReal_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NativeReal_tags,
 	sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
@@ -107,10 +109,39 @@
 		tmp.buf = (uint8_t *)unconst_buf.nonconstbuf;
 		tmp.size = length;
 
-		if(asn_REAL2double(&tmp, &d)) {
-			rval.code = RC_FAIL;
-			rval.consumed = 0;
-			return rval;
+		if(length < (ber_tlv_len_t)size) {
+			int ret;
+			uint8_t saved_byte = tmp.buf[tmp.size];
+			tmp.buf[tmp.size] = '\0';
+			ret = asn_REAL2double(&tmp, &d);
+			tmp.buf[tmp.size] = saved_byte;
+			if(ret) {
+				rval.code = RC_FAIL;
+				rval.consumed = 0;
+				return rval;
+			}
+		} else if(length < 48 /* Enough for longish %f value. */) {
+			tmp.buf = alloca(length + 1);
+			tmp.size = length;
+			memcpy(tmp.buf, buf_ptr, length);
+			tmp.buf[tmp.size] = '\0';
+			if(asn_REAL2double(&tmp, &d)) {
+				rval.code = RC_FAIL;
+				rval.consumed = 0;
+				return rval;
+			}
+		} else {
+			/* This should probably never happen: impractically long value */
+			tmp.buf = CALLOC(1, length + 1);
+			tmp.size = length;
+			if(tmp.buf) memcpy(tmp.buf, buf_ptr, length);
+			if(!tmp.buf || asn_REAL2double(&tmp, &d)) {
+				FREEMEM(tmp.buf);
+				rval.code = RC_FAIL;
+				rval.consumed = 0;
+				return rval;
+			}
+			FREEMEM(tmp.buf);
 		}
 
 		*Dbl = d;
@@ -199,6 +230,43 @@
 	return rval;
 }
 
+asn_dec_rval_t
+NativeReal_decode_aper(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
+		void **dbl_ptr, asn_per_data_t *pd) {
+	double *Dbl = (double *)*dbl_ptr;
+	asn_dec_rval_t rval;
+	REAL_t tmp;
+	void *ptmp = &tmp;
+	int ret;
+
+	(void)constraints;
+
+	/*
+	 * If the structure is not there, allocate it.
+	 */
+	if(Dbl == NULL) {
+		*dbl_ptr = CALLOC(1, sizeof(*Dbl));
+		Dbl = (double *)*dbl_ptr;
+		if(Dbl == NULL)
+			_ASN_DECODE_FAILED;
+	}
+
+	memset(&tmp, 0, sizeof(tmp));
+	rval = OCTET_STRING_decode_aper(opt_codec_ctx, td, NULL,
+			&ptmp, pd);
+	if(rval.code != RC_OK) {
+		ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
+		return rval;
+	}
+
+	ret = asn_REAL2double(&tmp, Dbl);
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
+	if(ret) _ASN_DECODE_FAILED;
+
+	return rval;
+}
+
 /*
  * Encode the NativeReal using the OCTET STRING PER encoder.
  */
@@ -228,6 +296,32 @@
 	return erval;
 }
 
+asn_enc_rval_t
+NativeReal_encode_aper(asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	double Dbl = *(const double *)sptr;
+	asn_enc_rval_t erval;
+	REAL_t tmp;
+
+	(void)constraints;
+
+	/* Prepare a temporary clean structure */
+	memset(&tmp, 0, sizeof(tmp));
+
+	if(asn_double2REAL(&tmp, Dbl))
+		_ASN_ENCODE_FAILED;
+
+	/* Encode a DER REAL */
+	erval = OCTET_STRING_encode_aper(td, NULL, &tmp, po);
+	if(erval.encoded == -1)
+		erval.structure_ptr = sptr;
+
+	/* Free possibly allocated members of the temporary structure */
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
+
+	return erval;
+}
+
 /*
  * Decode the chunk of XML text encoding REAL.
  */
diff --git a/src/NumericString.c b/src/NumericString.c
index 50fe449..81b880a 100644
--- a/src/NumericString.c
+++ b/src/NumericString.c
@@ -8,7 +8,7 @@
 /*
  * NumericString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_NumericString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_NumericString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (18 << 2)),	/* [UNIVERSAL 18] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -49,6 +49,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NumericString_tags,
 	sizeof(asn_DEF_NumericString_tags)
diff --git a/src/OBJECT_IDENTIFIER.c b/src/OBJECT_IDENTIFIER.c
index 0d7043e..24f4e0e 100644
--- a/src/OBJECT_IDENTIFIER.c
+++ b/src/OBJECT_IDENTIFIER.c
@@ -3,6 +3,7 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
+#include <INTEGER.h>
 #include <OBJECT_IDENTIFIER.h>
 #include <OCTET_STRING.h>
 #include <limits.h>	/* for CHAR_BIT */
@@ -11,7 +12,7 @@
 /*
  * OBJECT IDENTIFIER basic type description.
  */
-static ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
+static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
@@ -26,6 +27,8 @@
 	OBJECT_IDENTIFIER_encode_xer,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_OBJECT_IDENTIFIER_tags,
 	sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
@@ -64,9 +67,9 @@
 
 
 int
-OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) {
+OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) {
 	unsigned LE GCC_NOTUSED = 1; /* Little endian (x86) */
-	uint8_t *arcend = arcbuf + arclen;	/* End of arc */
+	const uint8_t *arcend = arcbuf + arclen;	/* End of arc */
 	unsigned int cache = 0;	/* No more than 14 significant bits */
 	unsigned char *rvbuf = (unsigned char *)rvbufp;
 	unsigned char *rvstart = rvbuf;	/* Original start of the value buffer */
@@ -119,7 +122,7 @@
 			errno = ERANGE;	/* Overflow */
 			return -1;
 		}
-		*(unsigned long *)rvbuf = accum + add;	/* alignment OK! */
+		*(unsigned long *)(void *)rvbuf = accum + add;	/* alignment OK! */
 		return 0;
 	}
 
@@ -180,7 +183,7 @@
 }
 
 ssize_t
-OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add,
+OBJECT_IDENTIFIER__dump_arc(const 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 */
@@ -211,7 +214,7 @@
 }
 
 int
-OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
+OBJECT_IDENTIFIER_print_arc(const 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)
@@ -281,15 +284,13 @@
 	arcs_count = OBJECT_IDENTIFIER_parse_arcs(
 		(const char *)chunk_buf, chunk_size, arcs,
 			sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
-	if(arcs_count <= 0) {
+	if(arcs_count < 0) {
 		/* Expecting more than zero arcs */
 		return XPBD_BROKEN_ENCODING;
+	} else if(arcs_count == 0) {
+		return XPBD_NOT_BODY_IGNORE;
 	}
-	if(endptr < chunk_end) {
-		/* We have a tail of unrecognized data. Check its safety. */
-		if(!xer_is_whitespace(endptr, chunk_end - endptr))
-			return XPBD_BROKEN_ENCODING;
-	}
+	assert(endptr == chunk_end);
 
 	if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
 		arcs = (long *)MALLOC(arcs_count * sizeof(long));
@@ -361,7 +362,7 @@
 }
 
 int
-OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs,
+OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid, void *arcs,
 		unsigned int arc_type_size, unsigned int arc_slots) {
 	void *arcs_end = (char *)arcs + (arc_type_size * arc_slots);
 	int num_arcs = 0;
@@ -649,12 +650,12 @@
 	long *arcs, unsigned int arcs_slots, const char **opt_oid_text_end) {
 	unsigned int arcs_count = 0;
 	const char *oid_end;
-	long value = 0;
 	enum {
-		ST_SKIPSPACE,
+		ST_LEADSPACE,
+		ST_TAILSPACE,
+		ST_AFTERVALUE,	/* Next character ought to be '.' or a space */
 		ST_WAITDIGITS,	/* Next character is expected to be a digit */
-		ST_DIGITS
-	} state = ST_SKIPSPACE;
+	} state = ST_LEADSPACE;
 
 	if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) {
 		if(opt_oid_text_end) *opt_oid_text_end = oid_text;
@@ -665,41 +666,76 @@
 	if(oid_txt_length == -1)
 		oid_txt_length = strlen(oid_text);
 
+#define	_OID_CAPTURE_ARC(oid_text, oid_end)		do {	\
+	const char *endp = oid_end;				\
+	long value;						\
+	switch(asn_strtol_lim(oid_text, &endp, &value)) {	\
+	case ASN_STRTOL_EXTRA_DATA:				\
+	case ASN_STRTOL_OK:					\
+		if(arcs_count < arcs_slots)			\
+			arcs[arcs_count] = value;		\
+		arcs_count++;					\
+		oid_text = endp - 1;				\
+		break;						\
+	case ASN_STRTOL_ERROR_RANGE:				\
+		if(opt_oid_text_end)				\
+			*opt_oid_text_end = oid_text;		\
+		errno = ERANGE;					\
+		return -1;					\
+	case ASN_STRTOL_ERROR_INVAL:				\
+	case ASN_STRTOL_EXPECT_MORE:				\
+		if(opt_oid_text_end)				\
+			*opt_oid_text_end = oid_text;		\
+		errno = EINVAL;					\
+		return -1;					\
+	}							\
+  } while(0)
+
 	for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
 	    switch(*oid_text) {
 	    case 0x09: case 0x0a: case 0x0d: case 0x20:	/* whitespace */
-		if(state == ST_SKIPSPACE) {
+		switch(state) {
+		case ST_LEADSPACE:
+		case ST_TAILSPACE:
 			continue;
-		} else {
-			break;	/* Finish */
+		case ST_AFTERVALUE:
+			state = ST_TAILSPACE;
+			continue;
+		case ST_WAITDIGITS:
+			break;	/* Digits expected after ".", got whitespace */
 		}
+		break;
 	    case 0x2e:	/* '.' */
-		if(state != ST_DIGITS
-		|| (oid_text + 1) == oid_end) {
-			state = ST_WAITDIGITS;
+		switch(state) {
+		case ST_LEADSPACE:
+		case ST_TAILSPACE:
+		case ST_WAITDIGITS:
+			if(opt_oid_text_end)
+				*opt_oid_text_end = oid_text;
+			errno = EINVAL;	/* Broken OID */
+			return -1;
 			break;
+		case ST_AFTERVALUE:
+			state = ST_WAITDIGITS;
+			continue;
 		}
-		if(arcs_count < arcs_slots)
-			arcs[arcs_count] = value;
-		arcs_count++;
-		state = ST_WAITDIGITS;
-		continue;
+		break;
 	    case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
 	    case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
-		if(state != ST_DIGITS) {
-			state = ST_DIGITS;
-			value = 0;
-		}
-		if(1) {
-			long new_value = value * 10;
-			if(new_value / 10 != value
-			|| (value = new_value + (*oid_text - 0x30)) < 0) {
-				/* Overflow */
-				state = ST_WAITDIGITS;
-				break;
-			}
+		switch(state) {
+		case ST_TAILSPACE:
+		case ST_AFTERVALUE:
+			if(opt_oid_text_end)
+				*opt_oid_text_end = oid_text;
+			errno = EINVAL;	/* "1. 1" => broken OID */
+			return -1;
+		case ST_LEADSPACE:
+		case ST_WAITDIGITS:
+			_OID_CAPTURE_ARC(oid_text, oid_end);
+			state = ST_AFTERVALUE;
 			continue;
 		}
+		break;
 	    default:
 		/* Unexpected symbols */
 		state = ST_WAITDIGITS;
@@ -713,17 +749,18 @@
 
 	/* Finalize last arc */
 	switch(state) {
+	case ST_LEADSPACE:
+		return 0; /* No OID found in input data */
 	case ST_WAITDIGITS:
-		errno = EINVAL;
+		errno = EINVAL;	/* Broken OID */
 		return -1;
-	case ST_DIGITS:
-		if(arcs_count < arcs_slots)
-			arcs[arcs_count] = value;
-		arcs_count++;
-		/* Fall through */
-	default:
+	case ST_AFTERVALUE:
+	case ST_TAILSPACE:
 		return arcs_count;
 	}
+
+	errno = EINVAL;	/* Broken OID */
+	return -1;
 }
 
 
diff --git a/src/OCTET_STRING.c b/src/OCTET_STRING.c
index 584def8..3e424e7 100644
--- a/src/OCTET_STRING.c
+++ b/src/OCTET_STRING.c
@@ -11,15 +11,15 @@
 /*
  * OCTET STRING basic type description.
  */
-static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
+static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
 };
-static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = {
+static const asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = {
 	sizeof(OCTET_STRING_t),
 	offsetof(OCTET_STRING_t, _asn_ctx),
 	ASN_OSUBV_STR
 };
-static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = {
+static const asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = {
 	{ APC_CONSTRAINED, 8, 8, 0, 255 },
 	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },
 	0, 0
@@ -36,6 +36,8 @@
 	OCTET_STRING_encode_xer,
 	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
 	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
+	OCTET_STRING_decode_aper,	/* Aligned PER decoder */
+	OCTET_STRING_encode_aper,	/* Aligned PER encoder */
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_OCTET_STRING_tags,
 	sizeof(asn_DEF_OCTET_STRING_tags)
@@ -580,7 +582,7 @@
 OCTET_STRING_encode_xer(asn_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 char * const h2c = "0123456789ABCDEF";
 	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
 	asn_enc_rval_t er;
 	char scratch[16 * 3 + 4];
@@ -639,8 +641,8 @@
 	_ASN_ENCODE_FAILED;
 }
 
-static struct OCTET_STRING__xer_escape_table_s {
-	char *string;
+static const struct OCTET_STRING__xer_escape_table_s {
+	const char *string;
 	int size;
 } OCTET_STRING__xer_escape_table[] = {
 #define	OSXET(s)	{ s, sizeof(s) - 1 }
@@ -702,7 +704,7 @@
 	 * nested table lookups).
 	 */
 	for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {
-		struct OCTET_STRING__xer_escape_table_s *el;
+		const struct OCTET_STRING__xer_escape_table_s *el;
 		el = &OCTET_STRING__xer_escape_table[i];
 		if(el->size == size && memcmp(buf, el->string, size) == 0)
 			return i;
@@ -1194,14 +1196,14 @@
 static int
 OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
 		size_t units, unsigned int bpc, unsigned int unit_bits,
-		long lb, long ub, asn_per_constraints_t *pc) {
+		int64_t lb, int64_t ub, asn_per_constraints_t *pc) {
 	uint8_t *end = buf + units * bpc;
 
-	ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d",
+	ASN_DEBUG("Expanding %d characters into (%lld..%lld):%d",
 		(int)units, lb, ub, unit_bits);
 
 	/* X.691: 27.5.4 */
-	if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {
+	if((uint64_t)ub <= ((uint64_t)2 << (unit_bits - 1))) {
 		/* Decode without translation */
 		lb = 0;
 	} else if(pc && pc->code2value) {
@@ -1216,7 +1218,7 @@
 			value = pc->code2value(code);
 			if(value < 0) {
 				ASN_DEBUG("Code %d (0x%02x) is"
-					" not in map (%ld..%ld)",
+					" not in map (%lld..%lld)",
 					code, code, lb, ub);
 				return 1;	/* FATAL */
 			}
@@ -1240,7 +1242,7 @@
 		int ch = code + lb;
 		if(code < 0) return -1;	/* WMORE */
 		if(ch > ub) {
-			ASN_DEBUG("Code %d is out of range (%ld..%ld)",
+			ASN_DEBUG("Code %d is out of range (%lld..%lld)",
 				ch, lb, ub);
 			return 1;	/* FATAL */
 		}
@@ -1258,14 +1260,14 @@
 static int
 OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf,
 		size_t units, unsigned int bpc, unsigned int unit_bits,
-		long lb, long ub, asn_per_constraints_t *pc) {
+		int64_t lb, int64_t ub, asn_per_constraints_t *pc) {
 	const uint8_t *end = buf + units * bpc;
 
-	ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)",
+	ASN_DEBUG("Squeezing %d characters into (%lld..%lld):%d (%d bpc)",
 		(int)units, lb, ub, unit_bits, bpc);
 
 	/* X.691: 27.5.4 */
-	if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {
+	if((uint64_t)ub <= ((uint64_t)2 << (unit_bits - 1))) {
 		/* Encode as is */
 		lb = 0;
 	} else if(pc && pc->value2code) {
@@ -1282,7 +1284,7 @@
 			code = pc->value2code(value);
 			if(code < 0) {
 				ASN_DEBUG("Character %d (0x%02x) is"
-					" not in map (%ld..%ld)",
+					" not in map (%lld..%lld)",
 					*buf, *buf, lb, ub);
 				return -1;
 			}
@@ -1309,7 +1311,7 @@
 		ch = value - lb;
 		if(ch < 0 || ch > ub) {
 			ASN_DEBUG("Character %d (0x%02x)"
-			" is out of range (%ld..%ld)",
+			" is out of range (%lld..%lld)",
 				*buf, *buf, lb, ub + lb);
 			return -1;
 		}
@@ -1392,7 +1394,7 @@
 		if(!st) RETURN(RC_FAIL);
 	}
 
-	ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",
+	ASN_DEBUG("PER Decoding %s size %lld .. %lld bits %d",
 		csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
 		csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);
 
@@ -1423,14 +1425,14 @@
 	if(csiz->effective_bits == 0) {
 		int ret;
 		if(bpc) {
-			ASN_DEBUG("Encoding OCTET STRING size %ld",
+			ASN_DEBUG("Encoding OCTET STRING size %lld",
 				csiz->upper_bound);
 			ret = OCTET_STRING_per_get_characters(pd, st->buf,
 				csiz->upper_bound, bpc, unit_bits,
 				cval->lower_bound, cval->upper_bound, pc);
 			if(ret > 0) RETURN(RC_FAIL);
 		} else {
-			ASN_DEBUG("Encoding BIT STRING size %ld",
+			ASN_DEBUG("Encoding BIT STRING size %lld",
 				csiz->upper_bound);
 			ret = per_get_many_bits(pd, st->buf, 0,
 					    unit_bits * csiz->upper_bound);
@@ -1492,6 +1494,194 @@
 	return rval;
 }
 
+asn_dec_rval_t
+OCTET_STRING_decode_aper(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
+	void **sptr, asn_per_data_t *pd) {
+
+	asn_OCTET_STRING_specifics_t *specs = td->specifics
+		? (asn_OCTET_STRING_specifics_t *)td->specifics
+		: &asn_DEF_OCTET_STRING_specs;
+	asn_per_constraints_t *pc = constraints ? constraints
+				: td->per_constraints;
+	asn_per_constraint_t *cval;
+	asn_per_constraint_t *csiz;
+	asn_dec_rval_t rval = { RC_OK, 0 };
+	BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
+	ssize_t consumed_myself = 0;
+	int repeat;
+	enum {
+		OS__BPC_BIT	= 0,
+		OS__BPC_CHAR	= 1,
+		OS__BPC_U16	= 2,
+		OS__BPC_U32	= 4
+	} bpc;	/* Bytes per character */
+	unsigned int unit_bits;
+	unsigned int canonical_unit_bits;
+
+	(void)opt_codec_ctx;
+
+	if(pc) {
+		cval = &pc->value;
+		csiz = &pc->size;
+	} else {
+		cval = &asn_DEF_OCTET_STRING_constraints.value;
+		csiz = &asn_DEF_OCTET_STRING_constraints.size;
+	}
+
+	switch(specs->subvariant) {
+	default:
+// 	case ASN_OSUBV_ANY:
+// 		ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant);
+// 		RETURN(RC_FAIL);
+	case ASN_OSUBV_BIT:
+		canonical_unit_bits = unit_bits = 1;
+		bpc = OS__BPC_BIT;
+		break;
+    case ASN_OSUBV_ANY:
+	case ASN_OSUBV_STR:
+		canonical_unit_bits = unit_bits = 8;
+// 		if(cval->flags & APC_CONSTRAINED)
+// 			unit_bits = cval->range_bits;
+		bpc = OS__BPC_CHAR;
+		break;
+	case ASN_OSUBV_U16:
+		canonical_unit_bits = unit_bits = 16;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U16;
+		break;
+	case ASN_OSUBV_U32:
+		canonical_unit_bits = unit_bits = 32;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U32;
+		break;
+	}
+
+	/*
+	 * Allocate the string.
+	 */
+	if(!st) {
+		st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+		if(!st) RETURN(RC_FAIL);
+	}
+
+	ASN_DEBUG("PER Decoding %s size %lld .. %lld bits %d",
+		csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
+		csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);
+
+	if(csiz->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) RETURN(RC_WMORE);
+		if(inext) {
+			csiz = &asn_DEF_OCTET_STRING_constraints.size;
+			cval = &asn_DEF_OCTET_STRING_constraints.value;
+			unit_bits = canonical_unit_bits;
+		}
+	}
+
+	if(csiz->effective_bits >= 0) {
+		FREEMEM(st->buf);
+		if(bpc) {
+			st->size = csiz->upper_bound * bpc;
+		} else {
+			st->size = (csiz->upper_bound + 7) >> 3;
+		}
+		st->buf = (uint8_t *)MALLOC(st->size + 1);
+		if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }
+	}
+
+	/* X.691, #16.5: zero-length encoding */
+	/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
+	/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
+	if(csiz->effective_bits == 0) {
+		int ret;
+		if (st->size > 2) { /* X.691 #16 NOTE 1 */
+			if (aper_get_align(pd) < 0)
+				RETURN(RC_FAIL);
+		}
+		if(bpc) {
+			ASN_DEBUG("Decoding OCTET STRING size %lld",
+				csiz->upper_bound);
+			ret = OCTET_STRING_per_get_characters(pd, st->buf,
+				csiz->upper_bound, bpc, unit_bits,
+				cval->lower_bound, cval->upper_bound, pc);
+			if(ret > 0) RETURN(RC_FAIL);
+		} else {
+			ASN_DEBUG("Decoding BIT STRING size %lld",
+				csiz->upper_bound);
+			ret = per_get_many_bits(pd, st->buf, 0,
+					    unit_bits * csiz->upper_bound);
+		}
+		if(ret < 0) RETURN(RC_WMORE);
+		consumed_myself += unit_bits * csiz->upper_bound;
+		st->buf[st->size] = 0;
+		if(bpc == 0) {
+			int ubs = (csiz->upper_bound & 0x7);
+			st->bits_unused = ubs ? 8 - ubs : 0;
+		}
+		RETURN(RC_OK);
+	}
+
+	st->size = 0;
+	do {
+		ssize_t raw_len;
+		ssize_t len_bytes;
+		ssize_t len_bits;
+		void *p;
+		int ret;
+
+		/* Get the PER length */
+		if (csiz->upper_bound - csiz->lower_bound == 0)
+			// Indefinite length case
+			raw_len = aper_get_length(pd, -1, csiz->effective_bits, &repeat);
+		else
+			raw_len = aper_get_length(pd, csiz->upper_bound - csiz->lower_bound + 1, csiz->effective_bits, &repeat);
+		repeat = 0;
+		if(raw_len < 0) RETURN(RC_WMORE);
+		raw_len += csiz->lower_bound;
+
+		ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
+			(long)csiz->effective_bits, (long)raw_len,
+			repeat ? "repeat" : "once", td->name);
+
+		if (raw_len > 2) { /* X.691 #16 NOTE 1 */
+			if (aper_get_align(pd) < 0)
+				RETURN(RC_FAIL);
+		}
+
+		if(bpc) {
+			len_bytes = raw_len * bpc;
+			len_bits = len_bytes * unit_bits;
+		} else {
+			len_bits = raw_len;
+			len_bytes = (len_bits + 7) >> 3;
+			if(len_bits & 0x7)
+				st->bits_unused = 8 - (len_bits & 0x7);
+			/* len_bits be multiple of 16K if repeat is set */
+		}
+		p = REALLOC(st->buf, st->size + len_bytes + 1);
+		if(!p) RETURN(RC_FAIL);
+		st->buf = (uint8_t *)p;
+
+		if(bpc) {
+			ret = OCTET_STRING_per_get_characters(pd,
+				&st->buf[st->size], raw_len, bpc, unit_bits,
+				cval->lower_bound, cval->upper_bound, pc);
+			if(ret > 0) RETURN(RC_FAIL);
+		} else {
+			ret = per_get_many_bits(pd, &st->buf[st->size],
+				0, len_bits);
+		}
+		if(ret < 0) RETURN(RC_WMORE);
+		st->size += len_bytes;
+	} while(repeat);
+	st->buf[st->size] = 0;	/* nul-terminate */
+
+	return rval;
+}
+
 asn_enc_rval_t
 OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
         asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
@@ -1566,12 +1756,12 @@
 	}
 
 	ASN_DEBUG("Encoding %s into %d units of %d bits"
-		" (%ld..%ld, effective %d)%s",
+		" (%lld..%lld, effective %d)%s",
 		td->name, sizeinunits, unit_bits,
 		csiz->lower_bound, csiz->upper_bound,
 		csiz->effective_bits, ct_extensible ? " EXT" : "");
 
-	/* Figure out wheter size lies within PER visible constraint */
+	/* Figure out whether size lies within PER visible constraint */
 
 	if(csiz->effective_bits >= 0) {
 		if((int)sizeinunits < csiz->lower_bound
@@ -1598,7 +1788,7 @@
 	/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
 	/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
 	if(csiz->effective_bits >= 0) {
-		ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits",
+		ASN_DEBUG("Encoding %d bytes (%lld), length in %d bits",
 				st->size, sizeinunits - csiz->lower_bound,
 				csiz->effective_bits);
 		ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound,
@@ -1652,10 +1842,177 @@
 	_ASN_ENCODED_OK(er);
 }
 
+asn_enc_rval_t
+OCTET_STRING_encode_aper(asn_TYPE_descriptor_t *td,
+        asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+
+        asn_OCTET_STRING_specifics_t *specs = td->specifics
+                ? (asn_OCTET_STRING_specifics_t *)td->specifics
+                : &asn_DEF_OCTET_STRING_specs;
+        asn_per_constraints_t *pc = constraints ? constraints
+                                : td->per_constraints;
+        asn_per_constraint_t *cval;
+        asn_per_constraint_t *csiz;
+        const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+        asn_enc_rval_t er = { 0, 0, 0 };
+        int inext = 0;          /* Lies not within extension root */
+        unsigned int unit_bits;
+        unsigned int canonical_unit_bits;
+        unsigned int sizeinunits;
+        const uint8_t *buf;
+        int ret;
+        enum {
+                OS__BPC_BIT     = 0,
+                OS__BPC_CHAR    = 1,
+                OS__BPC_U16     = 2,
+                OS__BPC_U32     = 4
+        } bpc;  /* Bytes per character */
+        int ct_extensible;
+
+        if(!st || (!st->buf && st->size))
+                _ASN_ENCODE_FAILED;
+
+        if(pc) {
+                cval = &pc->value;
+                csiz = &pc->size;
+        } else {
+                cval = &asn_DEF_OCTET_STRING_constraints.value;
+                csiz = &asn_DEF_OCTET_STRING_constraints.size;
+        }
+        ct_extensible = csiz->flags & APC_EXTENSIBLE;
+
+        switch(specs->subvariant) {
+        default:
+//         case ASN_OSUBV_ANY:
+//                 _ASN_ENCODE_FAILED;
+        case ASN_OSUBV_BIT:
+                canonical_unit_bits = unit_bits = 1;
+                bpc = OS__BPC_BIT;
+                sizeinunits = st->size * 8 - (st->bits_unused & 0x07);
+                ASN_DEBUG("BIT STRING of %d bytes",
+                                sizeinunits);
+		break;
+        case ASN_OSUBV_ANY:
+	case ASN_OSUBV_STR:
+		canonical_unit_bits = unit_bits = 8;
+// 		if(cval->flags & APC_CONSTRAINED)
+// 			unit_bits = 8;
+		bpc = OS__BPC_CHAR;
+		sizeinunits = st->size;
+		break;
+	case ASN_OSUBV_U16:
+		canonical_unit_bits = unit_bits = 16;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U16;
+		sizeinunits = st->size / 2;
+		break;
+	case ASN_OSUBV_U32:
+		canonical_unit_bits = unit_bits = 32;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U32;
+		sizeinunits = st->size / 4;
+		break;
+	}
+
+	ASN_DEBUG("Encoding %s into %d units of %d bits"
+		" (%lld..%lld, effective %d)%s",
+		td->name, sizeinunits, unit_bits,
+		csiz->lower_bound, csiz->upper_bound,
+		csiz->effective_bits, ct_extensible ? " EXT" : "");
+
+	/* Figure out wheter size lies within PER visible constraint */
+
+	if(csiz->effective_bits >= 0) {
+		if((int)sizeinunits < csiz->lower_bound
+		|| (int)sizeinunits > csiz->upper_bound) {
+			if(ct_extensible) {
+				cval = &asn_DEF_OCTET_STRING_constraints.value;
+				csiz = &asn_DEF_OCTET_STRING_constraints.size;
+				unit_bits = canonical_unit_bits;
+				inext = 1;
+			} else
+				_ASN_ENCODE_FAILED;
+		}
+	} else {
+		inext = 0;
+	}
+
+
+	if(ct_extensible) {
+		/* Declare whether length is [not] within extension root */
+		if(per_put_few_bits(po, inext, 1))
+			_ASN_ENCODE_FAILED;
+	}
+
+	/* X.691, #16.5: zero-length encoding */
+	/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
+	/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
+	if(csiz->effective_bits >= 0) {
+		ASN_DEBUG("Encoding %d bytes (%lld), length in %d bits",
+				st->size, sizeinunits - csiz->lower_bound,
+				csiz->effective_bits);
+		ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound,
+				csiz->effective_bits);
+		if(ret) _ASN_ENCODE_FAILED;
+		if (st->size > 2) { /* X.691 #16 NOTE 1 */
+			if (aper_put_align(po) < 0)
+				_ASN_ENCODE_FAILED;
+		}
+		if(bpc) {
+			ret = OCTET_STRING_per_put_characters(po, st->buf,
+				sizeinunits, bpc, unit_bits,
+				cval->lower_bound, cval->upper_bound, pc);
+		} else {
+			ret = per_put_many_bits(po, st->buf,
+				sizeinunits * unit_bits);
+		}
+		if(ret) _ASN_ENCODE_FAILED;
+		_ASN_ENCODED_OK(er);
+	}
+
+	ASN_DEBUG("Encoding %d bytes", st->size);
+
+	if(sizeinunits == 0) {
+		if(aper_put_length(po, -1, 0))
+			_ASN_ENCODE_FAILED;
+		_ASN_ENCODED_OK(er);
+	}
+
+	buf = st->buf;
+	while(sizeinunits) {
+		ssize_t maySave = aper_put_length(po, -1, sizeinunits);
+
+		if(maySave < 0) _ASN_ENCODE_FAILED;
+
+		ASN_DEBUG("Encoding %ld of %ld",
+			(long)maySave, (long)sizeinunits);
+
+		if(bpc) {
+			ret = OCTET_STRING_per_put_characters(po, buf,
+				maySave, bpc, unit_bits,
+				cval->lower_bound, cval->upper_bound, pc);
+		} else {
+			ret = per_put_many_bits(po, buf, maySave * unit_bits);
+		}
+		if(ret) _ASN_ENCODE_FAILED;
+
+		if(bpc)
+			buf += maySave * bpc;
+		else
+			buf += maySave >> 3;
+		sizeinunits -= maySave;
+		assert(!(maySave & 0x07) || !sizeinunits);
+	}
+
+	_ASN_ENCODED_OK(er);
+}
+
 int
 OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	static const char *h2c = "0123456789ABCDEF";
+	const char * const h2c = "0123456789ABCDEF";
 	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
 	char scratch[16 * 3 + 4];
 	char *p = scratch;
diff --git a/src/ObjectDescriptor.c b/src/ObjectDescriptor.c
index cd8e8a3..f049c1c 100644
--- a/src/ObjectDescriptor.c
+++ b/src/ObjectDescriptor.c
@@ -8,7 +8,7 @@
 /*
  * ObjectDescriptor basic type description.
  */
-static ber_tlv_tag_t asn_DEF_ObjectDescriptor_tags[] = {
+static const ber_tlv_tag_t asn_DEF_ObjectDescriptor_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (7 << 2)),	/* [UNIVERSAL 7] IMPLICIT ... */
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -24,6 +24,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_ObjectDescriptor_tags,
 	sizeof(asn_DEF_ObjectDescriptor_tags)
diff --git a/src/PrintableString.c b/src/PrintableString.c
index c8ee3ae..3058d09 100644
--- a/src/PrintableString.c
+++ b/src/PrintableString.c
@@ -9,7 +9,7 @@
 /*
  * ASN.1:1984 (X.409)
  */
-static int _PrintableString_alphabet[256] = {
+static const int _PrintableString_alphabet[256] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*                  */
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*                  */
  1, 0, 0, 0, 0, 0, 0, 2, 3, 4, 0, 5, 6, 7, 8, 9,	/* .      '() +,-./ */
@@ -19,7 +19,7 @@
  0,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,	/*  abcdefghijklmno */
 64,65,66,67,68,69,70,71,72,73,74, 0, 0, 0, 0, 0,	/* pqrstuvwxyz      */
 };
-static int _PrintableString_code2value[74] = { 
+static const int _PrintableString_code2value[74] = {
 32,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,
 55,56,57,58,61,63,65,66,67,68,69,70,71,72,73,74,
 75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,
@@ -29,7 +29,7 @@
 /*
  * PrintableString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_PrintableString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_PrintableString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (19 << 2)),	/* [UNIVERSAL 19] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -41,7 +41,7 @@
 		return _PrintableString_code2value[code];
 	return -1;
 }
-static asn_per_constraints_t asn_DEF_PrintableString_constraints = {
+static const asn_per_constraints_t asn_DEF_PrintableString_constraints = {
 	{ APC_CONSTRAINED, 4, 4, 0x20, 0x39 },	/* Value */
 	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },	/* Size */
 	asn_DEF_PrintableString_v2c,
@@ -59,6 +59,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_PrintableString_tags,
 	sizeof(asn_DEF_PrintableString_tags)
diff --git a/src/REAL.c b/src/REAL.c
index 5e93ac8..e179152 100644
--- a/src/REAL.c
+++ b/src/REAL.c
@@ -1,10 +1,10 @@
 /*-
- * Copyright (c) 2004, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2004-2013 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
-#if	defined(__alpha)
-#define	_ISOC99_SOURCE		/* For quiet NAN, through bits/nan.h */
+#define	_ISOC99_SOURCE		/* For ilogb() and quiet NAN */
 #define	_BSD_SOURCE		/* To reintroduce finite(3) */
+#if	defined(__alpha)
 #include <sys/resource.h>	/* For INFINITY */
 #endif
 #include <asn_internal.h>
@@ -27,10 +27,16 @@
 #define	INFINITY	(1.0/real_zero)
 #endif
 
+#ifdef isfinite
+#define _asn_isfinite(d)   isfinite(d)  /* ISO C99 */
+#else
+#define _asn_isfinite(d)   finite(d)    /* Deprecated on Mac OS X 10.9 */
+#endif
+
 /*
  * REAL basic type description.
  */
-static ber_tlv_tag_t asn_DEF_REAL_tags[] = {
+static const ber_tlv_tag_t asn_DEF_REAL_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (9 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_REAL = {
@@ -45,6 +51,8 @@
 	REAL_encode_xer,
 	REAL_decode_uper,
 	REAL_encode_uper,
+	REAL_decode_aper,
+	REAL_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_REAL_tags,
 	sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]),
@@ -88,7 +96,7 @@
 		buf = specialRealValue[SRV__NOT_A_NUMBER].string;
 		buflen = specialRealValue[SRV__NOT_A_NUMBER].length;
 		return (cb(buf, buflen, app_key) < 0) ? -1 : buflen;
-	} else if(!finite(d)) {
+	} else if(!_asn_isfinite(d)) {
 		if(copysign(1.0, d) < 0.0) {
 			buf = specialRealValue[SRV__MINUS_INFINITY].string;
 			buflen = specialRealValue[SRV__MINUS_INFINITY].length;
@@ -137,6 +145,7 @@
 
 		dot = (buf[0] == 0x2d /* '-' */) ? (buf + 2) : (buf + 1);
 		if(*dot >= 0x30) {
+			if(buf != local_buf) FREEMEM(buf);
 			errno = EINVAL;
 			return -1;	/* Not a dot, really */
 		}
@@ -157,6 +166,7 @@
 				}
 				expptr++;
 				if(expptr > end) {
+					if(buf != local_buf) FREEMEM(buf);
 					errno = EINVAL;
 					return -1;
 				}
@@ -182,6 +192,7 @@
 			}
 		}
 		if(E == end) {
+			if(buf != local_buf) FREEMEM(buf);
 			errno = EINVAL;
 			return -1;		/* No promised E */
 		}
@@ -358,6 +369,21 @@
 	return OCTET_STRING_encode_uper(td, 0, sptr, po);
 }
 
+asn_dec_rval_t
+REAL_decode_aper(asn_codec_ctx_t *opt_codec_ctx,
+	asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
+	void **sptr, asn_per_data_t *pd) {
+	(void)constraints;	/* No PER visible constraints */
+	return OCTET_STRING_decode_aper(opt_codec_ctx, td, 0, sptr, pd);
+}
+
+asn_enc_rval_t
+REAL_encode_aper(asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	(void)constraints;	/* No PER visible constraints */
+	return OCTET_STRING_encode_aper(td, 0, sptr, po);
+}
+
 int
 asn_REAL2double(const REAL_t *st, double *dbl_value) {
 	unsigned int octv;
@@ -375,10 +401,11 @@
 	octv = st->buf[0];	/* unsigned byte */
 
 	switch(octv & 0xC0) {
-	case 0x40:	/* X.690: 8.5.8 */
+	case 0x40:	/* X.690: 8.5.6 a) => 8.5.9 */
 		/* "SpecialRealValue" */
 
 		/* Be liberal in what you accept...
+		 * http://en.wikipedia.org/wiki/Robustness_principle
 		if(st->size != 1) ...
 		*/
 
@@ -389,10 +416,6 @@
 		case 0x41:	/* 01000001: MINUS-INFINITY */
 			*dbl_value = - INFINITY;
 			return 0;
-			/*
-			 * The following cases are defined by
-			 * X.690 Amendment 1 (10/03)
-			 */
 		case 0x42:	/* 01000010: NOT-A-NUMBER */
 			*dbl_value = NAN;
 			return 0;
@@ -403,21 +426,67 @@
 
 		errno = EINVAL;
 		return -1;
-	case 0x00: {	/* X.690: 8.5.6 */
+	case 0x00: {	/* X.690: 8.5.7 */
 		/*
-		 * Decimal. NR{1,2,3} format.
+		 * Decimal. NR{1,2,3} format from ISO 6093.
+		 * NR1: [ ]*[+-]?[0-9]+
+		 * NR2: [ ]*[+-]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)
+		 * NR3: [ ]*[+-]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)[Ee][+-]?[0-9]+
 		 */
 		double d;
+		char *buf;
+		char *endptr;
+		int used_malloc = 0;
 
-		assert(st->buf[st->size - 1] == 0); /* Security, vashu mat' */
+		if(octv == 0 || (octv & 0x3C)) {
+			/* Remaining values of bits 6 to 1 are Reserved. */
+			errno = EINVAL;
+			return -1;
+		}
 
-		d = strtod((char *)st->buf, 0);
-		if(finite(d)) {
+
+		/* 1. By contract, an input buffer should be null-terminated.
+		 * OCTET STRING decoder ensures that, as is asn_double2REAL().
+		 * 2. ISO 6093 specifies COMMA as a possible decimal separator.
+		 * However, strtod() can't always deal with COMMA.
+		 * So her we fix both by reallocating, copying and fixing.
+		 */
+		if(st->buf[st->size] || memchr(st->buf, ',', st->size)) {
+			uint8_t *p, *end;
+			char *b;
+			if(st->size > 100) {
+				/* Avoid malicious stack overflow in alloca() */
+				buf = (char *)MALLOC(st->size);
+				if(!buf) return -1;
+				used_malloc = 1;
+			} else {
+				buf = alloca(st->size);
+			}
+			b = buf;
+			/* Copy without the first byte and with 0-termination */
+			for(p = st->buf + 1, end = st->buf + st->size;
+					p < end; b++, p++)
+				*b = (*p == ',') ? '.' : *p;
+			*b = '\0';
+		} else {
+			buf = (char *)&st->buf[1];
+		}
+
+		endptr = buf;
+		d = strtod(buf, &endptr);
+		if(*endptr != '\0') {
+			/* Format is not consistent with ISO 6093 */
+			if(used_malloc) FREEMEM(buf);
+			errno = EINVAL;
+			return -1;
+		}
+		if(used_malloc) FREEMEM(buf);
+		if(_asn_isfinite(d)) {
 			*dbl_value = d;
 			return 0;
 		} else {
 			errno = ERANGE;
-			return 0;
+			return -1;
 		}
 	  }
 	}
@@ -476,13 +545,11 @@
 
 	/* Okay, the exponent is here. Now, what about mantissa? */
 	end = st->buf + st->size;
-	if(ptr < end) {
-		for(; ptr < end; ptr++)
-			m = ldexp(m, 8) + *ptr;
-	}
+	for(; ptr < end; ptr++)
+		m = ldexp(m, 8) + *ptr;
 
 	if(0)
-	ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f",
+	ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f\n",
 		m, scaleF, baseF, expval,
 		ldexp(m, expval * baseF + scaleF),
 		ldexp(m, scaleF) * pow(pow(2, baseF), expval)
@@ -494,7 +561,7 @@
 	m = ldexp(m, scaleF) * pow(pow(2, base), expval);
 	 */
 	m = ldexp(m, expval * baseF + scaleF);
-	if(finite(m)) {
+	if(_asn_isfinite(m)) {
 		*dbl_value = sign ? -m : m;
 	} else {
 		errno = ERANGE;
@@ -555,7 +622,7 @@
 			st->buf[0] = 0x42;	/* NaN */
 			st->buf[1] = 0;
 			st->size = 1;
-		} else if(!finite(dbl_value)) {
+		} else if(!_asn_isfinite(dbl_value)) {
 			if(copysign(1.0, dbl_value) < 0.0) {
 				st->buf[0] = 0x41;	/* MINUS-INFINITY */
 			} else {
@@ -564,14 +631,14 @@
 			st->buf[1] = 0;
 			st->size = 1;
 		} else {
-			if(copysign(1.0, dbl_value) < 0.0) {
-				st->buf[0] = 0x80 | 0x40;
-				st->buf[1] = 0;
-				st->size = 2;
-			} else {
+			if(copysign(1.0, dbl_value) >= 0.0) {
 				/* no content octets: positive zero */
 				st->buf[0] = 0;	/* JIC */
 				st->size = 0;
+			} else {
+				/* Negative zero. #8.5.3, 8.5.9 */
+				st->buf[0] = 0x43;
+				st->size = 1;
 			}
 		}
 		return 0;
@@ -630,7 +697,7 @@
 			accum = mval << ishift;
 		}
 
-		/* Adjust mantissa appropriately. */
+		/* Adjust exponent appropriately. */
 		expval += shift_count;
 	}
 
diff --git a/src/RELATIVE-OID.c b/src/RELATIVE-OID.c
index 983fc09..8e3e97f 100644
--- a/src/RELATIVE-OID.c
+++ b/src/RELATIVE-OID.c
@@ -13,7 +13,7 @@
 /*
  * RELATIVE-OID basic type description.
  */
-static ber_tlv_tag_t asn_DEF_RELATIVE_OID_tags[] = {
+static const ber_tlv_tag_t asn_DEF_RELATIVE_OID_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (13 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = {
@@ -28,6 +28,8 @@
 	RELATIVE_OID_encode_xer,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_RELATIVE_OID_tags,
 	sizeof(asn_DEF_RELATIVE_OID_tags)
@@ -106,14 +108,12 @@
 		(const char *)chunk_buf, chunk_size,
 		arcs, sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
 	if(arcs_count < 0) {
-		/* Expecting at least zero arcs */
+		/* Expecting at least one arc arcs */
 		return XPBD_BROKEN_ENCODING;
+	} else if(arcs_count == 0) {
+		return XPBD_NOT_BODY_IGNORE;
 	}
-	if(endptr < chunk_end) {
-		/* We have a tail of unrecognized data. Check its safety. */
-		if(!xer_is_whitespace(endptr, chunk_end - endptr))
-			return XPBD_BROKEN_ENCODING;
-	}
+	assert(endptr == chunk_end);
 
 	if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
 		arcs = (long *)MALLOC(arcs_count * sizeof(long));
@@ -164,7 +164,7 @@
 }
 
 int
-RELATIVE_OID_get_arcs(RELATIVE_OID_t *roid,
+RELATIVE_OID_get_arcs(const RELATIVE_OID_t *roid,
 	void *arcs, unsigned int arc_type_size, unsigned int arc_slots) {
 	void *arcs_end = (char *)arcs + (arc_slots * arc_type_size);
 	int num_arcs = 0;
diff --git a/src/T61String.c b/src/T61String.c
index 98461bb..4a6ad47 100644
--- a/src/T61String.c
+++ b/src/T61String.c
@@ -8,7 +8,7 @@
 /*
  * T61String basic type description.
  */
-static ber_tlv_tag_t asn_DEF_T61String_tags[] = {
+static const ber_tlv_tag_t asn_DEF_T61String_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (20 << 2)),	/* [UNIVERSAL 20] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -24,6 +24,8 @@
 	OCTET_STRING_encode_xer,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_T61String_tags,
 	sizeof(asn_DEF_T61String_tags)
diff --git a/src/TeletexString.c b/src/TeletexString.c
index cc2acad..40b5c4e 100644
--- a/src/TeletexString.c
+++ b/src/TeletexString.c
@@ -8,7 +8,7 @@
 /*
  * TeletexString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_TeletexString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_TeletexString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (20 << 2)),	/* [UNIVERSAL 20] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2)),	/* ... OCTET STRING */
 };
@@ -24,6 +24,8 @@
 	OCTET_STRING_encode_xer,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_TeletexString_tags,
 	sizeof(asn_DEF_TeletexString_tags)
diff --git a/src/UTCTime.c b/src/UTCTime.c
index 0abe1db..98a4c15 100644
--- a/src/UTCTime.c
+++ b/src/UTCTime.c
@@ -18,7 +18,7 @@
 /*
  * UTCTime basic type description.
  */
-static ber_tlv_tag_t asn_DEF_UTCTime_tags[] = {
+static const ber_tlv_tag_t asn_DEF_UTCTime_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (23 << 2)),	/* [UNIVERSAL 23] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),  /* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))    /* ... OCTET STRING */
@@ -40,6 +40,8 @@
 	UTCTime_encode_xer,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UTCTime_tags,
 	sizeof(asn_DEF_UTCTime_tags)
diff --git a/src/UTF8String.c b/src/UTF8String.c
index 7e73d77..4103af3 100644
--- a/src/UTF8String.c
+++ b/src/UTF8String.c
@@ -9,7 +9,7 @@
 /*
  * UTF8String basic type description.
  */
-static ber_tlv_tag_t asn_DEF_UTF8String_tags[] = {
+static const ber_tlv_tag_t asn_DEF_UTF8String_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (12 << 2)),	/* [UNIVERSAL 12] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2)),	/* ... OCTET STRING */
 };
@@ -25,6 +25,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UTF8String_tags,
 	sizeof(asn_DEF_UTF8String_tags)
@@ -41,7 +43,7 @@
  * This is the table of length expectations.
  * The second half of this table is only applicable to the long sequences.
  */
-static int UTF8String_ht[2][16] = {
+static const int UTF8String_ht[2][16] = {
 	{ /* 0x0 ... 0x7 */
 	  /* 0000..0111 */
 	  1, 1, 1, 1, 1, 1, 1, 1,
@@ -52,7 +54,7 @@
 	  4, 4, 4, 4, 4, 4, 4, 4,
 	  5, 5, 5, 5, 6, 6, -1, -1 }
 };
-static int32_t UTF8String_mv[7] = { 0, 0,
+static const int32_t UTF8String_mv[7] = { 0, 0,
 	0x00000080,
 	0x00000800,
 	0x00010000,
diff --git a/src/UniversalString.c b/src/UniversalString.c
index 7d16781..0cffce5 100644
--- a/src/UniversalString.c
+++ b/src/UniversalString.c
@@ -9,7 +9,7 @@
 /*
  * UniversalString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_UniversalString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_UniversalString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (28 << 2)),	/* [UNIVERSAL 28] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -35,6 +35,8 @@
 	UniversalString_encode_xer,	/* Convert into UTF-8 */
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UniversalString_tags,
 	sizeof(asn_DEF_UniversalString_tags)
diff --git a/src/VideotexString.c b/src/VideotexString.c
index df7233e..e6fc423 100644
--- a/src/VideotexString.c
+++ b/src/VideotexString.c
@@ -8,7 +8,7 @@
 /*
  * VideotexString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_VideotexString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_VideotexString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (21 << 2)),	/* [UNIVERSAL 21] IMPLICIT */
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -24,6 +24,8 @@
 	OCTET_STRING_encode_xer,
 	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_VideotexString_tags,
 	sizeof(asn_DEF_VideotexString_tags)
diff --git a/src/VisibleString.c b/src/VisibleString.c
index 3487b6f..20d1b21 100644
--- a/src/VisibleString.c
+++ b/src/VisibleString.c
@@ -8,7 +8,7 @@
 /*
  * VisibleString basic type description.
  */
-static ber_tlv_tag_t asn_DEF_VisibleString_tags[] = {
+static const ber_tlv_tag_t asn_DEF_VisibleString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),	/* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
@@ -29,6 +29,8 @@
 	OCTET_STRING_encode_xer_utf8,
 	OCTET_STRING_decode_uper,
 	OCTET_STRING_encode_uper,
+	OCTET_STRING_decode_aper,
+	OCTET_STRING_encode_aper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_VisibleString_tags,
 	sizeof(asn_DEF_VisibleString_tags)
diff --git a/src/asn_codecs_prim.c b/src/asn_codecs_prim.c
index a9bc10d..8e604a4 100644
--- a/src/asn_codecs_prim.c
+++ b/src/asn_codecs_prim.c
@@ -6,8 +6,6 @@
 #include <asn_codecs_prim.h>
 #include <errno.h>
 
-void *talloc_asn1_ctx;
-
 /*
  * Decode an always-primitive type.
  */
@@ -17,7 +15,7 @@
 	void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
 	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
 	asn_dec_rval_t rval;
-	ber_tlv_len_t length;
+	ber_tlv_len_t length = 0; // =0 to avoid [incorrect] warning.
 
 	/*
 	 * If the structure is not there, allocate it.
@@ -145,20 +143,26 @@
 	int want_more;
 };
 
-
+/*
+ * Since some kinds of primitive values can be encoded using value-specific
+ * tags (<MINUS-INFINITY>, <enum-element>, etc), the primitive decoder must
+ * be supplied with such tags to parse them as needed.
+ */
 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;
 	enum xer_pbd_rval bret;
 
-	if(arg->decoded_something) {
-		if(xer_is_whitespace(chunk_buf, chunk_size))
-			return 0;	/* Skip it. */
-		/*
-		 * Decoding was done once already. Prohibit doing it again.
-		 */
+	/*
+	 * The chunk_buf is guaranteed to start at '<'.
+	 */
+	assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c);
+
+	/*
+	 * Decoding was performed once already. Prohibit doing it again.
+	 */
+	if(arg->decoded_something)
 		return -1;
-	}
 
 	bret = arg->prim_body_decoder(arg->type_descriptor,
 		arg->struct_key, chunk_buf, chunk_size);
@@ -179,13 +183,20 @@
 }
 
 static ssize_t
-xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
+xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
 	enum xer_pbd_rval bret;
+	size_t lead_wsp_size;
 
 	if(arg->decoded_something) {
-		if(xer_is_whitespace(chunk_buf, chunk_size))
+		if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
+			/*
+			 * Example:
+			 * "<INTEGER>123<!--/--> </INTEGER>"
+			 *                      ^- chunk_buf position.
+			 */
 			return chunk_size;
+		}
 		/*
 		 * Decoding was done once already. Prohibit doing it again.
 		 */
@@ -205,6 +216,10 @@
 		return -1;
 	}
 
+	lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
+	chunk_buf = (const char *)chunk_buf + lead_wsp_size;
+	chunk_size -= lead_wsp_size;
+
 	bret = arg->prim_body_decoder(arg->type_descriptor,
 		arg->struct_key, chunk_buf, chunk_size);
 	switch(bret) {
@@ -217,7 +232,7 @@
 		arg->decoded_something = 1;
 		/* Fall through */
 	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
-		return chunk_size;
+		return lead_wsp_size + chunk_size;
 	}
 
 	return -1;
@@ -255,7 +270,7 @@
 
 	rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
 		xml_tag, buf_ptr, size,
-		xer_decode__unexpected_tag, xer_decode__body);
+		xer_decode__unexpected_tag, xer_decode__primitive_body);
 	switch(rc.code) {
 	case RC_OK:
 		if(!s_arg.decoded_something) {
diff --git a/src/ber_decoder.c b/src/ber_decoder.c
index 601f66c..0f99400 100644
--- a/src/ber_decoder.c
+++ b/src/ber_decoder.c
@@ -206,7 +206,7 @@
 		 */
 		len_len = ber_fetch_length(tlv_constr,
 			(const char *)ptr + tag_len, size - tag_len, &tlv_len);
-		ASN_DEBUG("Fetchinig len = %ld", (long)len_len);
+		ASN_DEBUG("Fetching len = %ld", (long)len_len);
 		switch(len_len) {
 		case -1: RETURN(RC_FAIL);
 		case 0: RETURN(RC_WMORE);
diff --git a/src/constr_CHOICE.c b/src/constr_CHOICE.c
index 4f0d992..18c24cd 100644
--- a/src/constr_CHOICE.c
+++ b/src/constr_CHOICE.c
@@ -183,11 +183,11 @@
 		}
 
 		do {
-			asn_TYPE_tag2member_t *t2m;
+			const asn_TYPE_tag2member_t *t2m;
 			asn_TYPE_tag2member_t key;
 
 			key.el_tag = tlv_tag;
-			t2m = (asn_TYPE_tag2member_t *)bsearch(&key,
+			t2m = (const asn_TYPE_tag2member_t *)bsearch(&key,
 					specs->tag2el, specs->tag2el_count,
 					sizeof(specs->tag2el[0]), _search4tag);
 			if(t2m) {
@@ -445,7 +445,7 @@
 }
 
 ber_tlv_tag_t
-CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
+CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
 	asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 	int present;
 
@@ -458,7 +458,7 @@
 	present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
 
 	if(present > 0 || present <= td->elements_count) {
-		asn_TYPE_member_t *elm = &td->elements[present-1];
+		const asn_TYPE_member_t *elm = &td->elements[present-1];
 		const void *memb_ptr;
 
 		if(elm->flags & ATF_POINTER) {
@@ -535,7 +535,7 @@
 #undef	XER_ADVANCE
 #define	XER_ADVANCE(num_bytes)	do {			\
 		size_t num = num_bytes;			\
-		buf_ptr = ((const char *)buf_ptr) + num;\
+		buf_ptr = (const void *)(((const char *)buf_ptr) + num); \
 		size -= num;				\
 		consumed_myself += num;			\
 	} while(0)
@@ -904,7 +904,88 @@
 			elm->name, td->name, rv.code);
 	return rv;
 }
-   
+
+asn_dec_rval_t
+CHOICE_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
+	asn_dec_rval_t rv;
+	asn_per_constraint_t *ct;
+	asn_TYPE_member_t *elm;	/* CHOICE's element */
+	void *memb_ptr;
+	void **memb_ptr2;
+	void *st = *sptr;
+	int value;
+
+	if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
+		_ASN_DECODE_FAILED;
+
+	/*
+	 * Create the target structure if it is not present already.
+	 */
+	if(!st) {
+		st = *sptr = CALLOC(1, specs->struct_size);
+		if(!st) _ASN_DECODE_FAILED;
+	}
+
+	if(constraints) ct = &constraints->value;
+	else if(td->per_constraints) ct = &td->per_constraints->value;
+	else ct = 0;
+
+	if(ct && ct->flags & APC_EXTENSIBLE) {
+		value = per_get_few_bits(pd, 1);
+		if(value < 0) _ASN_DECODE_STARVED;
+		if(value) ct = 0;	/* Not restricted */
+	}
+
+	if(ct && ct->range_bits >= 0) {
+		value = per_get_few_bits(pd, ct->range_bits);
+		if(value < 0) _ASN_DECODE_STARVED;
+		ASN_DEBUG("CHOICE %s got index %d in range %d",
+			td->name, value, ct->range_bits);
+		if(value > ct->upper_bound)
+			_ASN_DECODE_FAILED;
+	} else {
+		if(specs->ext_start == -1)
+			_ASN_DECODE_FAILED;
+		value = uper_get_nsnnwn(pd);
+		if(value < 0) _ASN_DECODE_STARVED;
+		value += specs->ext_start;
+		if(value >= td->elements_count)
+			_ASN_DECODE_FAILED;
+	}
+
+	/* Adjust if canonical order is different from natural order */
+	if(specs->canonical_order)
+		value = specs->canonical_order[value];
+
+	/* Set presence to be able to free it later */
+	_set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1);
+
+	elm = &td->elements[value];
+	if(elm->flags & ATF_POINTER) {
+		/* Member is a pointer to another structure */
+		memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+	} else {
+		memb_ptr = (char *)st + elm->memb_offset;
+		memb_ptr2 = &memb_ptr;
+	}
+	ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
+
+	if(ct && ct->range_bits >= 0) {
+		rv = elm->type->aper_decoder(opt_codec_ctx, elm->type,
+			elm->per_constraints, memb_ptr2, pd);
+	} else {
+		rv = uper_open_type_get(opt_codec_ctx, elm->type,
+			elm->per_constraints, memb_ptr2, pd);
+	}
+
+	if(rv.code != RC_OK)
+		ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d",
+			elm->name, td->name, rv.code);
+	return rv;
+}
+
 asn_enc_rval_t
 CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
@@ -913,10 +994,11 @@
 	asn_per_constraint_t *ct;
 	void *memb_ptr;
 	int present;
+	int present_enc;
 
 	if(!sptr) _ASN_ENCODE_FAILED;
 
-	ASN_DEBUG("Encoding %s as CHOICE", td->name);
+        ASN_DEBUG("Encoding %s as CHOICE using UPER", td->name);
 
 	if(constraints) ct = &constraints->value;
 	else if(td->per_constraints) ct = &td->per_constraints->value;
@@ -934,15 +1016,17 @@
 	else
 		present--;
 
-	/* Adjust if canonical order is different from natural order */
-	if(specs->canonical_order)
-		present = specs->canonical_order[present];
-
 	ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
 
+	/* Adjust if canonical order is different from natural order */
+	if(specs->canonical_order)
+		present_enc = specs->canonical_order[present];
+	else
+		present_enc = present;
+
 	if(ct && ct->range_bits >= 0) {
-		if(present < ct->lower_bound
-		|| present > ct->upper_bound) {
+		if(present_enc < ct->lower_bound
+		|| present_enc > ct->upper_bound) {
 			if(ct->flags & APC_EXTENSIBLE) {
 				if(per_put_few_bits(po, 1, 1))
 					_ASN_ENCODE_FAILED;
@@ -966,7 +1050,7 @@
 	}
 
 	if(ct && ct->range_bits >= 0) {
-		if(per_put_few_bits(po, present, ct->range_bits))
+		if(per_put_few_bits(po, present_enc, ct->range_bits))
 			_ASN_ENCODE_FAILED;
 
 		return elm->type->uper_encoder(elm->type, elm->per_constraints,
@@ -975,7 +1059,7 @@
 		asn_enc_rval_t rval;
 		if(specs->ext_start == -1)
 			_ASN_ENCODE_FAILED;
-		if(uper_put_nsnnwn(po, present - specs->ext_start))
+		if(uper_put_nsnnwn(po, present_enc - specs->ext_start))
 			_ASN_ENCODE_FAILED;
 		if(uper_open_type_put(elm->type, elm->per_constraints,
 			memb_ptr, po))
@@ -984,7 +1068,87 @@
 		_ASN_ENCODED_OK(rval);
 	}
 }
-   
+
+asn_enc_rval_t
+CHOICE_encode_aper(asn_TYPE_descriptor_t *td,
+				   asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
+	asn_TYPE_member_t *elm; /* CHOICE's element */
+	asn_per_constraint_t *ct;
+	void *memb_ptr;
+	int present;
+
+	if(!sptr) _ASN_ENCODE_FAILED;
+
+	ASN_DEBUG("Encoding %s as CHOICE using ALIGNED PER", td->name);
+
+	if(constraints) ct = &constraints->value;
+	else if(td->per_constraints) ct = &td->per_constraints->value;
+	else ct = 0;
+
+	present = _fetch_present_idx(sptr,
+								 specs->pres_offset, specs->pres_size);
+
+	/*
+	 * If the structure was not initialized properly, it cannot be encoded:
+	 * can't deduce what to encode in the choice type.
+	 */
+	if(present <= 0 || present > td->elements_count)
+		_ASN_ENCODE_FAILED;
+	else
+		present--;
+
+	/* Adjust if canonical order is different from natural order */
+	if(specs->canonical_order)
+		present = specs->canonical_order[present];
+
+	ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
+
+	if(ct && ct->range_bits >= 0) {
+		if(present < ct->lower_bound
+			|| present > ct->upper_bound) {
+			if(ct->flags & APC_EXTENSIBLE) {
+				if(per_put_few_bits(po, 1, 1))
+					_ASN_ENCODE_FAILED;
+			} else {
+				_ASN_ENCODE_FAILED;
+			}
+			ct = 0;
+			}
+	}
+	if(ct && ct->flags & APC_EXTENSIBLE) {
+		if(per_put_few_bits(po, 0, 1))
+			_ASN_ENCODE_FAILED;
+	}
+
+	elm = &td->elements[present];
+	if(elm->flags & ATF_POINTER) {
+		/* Member is a pointer to another structure */
+		memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
+		if(!memb_ptr) _ASN_ENCODE_FAILED;
+	} else {
+		memb_ptr = (char *)sptr + elm->memb_offset;
+	}
+
+	if(ct && ct->range_bits >= 0) {
+		if(per_put_few_bits(po, present, ct->range_bits))
+			_ASN_ENCODE_FAILED;
+
+			return elm->type->aper_encoder(elm->type, elm->per_constraints,
+										   memb_ptr, po);
+	} else {
+		asn_enc_rval_t rval;
+		if(specs->ext_start == -1)
+			_ASN_ENCODE_FAILED;
+		if(aper_put_nsnnwn(po, ct->range_bits, present - specs->ext_start))
+			_ASN_ENCODE_FAILED;
+		if(aper_open_type_put(elm->type, elm->per_constraints,
+			memb_ptr, po))
+			_ASN_ENCODE_FAILED;
+		rval.encoded = 0;
+		_ASN_ENCODED_OK(rval);
+	}
+}
 
 int
 CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
diff --git a/src/constr_SEQUENCE.c b/src/constr_SEQUENCE.c
index db3c925..21e5190 100644
--- a/src/constr_SEQUENCE.c
+++ b/src/constr_SEQUENCE.c
@@ -34,7 +34,7 @@
 #undef	ADVANCE
 #define	ADVANCE(num_bytes)	do {		\
 		size_t num = num_bytes;		\
-		ptr = ((const char *)ptr) + num;\
+		ptr = ((const char *)ptr) + num; \
 		size -= num;			\
 		if(ctx->left >= 0)		\
 			ctx->left -= num;	\
@@ -310,16 +310,16 @@
 			 * Resort to a binary search over
 			 * sorted array of tags.
 			 */
-			asn_TYPE_tag2member_t *t2m;
+			const asn_TYPE_tag2member_t *t2m;
 			asn_TYPE_tag2member_t key;
 			key.el_tag = tlv_tag;
 			key.el_no = edx;
-			t2m = (asn_TYPE_tag2member_t *)bsearch(&key,
+			t2m = (const asn_TYPE_tag2member_t *)bsearch(&key,
 				specs->tag2el, specs->tag2el_count,
 				sizeof(specs->tag2el[0]), _t2e_cmp);
 			if(t2m) {
-				asn_TYPE_tag2member_t *best = 0;
-				asn_TYPE_tag2member_t *t2m_f, *t2m_l;
+				const asn_TYPE_tag2member_t *best = 0;
+				const asn_TYPE_tag2member_t *t2m_f, *t2m_l;
 				int edx_max = edx + elements[edx].optional;
 				/*
 				 * Rewind to the first element with that tag,
@@ -667,8 +667,7 @@
 
 			if(elm->flags & ATF_POINTER) {
 				/* Member is a pointer to another structure */
-				memb_ptr2 = (void **)((char *)st
-					+ elm->memb_offset);
+				memb_ptr2 = (void **)((char *)st + elm->memb_offset);
 			} else {
 				memb_ptr = (char *)st + elm->memb_offset;
 				memb_ptr2 = &memb_ptr;
@@ -1143,6 +1142,219 @@
 		bmlength = uper_get_nslength(pd);
 		if(bmlength < 0) _ASN_DECODE_STARVED;
 
+		ASN_DEBUG("Extensions %ld present in %s", (long)bmlength, td->name);
+
+		epres = (uint8_t *)MALLOC((bmlength + 15) >> 3);
+		if(!epres) _ASN_DECODE_STARVED;
+
+		/* Get the extensions map */
+		if(per_get_many_bits(pd, epres, 0, bmlength))
+			_ASN_DECODE_STARVED;
+
+		memset(&epmd, 0, sizeof(epmd));
+		epmd.buffer = epres;
+		epmd.nbits = bmlength;
+		ASN_DEBUG("Read in extensions bitmap for %s of %ld bits (%x..)",
+			td->name, (long)bmlength, *epres);
+
+	    /* Go over extensions and read them in */
+	    for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;		/* Pointer to the member */
+		void **memb_ptr2;	/* Pointer to that pointer */
+		int present;
+
+		if(!IN_EXTENSION_GROUP(specs, edx)) {
+			ASN_DEBUG("%d is not extension", edx);
+			continue;
+		}
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+		} else {
+			memb_ptr = (void *)((char *)st + elm->memb_offset);
+			memb_ptr2 = &memb_ptr;
+		}
+
+		present = per_get_few_bits(&epmd, 1);
+		if(present <= 0) {
+			if(present < 0) break;	/* No more extensions */
+			continue;
+		}
+
+		ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2);
+		rv = uper_open_type_get(opt_codec_ctx, elm->type,
+			elm->per_constraints, memb_ptr2, pd);
+		if(rv.code != RC_OK) {
+			FREEMEM(epres);
+			return rv;
+		}
+	    }
+
+		/* Skip over overflow extensions which aren't present
+		 * in this system's version of the protocol */
+		for(;;) {
+			ASN_DEBUG("Getting overflow extensions");
+			switch(per_get_few_bits(&epmd, 1)) {
+			case -1: break;
+			case 0: continue;
+			default:
+				if(uper_open_type_skip(opt_codec_ctx, pd)) {
+					FREEMEM(epres);
+					_ASN_DECODE_STARVED;
+				}
+			}
+			break;
+		}
+
+		FREEMEM(epres);
+	}
+
+	/* Fill DEFAULT members in extensions */
+	for(edx = specs->roms_count; edx < specs->roms_count
+			+ specs->aoms_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void **memb_ptr2;	/* Pointer to member pointer */
+
+		if(!elm->default_value) continue;
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)st
+					+ elm->memb_offset);
+			if(*memb_ptr2) continue;
+		} else {
+			continue;	/* Extensions are all optionals */
+		}
+
+		/* Set default value */
+		if(elm->default_value(1, memb_ptr2)) {
+			_ASN_DECODE_FAILED;
+		}
+	}
+
+	rv.consumed = 0;
+	rv.code = RC_OK;
+	return rv;
+}
+
+asn_dec_rval_t
+SEQUENCE_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics;
+	void *st = *sptr;	/* Target structure. */
+	int extpresent;		/* Extension additions are present */
+	uint8_t *opres;		/* Presence of optional root members */
+	asn_per_data_t opmd;
+	asn_dec_rval_t rv;
+	int edx;
+
+	(void)constraints;
+
+	if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
+		_ASN_DECODE_FAILED;
+
+	if(!st) {
+		st = *sptr = CALLOC(1, specs->struct_size);
+		if(!st) _ASN_DECODE_FAILED;
+	}
+
+	ASN_DEBUG("Decoding %s as SEQUENCE (APER)", td->name);
+
+	/* Handle extensions */
+	if(specs->ext_before >= 0) {
+		extpresent = per_get_few_bits(pd, 1);
+		if(extpresent < 0) _ASN_DECODE_STARVED;
+	} else {
+		extpresent = 0;
+	}
+
+	/* Prepare a place and read-in the presence bitmap */
+	memset(&opmd, 0, sizeof(opmd));
+	if(specs->roms_count) {
+		opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1);
+		if(!opres) _ASN_DECODE_FAILED;
+		/* Get the presence map */
+		if(per_get_many_bits(pd, opres, 0, specs->roms_count)) {
+			FREEMEM(opres);
+			_ASN_DECODE_STARVED;
+		}
+		opmd.buffer = opres;
+		opmd.nbits = specs->roms_count;
+		ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)",
+			td->name, specs->roms_count, *opres);
+	} else {
+		opres = 0;
+	}
+
+	/*
+	 * Get the sequence ROOT elements.
+	 */
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;		/* Pointer to the member */
+		void **memb_ptr2;	/* Pointer to that pointer */
+
+		if(IN_EXTENSION_GROUP(specs, edx))
+			continue;
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+		} else {
+			memb_ptr = (char *)st + elm->memb_offset;
+			memb_ptr2 = &memb_ptr;
+		}
+
+		/* Deal with optionality */
+		if(elm->optional) {
+			int present = per_get_few_bits(&opmd, 1);
+			ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)",
+				td->name, elm->name, present,
+				(int)opmd.nboff, (int)opmd.nbits);
+			if(present == 0) {
+				/* This element is not present */
+				if(elm->default_value) {
+					/* Fill-in DEFAULT */
+					if(elm->default_value(1, memb_ptr2)) {
+						FREEMEM(opres);
+						_ASN_DECODE_FAILED;
+					}
+					ASN_DEBUG("Filled-in default");
+				}
+				/* The member is just not present */
+				continue;
+			}
+			/* Fall through */
+		}
+
+		/* Fetch the member from the stream */
+		ASN_DEBUG("Decoding member %s in %s", elm->name, td->name);
+		rv = elm->type->aper_decoder(opt_codec_ctx, elm->type,
+			elm->per_constraints, memb_ptr2, pd);
+		if(rv.code != RC_OK) {
+			ASN_DEBUG("Failed decode %s in %s",
+				elm->name, td->name);
+			FREEMEM(opres);
+			return rv;
+		}
+	}
+
+	/* Optionality map is not needed anymore */
+	FREEMEM(opres);
+
+	/*
+	 * Deal with extensions.
+	 */
+	if(extpresent) {
+		ssize_t bmlength;
+		uint8_t *epres;		/* Presence of extension members */
+		asn_per_data_t epmd;
+
+		bmlength = uper_get_nslength(pd);
+		if(bmlength < 0) _ASN_DECODE_STARVED;
+
 		ASN_DEBUG("Extensions %d present in %s", bmlength, td->name);
 
 		epres = (uint8_t *)MALLOC((bmlength + 15) >> 3);
@@ -1283,7 +1495,7 @@
 		if(po1 && per_put_few_bits(po1, present, 1))
 			return -1;
 		/* Encode as open type field */
-		if(po2 && present && uper_open_type_put(elm->type,
+		if(po2 && present && aper_open_type_put(elm->type,
 				elm->per_constraints, *memb_ptr2, po2))
 			return -1;
 
@@ -1421,3 +1633,130 @@
 	_ASN_ENCODED_OK(er);
 }
 
+asn_enc_rval_t
+SEQUENCE_encode_aper(asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	asn_SEQUENCE_specifics_t *specs
+		= (asn_SEQUENCE_specifics_t *)td->specifics;
+	asn_enc_rval_t er;
+	int n_extensions;
+	int edx;
+	int i;
+
+	(void)constraints;
+
+	if(!sptr)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	ASN_DEBUG("Encoding %s as SEQUENCE (APER)", td->name);
+
+	/*
+	 * X.691#18.1 Whether structure is extensible
+	 * and whether to encode extensions
+	 */
+	if(specs->ext_before >= 0) {
+		n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0);
+		per_put_few_bits(po, n_extensions ? 1 : 0, 1);
+	} else {
+		n_extensions = 0;       /* There are no extensions to encode */
+	}
+
+	/* Encode a presence bitmap */
+	for(i = 0; i < specs->roms_count; i++) {
+		asn_TYPE_member_t *elm;
+		void *memb_ptr;	 /* Pointer to the member */
+		void **memb_ptr2;       /* Pointer to that pointer */
+		int present;
+
+		edx = specs->oms[i];
+		elm = &td->elements[edx];
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+			present = (*memb_ptr2 != 0);
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+			memb_ptr2 = &memb_ptr;
+			present = 1;
+		}
+
+		/* Eliminate default values */
+		if(present && elm->default_value
+		&& elm->default_value(0, memb_ptr2) == 1)
+			present = 0;
+
+		ASN_DEBUG("Element %s %s %s->%s is %s",
+			elm->flags & ATF_POINTER ? "ptr" : "inline",
+			elm->default_value ? "def" : "wtv",
+			td->name, elm->name, present ? "present" : "absent");
+		if(per_put_few_bits(po, present, 1))
+			_ASN_ENCODE_FAILED;
+	}
+
+	/*
+	 * Encode the sequence ROOT elements.
+	 */
+	ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before);
+	for(edx = 0; edx < ((specs->ext_after < 0)
+		? td->elements_count : specs->ext_before - 1); edx++) {
+
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;	 /* Pointer to the member */
+		void **memb_ptr2;       /* Pointer to that pointer */
+
+		if(IN_EXTENSION_GROUP(specs, edx))
+			continue;
+
+		ASN_DEBUG("About to encode %s", elm->type->name);
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+			if(!*memb_ptr2) {
+				ASN_DEBUG("Element %s %d not present",
+					elm->name, edx);
+				if(elm->optional)
+					continue;
+				/* Mandatory element is missing */
+				_ASN_ENCODE_FAILED;
+			}
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+			memb_ptr2 = &memb_ptr;
+		}
+
+		/* Eliminate default values */
+		if(elm->default_value && elm->default_value(0, memb_ptr2) == 1)
+			continue;
+
+		ASN_DEBUG("Encoding %s->%s", td->name, elm->name);
+		er = elm->type->aper_encoder(elm->type, elm->per_constraints,
+			*memb_ptr2, po);
+		if(er.encoded == -1)
+			return er;
+	}
+
+	/* No extensions to encode */
+	if(!n_extensions) _ASN_ENCODED_OK(er);
+
+	ASN_DEBUG("Length of %d bit-map", n_extensions);
+	/* #18.8. Write down the presence bit-map length. */
+	if(aper_put_nslength(po, n_extensions))
+		_ASN_ENCODE_FAILED;
+
+	ASN_DEBUG("Bit-map of %d elements", n_extensions);
+	/* #18.7. Encoding the extensions presence bit-map. */
+	/* TODO: act upon NOTE in #18.7 for canonical PER */
+	if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions)
+		_ASN_ENCODE_FAILED;
+
+	ASN_DEBUG("Writing %d extensions", n_extensions);
+	/* #18.9. Encode extensions as open type fields. */
+	if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions)
+		_ASN_ENCODE_FAILED;
+
+	_ASN_ENCODED_OK(er);
+}
diff --git a/src/constr_SEQUENCE_OF.c b/src/constr_SEQUENCE_OF.c
index aa10117..6981c8b 100644
--- a/src/constr_SEQUENCE_OF.c
+++ b/src/constr_SEQUENCE_OF.c
@@ -164,7 +164,7 @@
 	if(ct) {
 		int not_in_root = (list->count < ct->lower_bound
 				|| list->count > ct->upper_bound);
-		ASN_DEBUG("lb %ld ub %ld %s",
+		ASN_DEBUG("lb %lld ub %lld %s",
 			ct->lower_bound, ct->upper_bound,
 			ct->flags & APC_EXTENSIBLE ? "ext" : "fix");
 		if(ct->flags & APC_EXTENSIBLE) {
@@ -206,3 +206,70 @@
 	_ASN_ENCODED_OK(er);
 }
 
+asn_enc_rval_t
+SEQUENCE_OF_encode_aper(asn_TYPE_descriptor_t *td,
+	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	asn_anonymous_sequence_ *list;
+	asn_per_constraint_t *ct;
+	asn_enc_rval_t er;
+	asn_TYPE_member_t *elm = td->elements;
+	int seq;
+
+	if(!sptr) _ASN_ENCODE_FAILED;
+	list = _A_SEQUENCE_FROM_VOID(sptr);
+
+	er.encoded = 0;
+
+	ASN_DEBUG("Encoding %s as SEQUENCE OF size (%d) using ALIGNED PER", td->name, list->count);
+
+	if(constraints) ct = &constraints->size;
+	else if(td->per_constraints) ct = &td->per_constraints->size;
+	else ct = 0;
+
+	/* If extensible constraint, check if size is in root */
+	if(ct) {
+		int not_in_root = (list->count < ct->lower_bound
+				|| list->count > ct->upper_bound);
+		ASN_DEBUG("lb %lld ub %lld %s",
+			ct->lower_bound, ct->upper_bound,
+			ct->flags & APC_EXTENSIBLE ? "ext" : "fix");
+		if(ct->flags & APC_EXTENSIBLE) {
+			/* Declare whether size is in extension root */
+			if(per_put_few_bits(po, not_in_root, 1))
+				_ASN_ENCODE_FAILED;
+			if(not_in_root) ct = 0;
+		} else if(not_in_root && ct->effective_bits >= 0)
+			_ASN_ENCODE_FAILED;
+	}
+
+	if(ct && ct->effective_bits >= 0) {
+		/* X.691, #19.5: No length determinant */
+//		 if(per_put_few_bits(po, list->count - ct->lower_bound,
+//				 ct->effective_bits))
+//			 _ASN_ENCODE_FAILED;
+		if (aper_put_length(po, ct->upper_bound - ct->lower_bound + 1, list->count - ct->lower_bound) < 0)
+			_ASN_ENCODE_FAILED;
+	}
+
+	for(seq = -1; seq < list->count;) {
+		ssize_t mayEncode;
+		if(seq < 0) seq = 0;
+		if(ct && ct->effective_bits >= 0) {
+			mayEncode = list->count;
+		} else {
+			mayEncode = aper_put_length(po, -1, list->count - seq);
+			if(mayEncode < 0) _ASN_ENCODE_FAILED;
+		}
+
+		while(mayEncode--) {
+			void *memb_ptr = list->array[seq++];
+			if(!memb_ptr) _ASN_ENCODE_FAILED;
+			er = elm->type->aper_encoder(elm->type,
+				elm->per_constraints, memb_ptr, po);
+			if(er.encoded == -1)
+				_ASN_ENCODE_FAILED;
+		}
+	}
+
+	_ASN_ENCODED_OK(er);
+}
diff --git a/src/constr_SET.c b/src/constr_SET.c
index ecf5661..8a124c0 100644
--- a/src/constr_SET.c
+++ b/src/constr_SET.c
@@ -175,7 +175,7 @@
 		 * for optimization.
 		 */
 	  for(;; ctx->step = 0) {
-		asn_TYPE_tag2member_t *t2m;
+		const asn_TYPE_tag2member_t *t2m;
 		asn_TYPE_tag2member_t key;
 		void *memb_ptr;		/* Pointer to the member */
 		void **memb_ptr2;	/* Pointer to that pointer */
@@ -225,7 +225,7 @@
 		}
 
 		key.el_tag = tlv_tag;
-		t2m = (asn_TYPE_tag2member_t *)bsearch(&key,
+		t2m = (const asn_TYPE_tag2member_t *)bsearch(&key,
 				specs->tag2el, specs->tag2el_count,
 				sizeof(specs->tag2el[0]), _t2e_cmp);
 		if(t2m) {
@@ -404,7 +404,7 @@
 		unsigned int midx, pres, must;
 
 		midx = edx/(8 * sizeof(specs->_mandatory_elements[0]));
-		pres = ((unsigned int *)((char *)st+specs->pres_offset))[midx];
+		pres = ((unsigned int *)((char *)st + specs->pres_offset))[midx];
 		must = sys_ntohl(specs->_mandatory_elements[midx]);
 
 		if((pres & must) == must) {
@@ -439,7 +439,8 @@
 	size_t computed_size = 0;
 	asn_enc_rval_t er;
 	int t2m_build_own = (specs->tag2el_count != td->elements_count);
-	asn_TYPE_tag2member_t *t2m;
+	const asn_TYPE_tag2member_t *t2m;
+	asn_TYPE_tag2member_t *t2m_build;
 	int t2m_count;
 	ssize_t ret;
 	int edx;
@@ -448,17 +449,16 @@
 	 * Use existing, or build our own tags map.
 	 */
 	if(t2m_build_own) {
-		t2m = (asn_TYPE_tag2member_t *)alloca(
-				td->elements_count * sizeof(t2m[0]));
-		if(!t2m) _ASN_ENCODE_FAILED; /* There are such platforms */
+		t2m_build = (asn_TYPE_tag2member_t *)alloca(
+				td->elements_count * sizeof(t2m_build[0]));
+		if(!t2m_build) _ASN_ENCODE_FAILED; /* There are such platforms */
 		t2m_count = 0;
 	} else {
+		t2m_build = NULL;
 		/*
 		 * There is no untagged CHOICE in this SET.
 		 * Employ existing table.
 		 */
-		t2m = specs->tag2el;
-		t2m_count = specs->tag2el_count;
 	}
 
 	/*
@@ -479,8 +479,8 @@
 					/* Mandatory elements missing */
 					_ASN_ENCODE_FAILED;
 				if(t2m_build_own) {
-					t2m[t2m_count].el_no = edx;
-					t2m[t2m_count].el_tag = 0;
+					t2m_build[t2m_count].el_no = edx;
+					t2m_build[t2m_count].el_tag = 0;
 					t2m_count++;
 				}
 				continue;
@@ -499,8 +499,8 @@
 		 * Remember the outmost tag of this member.
 		 */
 		if(t2m_build_own) {
-			t2m[t2m_count].el_no = edx;
-			t2m[t2m_count].el_tag = asn_TYPE_outmost_tag(
+			t2m_build[t2m_count].el_no = edx;
+			t2m_build[t2m_count].el_tag = asn_TYPE_outmost_tag(
 				elm->type, memb_ptr, elm->tag_mode, elm->tag);
 			t2m_count++;
 		} else {
@@ -513,18 +513,21 @@
 	/*
 	 * Finalize order of the components.
 	 */
-	assert(t2m_count == td->elements_count);
 	if(t2m_build_own) {
 		/*
 		 * Sort the underlying members according to their
 		 * canonical tags order. DER encoding mandates it.
 		 */
-		qsort(t2m, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
+		qsort(t2m_build, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
+		t2m = t2m_build;
 	} else {
 		/*
 		 * Tags are already sorted by the compiler.
 		 */
+		t2m = specs->tag2el;
+		t2m_count = specs->tag2el_count;
 	}
+	assert(t2m_count == td->elements_count);
 
 	/*
 	 * Encode the TLV for the sequence itself.
@@ -570,6 +573,186 @@
 	_ASN_ENCODED_OK(er);
 }
 
+asn_enc_rval_t
+SET_encode_uper(asn_TYPE_descriptor_t *td,
+				asn_per_constraints_t *constraints,
+				void *sptr,
+				asn_per_outp_t *po) {
+	_ASN_ENCODE_FAILED;
+}
+
+asn_dec_rval_t
+SET_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+					 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	_ASN_DECODE_FAILED;
+}
+
+asn_enc_rval_t
+SET_encode_aper(asn_TYPE_descriptor_t *td,
+				asn_per_constraints_t *constraints,
+				void *sptr,
+				asn_per_outp_t *po) {
+	asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
+	asn_enc_rval_t er;
+	int edx;
+	int t2m_build_own = (specs->tag2el_count != td->elements_count);
+	const asn_TYPE_tag2member_t *t2m;
+	asn_TYPE_tag2member_t *t2m_build;
+	int t2m_count;
+
+	(void)constraints;
+
+	if(!sptr)
+		_ASN_ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	ASN_DEBUG("Encoding %s as SET (APER) map %d", td->name, specs->_mandatory_elements[0]);
+
+	/*
+	 * Use existing, or build our own tags map.
+	 */
+	if(t2m_build_own) {
+		t2m_build = (asn_TYPE_tag2member_t *)alloca(
+			td->elements_count * sizeof(t2m[0]));
+		if(!t2m_build) _ASN_ENCODE_FAILED; /* There are such platforms */
+		t2m_count = 0;
+	} else {
+		t2m_build = NULL;
+		/*
+		 * There is no untagged CHOICE in this SET.
+		 * Employ existing table.
+		 */
+	}
+
+	/*
+	 * Gather the length of the underlying members sequence.
+	 */
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		void *memb_ptr;
+
+		/*
+		 * Compute the length of the encoding of this member.
+		 */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
+			if(!memb_ptr) {
+				if(!elm->optional)
+				/* Mandatory elements missing */
+					_ASN_ENCODE_FAILED;
+				if(t2m_build_own) {
+					t2m_build[t2m_count].el_no = edx;
+					t2m_build[t2m_count].el_tag = 0;
+					t2m_count++;
+				}
+				continue;
+			}
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+		}
+
+		/*
+		 * Remember the outmost tag of this member.
+		 */
+		if(t2m_build_own) {
+			t2m_build[t2m_count].el_no = edx;
+			t2m_build[t2m_count].el_tag = asn_TYPE_outmost_tag(
+				elm->type, memb_ptr, elm->tag_mode, elm->tag);
+			t2m_count++;
+		} else {
+			/*
+			 * No dynamic sorting is necessary.
+			 */
+		}
+	}
+
+	/*
+	 * Finalize order of the components.
+	 */
+	assert(t2m_count == td->elements_count);
+	if(t2m_build_own) {
+		/*
+		 * Sort the underlying members according to their
+		 * canonical tags order. DER encoding mandates it.
+		 */
+		qsort(t2m_build, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
+		t2m = t2m_build;
+	} else {
+		/*
+		 * Tags are already sorted by the compiler.
+		 */
+		t2m = specs->tag2el;
+		t2m_count = specs->tag2el_count;
+	}
+	assert(t2m_count == td->elements_count);
+
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[t2m[edx].el_no];
+//		asn_enc_rval_t tmper;
+//		void *memb_ptr;		 /* Pointer to the member */
+		void **memb_ptr2;	   /* Pointer to that pointer */
+		int present;
+
+		/* Fetch the pointer to this member */
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+			present = (*memb_ptr2 != 0);
+		} else {
+//			 memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+//			 memb_ptr2 = &memb_ptr;
+			present = 1;
+			continue;
+		}
+
+//		 /* Eliminate default values */
+//		 if(present && elm->default_value
+//			 && elm->default_value(0, memb_ptr2) == 1)
+//			 present = 0;
+
+		ASN_DEBUG("Element %s %s %s->%s is %s",
+				  elm->flags & ATF_POINTER ? "ptr" : "inline",
+				  elm->default_value ? "def" : "wtv",
+				  td->name, elm->name, present ? "present" : "absent");
+		if(per_put_few_bits(po, present << 7, 8))
+			_ASN_ENCODE_FAILED;
+	}
+
+	/*
+	 * Encode all members.
+	 */
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		asn_enc_rval_t tmper;
+		void *memb_ptr;		 /* Pointer to the member */
+		void **memb_ptr2;	   /* Pointer to that pointer */
+
+		/* Encode according to the tag order */
+//		 elm = &td->elements[t2m[edx].el_no];
+
+		if(elm->flags & ATF_POINTER) {
+			memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+			if(!*memb_ptr2) {
+				ASN_DEBUG("Element %s %d not present",
+						  elm->name, edx);
+				if(elm->optional)
+					continue;
+				/* Mandatory element is missing */
+				_ASN_ENCODE_FAILED;
+			}
+		} else {
+			memb_ptr = (void *)((char *)sptr + elm->memb_offset);
+			memb_ptr2 = &memb_ptr;
+		}
+		tmper = elm->type->aper_encoder(elm->type, elm->per_constraints,
+										*memb_ptr2, po);
+		if(tmper.encoded == -1)
+			return tmper;
+	}
+
+	_ASN_ENCODED_OK(er);
+}
+
 #undef	XER_ADVANCE
 #define	XER_ADVANCE(num_bytes)	do {			\
 		size_t num = num_bytes;			\
@@ -648,8 +831,7 @@
 
 			if(elm->flags & ATF_POINTER) {
 				/* Member is a pointer to another structure */
-				memb_ptr2 = (void **)((char *)st
-					+ elm->memb_offset);
+				memb_ptr2 = (void **)((char *)st + elm->memb_offset);
 			} else {
 				memb_ptr = (char *)st + elm->memb_offset;
 				memb_ptr2 = &memb_ptr;
@@ -804,7 +986,7 @@
 	asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
 	asn_enc_rval_t er;
 	int xcan = (flags & XER_F_CANONICAL);
-	asn_TYPE_tag2member_t *t2m = specs->tag2el_cxer;
+	const asn_TYPE_tag2member_t *t2m = specs->tag2el_cxer;
 	int t2m_count = specs->tag2el_cxer_count;
 	int edx;
 
diff --git a/src/constr_SET_OF.c b/src/constr_SET_OF.c
index 11eac57..2fd530e 100644
--- a/src/constr_SET_OF.c
+++ b/src/constr_SET_OF.c
@@ -884,7 +884,7 @@
 	if(!st) {
 		st = *sptr = CALLOC(1, specs->struct_size);
 		if(!st) _ASN_DECODE_FAILED;
-	}                                                                       
+	}
 	list = _A_SET_FROM_VOID(st);
 
 	/* Figure out which constraints to use */
@@ -901,7 +901,7 @@
 	if(ct && ct->effective_bits >= 0) {
 		/* X.691, #19.5: No length determinant */
 		nelems = per_get_few_bits(pd, ct->effective_bits);
-		ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s",
+		ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s",
 			(long)nelems, ct->lower_bound, td->name);
 		if(nelems < 0)  _ASN_DECODE_STARVED;
 		nelems += ct->lower_bound;
@@ -915,7 +915,7 @@
 			nelems = uper_get_length(pd,
 				ct ? ct->effective_bits : -1, &repeat);
 			ASN_DEBUG("Got to decode %d elements (eff %d)",
-				(int)nelems, (int)ct ? ct->effective_bits : -1);
+				(int)nelems, (int)(ct ? ct->effective_bits : -1));
 			if(nelems < 0) _ASN_DECODE_STARVED;
 		}
 
@@ -951,3 +951,91 @@
 	return rv;
 }
 
+asn_dec_rval_t
+SET_OF_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+				   asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+	asn_dec_rval_t rv;
+	asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics;
+	asn_TYPE_member_t *elm = td->elements;	/* Single one */
+	void *st = *sptr;
+	asn_anonymous_set_ *list;
+	asn_per_constraint_t *ct;
+	int repeat = 0;
+	ssize_t nelems;
+
+	if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
+		_ASN_DECODE_FAILED;
+
+	/*
+	 * Create the target structure if it is not present already.
+	 */
+	if(!st) {
+		st = *sptr = CALLOC(1, specs->struct_size);
+		if(!st) _ASN_DECODE_FAILED;
+	}
+	list = _A_SET_FROM_VOID(st);
+
+	/* Figure out which constraints to use */
+	if(constraints) ct = &constraints->size;
+	else if(td->per_constraints) ct = &td->per_constraints->size;
+	else ct = 0;
+
+	if(ct && ct->flags & APC_EXTENSIBLE) {
+		int value = per_get_few_bits(pd, 1);
+		if(value < 0) _ASN_DECODE_STARVED;
+		if(value) ct = 0;	/* Not restricted! */
+	}
+
+	if(ct && ct->effective_bits >= 0) {
+		/* X.691, #19.5: No length determinant */
+// 		nelems = per_get_few_bits(pd, ct->effective_bits);
+		nelems = aper_get_nsnnwn(pd, ct->upper_bound - ct->lower_bound);
+		ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s",
+			(long)nelems, ct->lower_bound, td->name);
+		if(nelems < 0)  _ASN_DECODE_STARVED;
+		nelems += ct->lower_bound;
+	} else {
+		nelems = -1;
+	}
+
+	do {
+		int i;
+		if(nelems < 0) {
+			nelems = aper_get_length(pd, ct ? ct->upper_bound - ct->lower_bound + 1 : -1,
+				ct ? ct->effective_bits : -1, &repeat);
+			ASN_DEBUG("Got to decode %d elements (eff %d)",
+				(int)nelems, (int)(ct ? ct->effective_bits : -1));
+			if(nelems < 0) _ASN_DECODE_STARVED;
+		}
+
+		for(i = 0; i < nelems; i++) {
+			void *ptr = 0;
+			ASN_DEBUG("SET OF %s decoding", elm->type->name);
+			rv = elm->type->aper_decoder(opt_codec_ctx, elm->type,
+				elm->per_constraints, &ptr, pd);
+			ASN_DEBUG("%s SET OF %s decoded %d, %p",
+				td->name, elm->type->name, rv.code, ptr);
+			if(rv.code == RC_OK) {
+				if(ASN_SET_ADD(list, ptr) == 0)
+					continue;
+				ASN_DEBUG("Failed to add element into %s",
+					td->name);
+				/* Fall through */
+				rv.code = RC_FAIL;
+			} else {
+				ASN_DEBUG("Failed decoding %s of %s (SET OF)",
+					elm->type->name, td->name);
+			}
+			if(ptr) ASN_STRUCT_FREE(*elm->type, ptr);
+			return rv;
+		}
+
+		nelems = -1;	/* Allow uper_get_length() */
+	} while(repeat);
+
+	ASN_DEBUG("Decoded %s as SET OF", td->name);
+
+	rv.code = RC_OK;
+	rv.consumed = 0;
+	return rv;
+}
diff --git a/src/constr_TYPE.c b/src/constr_TYPE.c
index 4bc88d4..322f68c 100644
--- a/src/constr_TYPE.c
+++ b/src/constr_TYPE.c
@@ -17,7 +17,7 @@
  * Return the outmost tag of the type.
  */
 ber_tlv_tag_t
-asn_TYPE_outmost_tag(asn_TYPE_descriptor_t *type_descriptor,
+asn_TYPE_outmost_tag(const asn_TYPE_descriptor_t *type_descriptor,
 		const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) {
 
 	if(tag_mode)
diff --git a/src/der_encoder.c b/src/der_encoder.c
index 6c859e1..1c01480 100644
--- a/src/der_encoder.c
+++ b/src/der_encoder.c
@@ -80,8 +80,8 @@
 		ber_tlv_tag_t tag,	/* EXPLICIT or IMPLICIT tag */
 		asn_app_consume_bytes_f *cb,
 		void *app_key) {
-	ber_tlv_tag_t *tags;	/* Copy of tags stream */
-	int tags_count;		/* Number of tags */
+	const ber_tlv_tag_t *tags;	/* Copy of tags stream */
+	int tags_count;			/* Number of tags */
 	size_t overall_length;
 	ssize_t *lens;
 	int i;
@@ -102,8 +102,9 @@
 		 * and initialize it appropriately.
 		 */
 		int stag_offset;
-		tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
-		if(!tags) {	/* Can fail on !x86 */
+		ber_tlv_tag_t *tags_buf;
+		tags_buf = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
+		if(!tags_buf) {	/* Can fail on !x86 */
 			errno = ENOMEM;
 			return -1;
 		}
@@ -111,10 +112,11 @@
 			+ 1	/* EXPLICIT or IMPLICIT tag is given */
 			- ((tag_mode == -1) && sd->tags_count);
 		/* Copy tags over */
-		tags[0] = tag;
+		tags_buf[0] = tag;
 		stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
 		for(i = 1; i < tags_count; i++)
-			tags[i] = sd->tags[i + stag_offset];
+			tags_buf[i] = sd->tags[i + stag_offset];
+		tags = tags_buf;
 	} else {
 		tags = sd->tags;
 		tags_count = sd->tags_count;
diff --git a/src/per_decoder.c b/src/per_decoder.c
index 2b3d2e2..20fe1a1 100644
--- a/src/per_decoder.c
+++ b/src/per_decoder.c
@@ -21,6 +21,35 @@
 		rval.consumed >>= 3;
 	} else if(rval.code == RC_OK) {
 		if(size) {
+			if(((const uint8_t *)buffer)[0] == 0) {
+				rval.consumed = 1;	/* 1 byte */
+			} else {
+				ASN_DEBUG("Expecting single zeroed byte");
+				rval.code = RC_FAIL;
+			}
+		} else {
+			/* Must contain at least 8 bits. */
+			rval.code = RC_WMORE;
+		}
+	}
+
+	return rval;
+}
+
+asn_dec_rval_t
+aper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) {
+	asn_dec_rval_t rval;
+
+	rval = aper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0);
+	if(rval.consumed) {
+		/*
+		 * We've always given 8-aligned data,
+		 * so convert bits to integral bytes.
+		 */
+		rval.consumed += 7;
+		rval.consumed >>= 3;
+	} else if(rval.code == RC_OK) {
+		if(size) {
 			if(((uint8_t *)buffer)[0] == 0) {
 				rval.consumed = 1;	/* 1 byte */
 			} else {
@@ -81,8 +110,8 @@
 		/* Return the number of consumed bits */
 		rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3)
 					+ pd.nboff - skip_bits;
-		ASN_DEBUG("PER decoding consumed %d, counted %d",
-			rval.consumed, pd.moved);
+		ASN_DEBUG("PER decoding consumed %ld, counted %ld",
+			(long)rval.consumed, (long)pd.moved);
 		assert(rval.consumed == pd.moved);
 	} else {
 		/* PER codec is not a restartable */
@@ -91,3 +120,57 @@
 	return rval;
 }
 
+asn_dec_rval_t
+aper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) {
+	asn_codec_ctx_t s_codec_ctx;
+	asn_dec_rval_t rval;
+	asn_per_data_t pd;
+
+	if(skip_bits < 0 || skip_bits > 7
+		|| unused_bits < 0 || unused_bits > 7
+		|| (unused_bits > 0 && !size))
+		_ASN_DECODE_FAILED;
+
+	/*
+	 * Stack checker requires that the codec context
+	 * must be allocated on the stack.
+	 */
+	if(opt_codec_ctx) {
+		if(opt_codec_ctx->max_stack_size) {
+			s_codec_ctx = *opt_codec_ctx;
+			opt_codec_ctx = &s_codec_ctx;
+		}
+	} else {
+		/* If context is not given, be security-conscious anyway */
+		memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
+		s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
+		opt_codec_ctx = &s_codec_ctx;
+	}
+
+	/* Fill in the position indicator */
+	memset(&pd, 0, sizeof(pd));
+	pd.buffer = (const uint8_t *)buffer;
+	pd.nboff = skip_bits;
+	pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from <limits.h> */
+	if(pd.nboff > pd.nbits)
+		_ASN_DECODE_FAILED;
+
+	/*
+	 * Invoke type-specific decoder.
+	 */
+	if(!td->aper_decoder)
+		_ASN_DECODE_FAILED;	/* PER is not compiled in */
+		rval = td->aper_decoder(opt_codec_ctx, td, 0, sptr, &pd);
+	if(rval.code == RC_OK) {
+		/* Return the number of consumed bits */
+		rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3)
+		+ pd.nboff - skip_bits;
+		ASN_DEBUG("PER decoding consumed %d, counted %d",
+				  rval.consumed, pd.moved);
+		assert(rval.consumed == pd.moved);
+	} else {
+		/* PER codec is not a restartable */
+		rval.consumed = 0;
+	}
+	return rval;
+}
diff --git a/src/per_encoder.c b/src/per_encoder.c
index f4bace0..02dc3a2 100644
--- a/src/per_encoder.c
+++ b/src/per_encoder.c
@@ -4,6 +4,7 @@
 
 static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key);
 
+static asn_enc_rval_t aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key);
 asn_enc_rval_t
 uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
 	return uper_encode_internal(td, 0, sptr, cb, app_key);
@@ -41,6 +42,18 @@
 	return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key);
 }
 
+asn_enc_rval_t
+aper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) {
+	enc_to_buf_arg key;
+
+	key.buffer = buffer;
+	key.left = buffer_size;
+
+	if(td) ASN_DEBUG("Encoding \"%s\" using ALIGNED PER", td->name);
+
+	return aper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key);
+}
+
 typedef struct enc_dyn_arg {
 	void *buffer;
 	size_t length;
@@ -88,11 +101,40 @@
 		}
 	default:
 		*buffer_r = key.buffer;
-		ASN_DEBUG("Complete encoded in %d bits", er.encoded);
+		ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
 		return ((er.encoded + 7) >> 3);
 	}
 }
 
+ssize_t
+aper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) {
+	asn_enc_rval_t er;
+	enc_dyn_arg key;
+
+	memset(&key, 0, sizeof(key));
+
+	er = aper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key);
+	switch(er.encoded) {
+		case -1:
+			FREEMEM(key.buffer);
+			return -1;
+		case 0:
+			FREEMEM(key.buffer);
+			key.buffer = MALLOC(1);
+			if(key.buffer) {
+				*(char *)key.buffer = '\0';
+				*buffer_r = key.buffer;
+				return 1;
+			} else {
+				return -1;
+			}
+		default:
+			*buffer_r = key.buffer;
+			ASN_DEBUG("Complete encoded in %d bits", er.encoded);
+			return ((er.encoded + 7) >> 3);
+	}
+}
+
 /*
  * Internally useful functions.
  */
@@ -115,6 +157,23 @@
 	return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key);
 }
 
+static int
+_aper_encode_flush_outp(asn_per_outp_t *po) {
+	uint8_t *buf;
+
+	if(po->nboff == 0 && po->buffer == po->tmpspace)
+		return 0;
+
+	buf = po->buffer + (po->nboff >> 3);
+	/* Make sure we account for the last, partially filled */
+	if(po->nboff & 0x07) {
+		buf[0] &= 0xff << (8 - (po->nboff & 0x07));
+		buf++;
+	}
+
+	return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key);
+}
+
 static asn_enc_rval_t
 uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
 	asn_per_outp_t po;
@@ -149,3 +208,37 @@
 	return er;
 }
 
+static asn_enc_rval_t
+aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {
+	asn_per_outp_t po;
+	asn_enc_rval_t er;
+
+	/*
+	 * Invoke type-specific encoder.
+	 */
+	if(!td || !td->aper_encoder)
+		_ASN_ENCODE_FAILED;	 /* PER is not compiled in */
+
+	po.buffer = po.tmpspace;
+	po.nboff = 0;
+	po.nbits = 8 * sizeof(po.tmpspace);
+	po.outper = cb;
+	po.op_key = app_key;
+	po.flushed_bytes = 0;
+
+	er = td->aper_encoder(td, constraints, sptr, &po);
+	if(er.encoded != -1) {
+		size_t bits_to_flush;
+
+		bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;
+
+		/* Set number of bits encoded to a firm value */
+		er.encoded = (po.flushed_bytes << 3) + bits_to_flush;
+
+		if(_aper_encode_flush_outp(&po))
+			_ASN_ENCODE_FAILED;
+	}
+
+	return er;
+}
+
diff --git a/src/per_opentype.c b/src/per_opentype.c
index c749c8c..984a96d 100644
--- a/src/per_opentype.c
+++ b/src/per_opentype.c
@@ -18,8 +18,6 @@
 static int per_skip_bits(asn_per_data_t *pd, int skip_nbits);
 static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd);
 
-int asn_debug_indent;
-
 /*
  * Encode an "open type field".
  * #10.1, #10.2
@@ -38,6 +36,37 @@
 
 	for(bptr = buf, toGo = size; toGo;) {
 		ssize_t maySave = uper_put_length(po, toGo);
+		ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
+			(int)size, td->name, (int)maySave);
+		if(maySave < 0) break;
+		if(per_put_many_bits(po, bptr, maySave * 8)) break;
+		bptr = (char *)bptr + maySave;
+		toGo -= maySave;
+	}
+
+	FREEMEM(buf);
+	if(toGo) return -1;
+
+	ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
+		td->name, (long)size);
+
+	return 0;
+}
+
+int
+aper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+	void *buf;
+	void *bptr;
+	ssize_t size;
+	size_t toGo;
+
+	ASN_DEBUG("Open type put %s ...", td->name);
+
+	size = aper_encode_to_new_buffer(td, constraints, sptr, &buf);
+	if(size <= 0) return -1;
+
+	for(bptr = buf, toGo = size; toGo;) {
+		ssize_t maySave = aper_put_length(po, -1, toGo);
 		if(maySave < 0) break;
 		if(per_put_many_bits(po, bptr, maySave * 8)) break;
 		bptr = (char *)bptr + maySave;
@@ -48,7 +77,7 @@
 	if(toGo) return -1;
 
 	ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)",
-		td->name, size);
+			  td->name, size);
 
 	return 0;
 }
@@ -92,28 +121,31 @@
 		bufLen += chunk_bytes;
 	} while(repeat);
 
-	ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name,
-		bufLen);
+	ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,
+		(long)bufLen);
 
 	memset(&spd, 0, sizeof(spd));
 	spd.buffer = buf;
 	spd.nbits = bufLen << 3;
 
-	asn_debug_indent += 4;
+	ASN_DEBUG_INDENT_ADD(+4);
 	rv = td->uper_decoder(ctx, td, constraints, sptr, &spd);
-	asn_debug_indent -= 4;
+	ASN_DEBUG_INDENT_ADD(-4);
 
 	if(rv.code == RC_OK) {
 		/* Check padding validity */
 		padding = spd.nbits - spd.nboff;
-		if(padding < 8 && per_get_few_bits(&spd, padding) == 0) {
+                if ((padding < 8 ||
+		/* X.691#10.1.3 */
+		(spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&
+                    per_get_few_bits(&spd, padding) == 0) {
 			/* Everything is cool */
 			FREEMEM(buf);
 			return rv;
 		}
 		FREEMEM(buf);
 		if(padding >= 8) {
-			ASN_DEBUG("Too large padding %d in open type", padding);
+			ASN_DEBUG("Too large padding %d in open type", (int)padding);
 			_ASN_DECODE_FAILED;
 		} else {
 			ASN_DEBUG("Non-zero padding");
@@ -148,9 +180,9 @@
 	pd->nbits = pd->nboff;	/* 0 good bits at this point, will refill */
 	pd->moved = 0;	/* This now counts the open type size in bits */
 
-	asn_debug_indent += 4;
+	ASN_DEBUG_INDENT_ADD(+4);
 	rv = td->uper_decoder(ctx, td, constraints, sptr, pd);
-	asn_debug_indent -= 4;
+	ASN_DEBUG_INDENT_ADD(-4);
 
 #define	UPDRESTOREPD	do {						\
 	/* buffer and nboff are valid, preserve them. */		\
@@ -165,24 +197,23 @@
 		return rv;
 	}
 
-	ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d"
-		, td->name,
+	ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name,
 		per_data_string(pd),
 		per_data_string(&arg.oldpd),
-		arg.unclaimed, arg.repeat);
+		(int)arg.unclaimed, (int)arg.repeat);
 
 	padding = pd->moved % 8;
 	if(padding) {
 		int32_t pvalue;
 		if(padding > 7) {
 			ASN_DEBUG("Too large padding %d in open type",
-				padding);
+				(int)padding);
 			rv.code = RC_FAIL;
 			UPDRESTOREPD;
 			return rv;
 		}
 		padding = 8 - padding;
-		ASN_DEBUG("Getting padding of %d bits", padding);
+		ASN_DEBUG("Getting padding of %d bits", (int)padding);
 		pvalue = per_get_few_bits(pd, padding);
 		switch(pvalue) {
 		case -1:
@@ -192,7 +223,7 @@
 		case 0: break;
 		default:
 			ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",
-				padding, (int)pvalue);
+				(int)padding, (int)pvalue);
 			UPDRESTOREPD;
 			_ASN_DECODE_FAILED;
 		}
@@ -212,14 +243,14 @@
 	UPDRESTOREPD;
 
 	/* Skip data not consumed by the decoder */
-	if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed);
 	if(arg.unclaimed) {
+		ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed);
 		switch(per_skip_bits(pd, arg.unclaimed)) {
 		case -1:
-			ASN_DEBUG("Claim of %d failed", arg.unclaimed);
+			ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed);
 			_ASN_DECODE_STARVED;
 		case 0:
-			ASN_DEBUG("Got claim of %d", arg.unclaimed);
+			ASN_DEBUG("Got claim of %d", (int)arg.unclaimed);
 			break;
 		default:
 			/* Padding must be blank */
@@ -243,9 +274,7 @@
 uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
 
-	return uper_open_type_get_simple(ctx, td, constraints,
-		sptr, pd);
-
+	return uper_open_type_get_simple(ctx, td, constraints, sptr, pd);
 }
 
 int
@@ -293,8 +322,8 @@
 
 	asn_per_data_t *oldpd = &arg->oldpd;
 
-	ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d",
-		pd->moved, oldpd->moved);
+	ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld",
+		(long)pd->moved, (long)oldpd->moved);
 
 	/* Advance our position to where pd is */
 	oldpd->buffer = pd->buffer;
@@ -314,7 +343,8 @@
 		pd->buffer = oldpd->buffer;
 		pd->nboff = oldpd->nboff - 1;
 		pd->nbits = oldpd->nbits;
-		ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved);
+		ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)",
+			(long)pd->moved);
 		return 0;
 	}
 
@@ -324,8 +354,8 @@
 	}
 
 	next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
-	ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d",
-		next_chunk_bytes, oldpd->moved, arg->repeat);
+	ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
+		(long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
 	if(next_chunk_bytes < 0) return -1;
 	if(next_chunk_bytes == 0) {
 		pd->refill = 0;	/* No more refills, naturally */
@@ -336,14 +366,16 @@
 	if(avail >= next_chunk_bits) {
 		pd->nbits = oldpd->nboff + next_chunk_bits;
 		arg->unclaimed = 0;
-		ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)",
-			next_chunk_bits, oldpd->moved,
-			oldpd->nboff, oldpd->nbits,
-			oldpd->nbits - oldpd->nboff);
+		ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)",
+			(long)next_chunk_bits, (long)oldpd->moved,
+			(long)oldpd->nboff, (long)oldpd->nbits,
+			(long)(oldpd->nbits - oldpd->nboff));
 	} else {
 		pd->nbits = oldpd->nbits;
 		arg->unclaimed = next_chunk_bits - avail;
-		ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed);
+		ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld",
+			(long)avail, (long)next_chunk_bits,
+			(long)arg->unclaimed);
 	}
 	pd->buffer = oldpd->buffer;
 	pd->nboff = oldpd->nboff;
@@ -357,7 +389,9 @@
 	int hasNonZeroBits = 0;
 	while(skip_nbits > 0) {
 		int skip;
-		if(skip_nbits < skip)
+
+		/* per_get_few_bits() is more efficient when nbits <= 24 */
+		if(skip_nbits < 24)
 			skip = skip_nbits;
 		else
 			skip = 24;
diff --git a/src/per_support.c b/src/per_support.c
index 173e696..d536bc0 100644
--- a/src/per_support.c
+++ b/src/per_support.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
+ * Copyright (c) 2005-2014 Lev Walkin <vlm@lionet.info>.
  * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
@@ -13,11 +13,11 @@
 	static int n;
 	n = (n+1) % 2;
 	snprintf(buf[n], sizeof(buf),
-		"{m=%d span %+d[%d..%d] (%d)}",
-		pd->moved,
-		(((int)pd->buffer) & 0xf),
-		pd->nboff, pd->nbits,
-		pd->nbits - pd->nboff);
+		"{m=%ld span %+ld[%d..%d] (%d)}",
+		(long)pd->moved,
+		(((long)pd->buffer) & 0xf),
+		(int)pd->nboff, (int)pd->nbits,
+		(int)(pd->nbits - pd->nboff));
 	return buf[n];
 }
 
@@ -31,6 +31,16 @@
 	}
 }
 
+int32_t
+aper_get_align(asn_per_data_t *pd) {
+
+	if(pd->nboff & 0x7) {
+		ASN_DEBUG("Aligning %d bits", 8 - (pd->nboff & 0x7));
+		return per_get_few_bits(pd, 8 - (pd->nboff & 0x7));
+	}
+	return 0;
+}
+
 /*
  * Extract a small number of bits (<= 31) from the specified PER data pointer.
  */
@@ -49,7 +59,8 @@
 		int32_t tailv, vhead;
 		if(!pd->refill || nbits > 31) return -1;
 		/* Accumulate unused bytes before refill */
-		ASN_DEBUG("Obtain the rest %d bits (want %d)", nleft, nbits);
+		ASN_DEBUG("Obtain the rest %d bits (want %d)",
+			(int)nleft, (int)nbits);
 		tailv = per_get_few_bits(pd, nleft);
 		if(tailv < 0) return -1;
 		/* Refill (replace pd contents with new data) */
@@ -103,13 +114,13 @@
 
 	accum &= (((uint32_t)1 << nbits) - 1);
 
-	ASN_DEBUG("  [PER got %2d<=%2d bits => span %d %+d[%d..%d]:%02x (%d) => 0x%x]",
-		nbits, nleft,
-		pd->moved,
-		(((int)pd->buffer) & 0xf),
-		pd->nboff, pd->nbits,
+	ASN_DEBUG("  [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%02x]",
+		(int)nbits, (int)nleft,
+		(int)pd->moved,
+		(((long)pd->buffer) & 0xf),
+		(int)pd->nboff, (int)pd->nbits,
 		pd->buffer[0],
-		pd->nbits - pd->nboff,
+		(int)(pd->nbits - pd->nboff),
 		(int)accum);
 
 	return accum;
@@ -122,6 +133,8 @@
 per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) {
 	int32_t value;
 
+	ASN_DEBUG("align: %s, nbits %d", alright ? "YES":"NO", nbits);
+
 	if(alright && (nbits & 7)) {
 		/* Perform right alignment of a first few bits */
 		value = per_get_few_bits(pd, nbits & 0x07);
@@ -186,6 +199,36 @@
 	return (16384 * value);
 }
 
+ssize_t
+aper_get_length(asn_per_data_t *pd, int range, int ebits, int *repeat) {
+	ssize_t value;
+
+	*repeat = 0;
+
+	if (range <= 65536 && range >= 0)
+		return aper_get_nsnnwn(pd, range);
+
+	if (aper_get_align(pd) < 0)
+		return -1;
+
+	if(ebits >= 0) return per_get_few_bits(pd, ebits);
+
+	value = per_get_few_bits(pd, 8);
+	if(value < 0) return -1;
+	if((value & 128) == 0)  /* #10.9.3.6 */
+		return (value & 0x7F);
+	if((value & 64) == 0) { /* #10.9.3.7 */
+		value = ((value & 63) << 8) | per_get_few_bits(pd, 8);
+		if(value < 0) return -1;
+		return value;
+	}
+	value &= 63;	/* this is "m" from X.691, #10.9.3.8 */
+	if(value < 1 || value > 4)
+		return -1;
+	*repeat = 1;
+	return (16384 * value);
+}
+
 /*
  * Get the normally small length "n".
  * This procedure used to decode length of extensions bit-maps
@@ -200,7 +243,7 @@
 	if(per_get_few_bits(pd, 1) == 0) {
 		length = per_get_few_bits(pd, 6) + 1;
 		if(length <= 0) return -1;
-		ASN_DEBUG("l=%d", length);
+		ASN_DEBUG("l=%d", (int)length);
 		return length;
 	} else {
 		int repeat;
@@ -210,6 +253,25 @@
 	}
 }
 
+ssize_t
+aper_get_nslength(asn_per_data_t *pd) {
+	ssize_t length;
+
+	ASN_DEBUG("Getting normally small length");
+
+	if(per_get_few_bits(pd, 1) == 0) {
+		length = per_get_few_bits(pd, 6) + 1;
+		if(length <= 0) return -1;
+		ASN_DEBUG("l=%d", length);
+		return length;
+	} else {
+		int repeat;
+		length = aper_get_length(pd, -1, -1, &repeat);
+		if(length >= 0 && !repeat) return length;
+		return -1; /* Error, or do not support >16K extensions */
+	}
+}
+
 /*
  * Get the normally small non-negative whole number.
  * X.691, #10.6
@@ -236,14 +298,49 @@
 	return value;
 }
 
+ssize_t
+aper_get_nsnnwn(asn_per_data_t *pd, int range) {
+	ssize_t value;
+	int bytes = 0;
+
+	ASN_DEBUG("getting nsnnwn with range %d", range);
+
+	if(range <= 255) {
+		if (range < 0) return -1;
+		/* 1 -> 8 bits */
+		int i;
+		for (i = 1; i <= 8; i++) {
+			int upper = 1 << i;
+			if (upper >= range)
+				break;
+		}
+		value = per_get_few_bits(pd, i);
+		return value;
+	} else if (range == 256){
+		/* 1 byte */
+		bytes = 1;
+		return -1;
+	} else if (range <= 65536) {
+		/* 2 bytes */
+		bytes = 2;
+	} else {
+		return -1;
+	}
+	if (aper_get_align(pd) < 0)
+		return -1;
+	value = per_get_few_bits(pd, 8 * bytes);
+	return value;
+}
+
 /*
- * Put the normally small non-negative whole number.
- * X.691, #10.6
+ * X.691-11/2008, #11.6
+ * Encoding of a normally small non-negative whole number
  */
 int
 uper_put_nsnnwn(asn_per_outp_t *po, int n) {
 	int bytes;
 
+		ASN_DEBUG("uper put nsnnwn n %d", n);
 	if(n <= 63) {
 		if(n < 0) return -1;
 		return per_put_few_bits(po, n, 7);
@@ -263,6 +360,58 @@
 }
 
 
+/* X.691-2008/11, #11.5.6 -> #11.3 */
+int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) {
+	unsigned long lhalf;    /* Lower half of the number*/
+	long half;
+
+	if(nbits <= 31) {
+		half = per_get_few_bits(pd, nbits);
+		if(half < 0) return -1;
+		*out_value = half;
+		return 0;
+	}
+
+	if((size_t)nbits > 8 * sizeof(*out_value))
+		return -1;  /* RANGE */
+
+	half = per_get_few_bits(pd, 31);
+	if(half < 0) return -1;
+
+	if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31))
+		return -1;
+
+	*out_value = ((unsigned long)half << (nbits - 31)) | lhalf;
+	return 0;
+}
+
+
+/* X.691-2008/11, #11.5.6 -> #11.3 */
+int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) {
+	/*
+	 * Assume signed number can be safely coerced into
+	 * unsigned of the same range.
+	 * The following testing code will likely be optimized out
+	 * by compiler if it is true.
+	 */
+	unsigned long uvalue1 = ULONG_MAX;
+	         long svalue  = uvalue1;
+	unsigned long uvalue2 = svalue;
+	assert(uvalue1 == uvalue2);
+	return uper_put_constrained_whole_number_u(po, v, nbits);
+}
+
+int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) {
+	if(nbits <= 31) {
+		return per_put_few_bits(po, v, nbits);
+	} else {
+		/* Put higher portion first, followed by lower 31-bit */
+		if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31))
+			return -1;
+		return per_put_few_bits(po, v, 31);
+	}
+}
+
 /*
  * Put a small number of bits (<= 31).
  */
@@ -275,7 +424,7 @@
 	if(obits <= 0 || obits >= 32) return obits ? -1 : 0;
 
 	ASN_DEBUG("[PER put %d bits %x to %p+%d bits]",
-			obits, (int)bits, po->buffer, po->nboff);
+			obits, (int)bits, po->buffer, (int)po->nboff);
 
 	/*
 	 * Normalize position indicator.
@@ -291,8 +440,8 @@
 	 */
 	if(po->nboff + obits > po->nbits) {
 		int complete_bytes = (po->buffer - po->tmpspace);
-		ASN_DEBUG("[PER output %d complete + %d]",
-			complete_bytes, po->flushed_bytes);
+		ASN_DEBUG("[PER output %ld complete + %ld]",
+			(long)complete_bytes, (long)po->flushed_bytes);
 		if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0)
 			return -1;
 		if(po->nboff)
@@ -307,47 +456,106 @@
 	 */
 	buf = po->buffer;
 	omsk = ~((1 << (8 - po->nboff)) - 1);
-	off = (po->nboff += obits);
+	off = (po->nboff + obits);
 
 	/* Clear data of debris before meaningful bits */
 	bits &= (((uint32_t)1 << obits) - 1);
 
 	ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits,
 		(int)bits, (int)bits,
-		po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk);
+		(int)po->nboff, (int)off,
+		buf[0], (int)(omsk&0xff),
+		(int)(buf[0] & omsk));
 
 	if(off <= 8)	/* Completely within 1 byte */
+		po->nboff = off,
 		bits <<= (8 - off),
 		buf[0] = (buf[0] & omsk) | bits;
 	else if(off <= 16)
+		po->nboff = off,
 		bits <<= (16 - off),
 		buf[0] = (buf[0] & omsk) | (bits >> 8),
 		buf[1] = bits;
 	else if(off <= 24)
+		po->nboff = off,
 		bits <<= (24 - off),
 		buf[0] = (buf[0] & omsk) | (bits >> 16),
 		buf[1] = bits >> 8,
 		buf[2] = bits;
 	else if(off <= 31)
+		po->nboff = off,
 		bits <<= (32 - off),
 		buf[0] = (buf[0] & omsk) | (bits >> 24),
 		buf[1] = bits >> 16,
 		buf[2] = bits >> 8,
 		buf[3] = bits;
 	else {
-		ASN_DEBUG("->[PER out split %d]", obits);
-		po->nboff -= obits; /* undo incrementation from a few lines above */
-		per_put_few_bits(po, bits >> (obits - 24), 24); /* shift according to the rest of the bits */
+		per_put_few_bits(po, bits >> (obits - 24), 24);
 		per_put_few_bits(po, bits, obits - 24);
-		ASN_DEBUG("<-[PER out split %d]", obits);
 	}
 
-	ASN_DEBUG("[PER out %u/%x => %02x buf+%d]",
-		(int)bits, (int)bits, buf[0], po->buffer - po->tmpspace);
+	ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]",
+		(int)bits, (int)bits, buf[0],
+		(long)(po->buffer - po->tmpspace));
 
 	return 0;
 }
 
+int
+aper_put_nsnnwn(asn_per_outp_t *po, int range, int number) {
+	int bytes;
+
+    ASN_DEBUG("aper put nsnnwn %d with range %d", number, range);
+	/* 10.5.7.1 X.691 */
+	if(range < 0) {
+		int i;
+		for (i = 1; ; i++) {
+			int bits = 1 << (8 * i);
+			if (number <= bits)
+				break;
+		}
+		bytes = i;
+		assert(i <= 4);
+	}
+	if(range <= 255) {
+		int i;
+		for (i = 1; i <= 8; i++) {
+			int bits = 1 << i;
+			if (range <= bits)
+				break;
+		}
+		return per_put_few_bits(po, number, i);
+	} else if(range == 256) {
+		bytes = 1;
+	} else if(range <= 65536) {
+		bytes = 2;
+	} else { /* Ranges > 64K */
+		int i;
+		for (i = 1; ; i++) {
+			int bits = 1 << (8 * i);
+			if (range <= bits)
+				break;
+		}
+		assert(i <= 4);
+		bytes = i;
+	}
+	if(aper_put_align(po) < 0) /* Aligning on octet */
+		return -1;
+// 	if(per_put_few_bits(po, bytes, 8))
+// 		return -1;
+
+    return per_put_few_bits(po, number, 8 * bytes);
+}
+
+int aper_put_align(asn_per_outp_t *po) {
+
+	if(po->nboff & 0x7) {
+		ASN_DEBUG("Aligning %d bits", 8 - (po->nboff & 0x7));
+		if(per_put_few_bits(po, 0x00, (8 - (po->nboff & 0x7))))
+			return -1;
+	}
+	return 0;
+}
 
 /*
  * Output a large number of bits.
@@ -387,6 +595,8 @@
 ssize_t
 uper_put_length(asn_per_outp_t *po, size_t length) {
 
+	ASN_DEBUG("UPER put length %d", length);
+
 	if(length <= 127)	/* #10.9.3.6 */
 		return per_put_few_bits(po, length, 8)
 			? -1 : (ssize_t)length;
@@ -401,6 +611,33 @@
 			? -1 : (ssize_t)(length << 14);
 }
 
+ssize_t
+aper_put_length(asn_per_outp_t *po, int range, size_t length) {
+
+	ASN_DEBUG("APER put length %d with range %d", length, range);
+
+	/* 10.9 X.691 Note 2 */
+	if (range <= 65536 && range >= 0)
+		return aper_put_nsnnwn(po, range, length);
+
+	if (aper_put_align(po) < 0)
+		return -1;
+
+	if(length <= 127)	   /* #10.9.3.6 */{
+		return per_put_few_bits(po, length, 8)
+		? -1 : (ssize_t)length;
+	}
+	else if(length < 16384) /* #10.9.3.7 */
+		return per_put_few_bits(po, length|0x8000, 16)
+		? -1 : (ssize_t)length;
+
+	length >>= 14;
+	if(length > 4) length = 4;
+
+	return per_put_few_bits(po, 0xC0 | length, 8)
+	? -1 : (ssize_t)(length << 14);
+}
+
 
 /*
  * Put the normally small length "n" into the stream.
@@ -424,3 +661,19 @@
 	return 0;
 }
 
+int
+aper_put_nslength(asn_per_outp_t *po, size_t length) {
+
+	if(length <= 64) {
+		/* #10.9.3.4 */
+		if(length == 0) return -1;
+		return per_put_few_bits(po, length-1, 7) ? -1 : 0;
+	} else {
+		if(aper_put_length(po, -1, length) != (ssize_t)length) {
+			/* This might happen in case of >16K extensions */
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/src/xer_decoder.c b/src/xer_decoder.c
index 161dc78..cb4b5f8 100644
--- a/src/xer_decoder.c
+++ b/src/xer_decoder.c
@@ -109,7 +109,8 @@
 
 	if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
 		if(size >= 2)
-		ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]);
+			ASN_DEBUG("Broken XML tag: \"%c...%c\"",
+			buf[0], buf[size - 1]);
 		return XCT_BROKEN;
 	}
 
@@ -315,8 +316,8 @@
 }
 
 
-int
-xer_is_whitespace(const void *chunk_buf, size_t chunk_size) {
+size_t
+xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
 	const char *p = (const char *)chunk_buf;
 	const char *pend = p + chunk_size;
 
@@ -329,12 +330,13 @@
 		 * SPACE (32)
 		 */
 		case 0x09: case 0x0a: case 0x0d: case 0x20:
-			break;
+			continue;
 		default:
-			return 0;
+			break;
 		}
+		break;
 	}
-	return 1;       /* All whitespace */
+	return (p - (const char *)chunk_buf);
 }
 
 /*
diff --git a/src/xer_support.c b/src/xer_support.c
index 9e34e69..36b4bfb 100644
--- a/src/xer_support.c
+++ b/src/xer_support.c
@@ -22,16 +22,7 @@
 	ST_COMMENT_CLO_RT	/* "-->"[1] */
 } pstate_e;
 
-static pxml_chunk_type_e final_chunk_type[] = {
-	PXML_TEXT,
-	PXML_TAG_END,
-	PXML_COMMENT_END,
-	PXML_TAG_END,
-	PXML_COMMENT_END,
-};
-
-
-static int
+static const int
 _charclass[256] = {
 	0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
@@ -79,8 +70,11 @@
 #define TOKEN_CB(_type, _ns, _current_too)			\
 	TOKEN_CB_CALL(_type, _ns, _current_too, 0)
 
+#define PXML_TAG_FINAL_CHUNK_TYPE      PXML_TAG_END
+#define PXML_COMMENT_FINAL_CHUNK_TYPE  PXML_COMMENT_END
+
 #define TOKEN_CB_FINAL(_type, _ns, _current_too)		\
-	TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1)
+	TOKEN_CB_CALL( _type ## _FINAL_CHUNK_TYPE , _ns, _current_too, 1)
 
 /*
  * Parser itself