port/merge Eurecom APER support from OPENAIRMME

Eurecom has developed APER support for asn1c as part of the OPENAIRMME
softare (a LTE MME).  This is too important to let it bit-rout out
of asn1c.  Let's forward-port and merge it.
diff --git a/asn1c/unber.c b/asn1c/unber.c
index 43bdff9..6a182eb 100644
--- a/asn1c/unber.c
+++ b/asn1c/unber.c
@@ -846,6 +846,30 @@
     return er;
 }
 
+asn_dec_rval_t
+OCTET_STRING_decode_aper(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
+			 asn_per_constraints_t *cts, void **sptr,
+			 asn_per_data_t *pd) {
+    asn_dec_rval_t rv = { 0, 0 };
+    (void)ctx;
+    (void)td;
+    (void)cts;
+    (void)sptr;
+    (void)pd;
+    return rv;
+}
+
+asn_enc_rval_t
+OCTET_STRING_encode_aper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts,
+			 void *sptr, asn_per_outp_t *po) {
+	asn_enc_rval_t er = { 0, 0, 0 };
+	(void)td;
+	(void)cts;
+	(void)sptr;
+	(void)po;
+	return er;
+}
+
 size_t
 xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
     (void)chunk_buf;
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index b4cd736..ecbf9bb 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -1242,6 +1242,8 @@
 	OUT("td->xer_encoder    = asn_DEF_%s.xer_encoder;\n",    type_name);
 	OUT("td->uper_decoder   = asn_DEF_%s.uper_decoder;\n",   type_name);
 	OUT("td->uper_encoder   = asn_DEF_%s.uper_encoder;\n",   type_name);
+	OUT("td->aper_decoder   = asn_DEF_%s.aper_decoder;\n",   type_name);
+	OUT("td->aper_encoder   = asn_DEF_%s.aper_encoder;\n",   type_name);
 	if(!terminal && !tags_count) {
 	  OUT("/* The next four lines are here because of -fknown-extern-type */\n");
 	  OUT("td->tags           = asn_DEF_%s.tags;\n",         type_name);
@@ -1394,7 +1396,39 @@
 	);
 	OUT("}\n");
 	OUT("\n");
-  }
+
+	p = MKID(expr);
+	if(HIDE_INNER_DEFS) OUT("static ");
+							OUT("asn_enc_rval_t\n");
+	OUT("%s", p);
+	if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index);
+		OUT("_encode_aper(asn_TYPE_descriptor_t *td,\n");
+	INDENTED(
+	OUT("\tasn_per_constraints_t *constraints,\n");
+	OUT("\tvoid *structure, asn_per_outp_t *per_out) {\n");
+	OUT("%s_%d_inherit_TYPE_descriptor(td);\n",
+		p, expr->_type_unique_index);
+	OUT("return td->aper_encoder(td, constraints, structure, per_out);\n");
+	);
+	OUT("}\n");
+	OUT("\n");
+
+	p = MKID(expr);
+
+	if(HIDE_INNER_DEFS) OUT("static ");
+	OUT("asn_dec_rval_t\n");
+	OUT("%s", p);
+	if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index);
+	OUT("_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,\n");
+	INDENTED(
+		OUT("\tasn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) {\n");
+	OUT("%s_%d_inherit_TYPE_descriptor(td);\n",
+		p, expr->_type_unique_index);
+	OUT("return td->aper_decoder(opt_codec_ctx, td, constraints, structure, per_data);\n");
+	);
+	OUT("}\n");
+	OUT("\n");
+	}
 
 	REDIR(OT_FUNC_DECLS);
 
@@ -1415,6 +1449,8 @@
 		if(arg->flags & A1C_GEN_PER) {
 		OUT("per_type_decoder_f %s_decode_uper;\n", p);
 		OUT("per_type_encoder_f %s_encode_uper;\n", p);
+		OUT("per_type_decoder_f %s_decode_aper;\n", p);
+		OUT("per_type_encoder_f %s_encode_aper;\n", p);
 		}
 	}
 
@@ -2003,7 +2039,7 @@
 				break;
 			case ASN_STRING_UniversalString:
 				OUT("{ APC_CONSTRAINED,\t32, 32,"
-					" 0, 2147483647 }"
+					" 0, 2147483647L }"
 					" /* special case 1 */\n");
 				goto avoid;
 			default:
@@ -2456,8 +2492,12 @@
 		if(arg->flags & A1C_GEN_PER) {
 			FUNCREF(decode_uper);
 			FUNCREF(encode_uper);
+			FUNCREF(decode_aper);
+			FUNCREF(encode_aper);
 		} else {
-			OUT("0, 0,\t/* No PER support, "
+			OUT("0, 0,\t/* No UPER support, "
+				"use \"-gen-PER\" to enable */\n");
+			OUT("0, 0,\t/* No APER support, "
 				"use \"-gen-PER\" to enable */\n");
 		}
 
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 0762850..9fb2eff 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -383,7 +383,7 @@
 	if(left.type == ARE_VALUE
 		&& left.value >= 0
 	&& right.type == ARE_VALUE
-		&& right.value > 2147483647
+		&& right.value > 2147483647L
 		&& right.value <= (asn1c_integer_t)(4294967295UL))
 		return FL_FITS_UNSIGN;
 		
diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h
index e21827e..8303270 100644
--- a/libasn1compiler/asn1c_out.h
+++ b/libasn1compiler/asn1c_out.h
@@ -117,17 +117,25 @@
  * Format LONG_MIN according to C90 rules.
  */
 #define OINT(iv)	do {					\
-	if(iv == (-2147483647L - 1))				\
+	if(iv == (-2147483647L - 1))			\
 		OUT("(-2147483647L - 1)");			\
-	else							\
-		OUT("%" PRIdASN, iv);				\
+	else if (iv > 4294967296UL)				\
+		OUT("%" PRIdASN "ull", iv);			\
+	else if (iv > 2147483647L)				\
+		OUT("%" PRIdASN "ul", iv);			\
+	else									\
+		OUT("%" PRIdASN "l", iv);			\
 } while(0)
 
 #define OINTS(iv)	do {					\
-	if(iv == (-2147483647L - 1))				\
+	if(iv == (-2147483647L - 1))			\
 		OUT("(-2147483647L - 1)");			\
-	else							\
-		OUT("% " PRIdASN, iv);				\
+	else if (iv > 4294967296UL)				\
+		OUT("%" PRIdASN "ull", iv);			\
+	else if (iv > 2147483647L)				\
+		OUT("%" PRIdASN "ul", iv);			\
+	else									\
+		OUT("% " PRIdASN "l", iv);			\
 } while(0)
 
 #endif	/* ASN1_COMPILED_OUTPUT_H */
diff --git a/skeletons/ANY.c b/skeletons/ANY.c
index 77024bd..128b550 100644
--- a/skeletons/ANY.c
+++ b/skeletons/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/skeletons/ANY.h b/skeletons/ANY.h
index b7d92fa..a68441d 100644
--- a/skeletons/ANY.h
+++ b/skeletons/ANY.h
@@ -32,10 +32,13 @@
 
 /* Convert another ASN.1 type into the ANY. This implies DER encoding. */
 int ANY_fromType(ANY_t *, asn_TYPE_descriptor_t *td, void *struct_ptr);
+int ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr);
 ANY_t *ANY_new_fromType(asn_TYPE_descriptor_t *td, void *struct_ptr);
+ANY_t *ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr);
 
 /* Convert the contents of the ANY type into the specified type. */
 int ANY_to_type(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr);
+int ANY_to_type_aper(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr);
 
 #define	ANY_fromBuf(s, buf, size)	OCTET_STRING_fromBuf((s), (buf), (size))
 #define	ANY_new_fromBuf(buf, size)	OCTET_STRING_new_fromBuf(	\
diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c
index 997ff41..d32a12f 100644
--- a/skeletons/BIT_STRING.c
+++ b/skeletons/BIT_STRING.c
@@ -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)
diff --git a/skeletons/BMPString.c b/skeletons/BMPString.c
index 8beaabd..aa248dc 100644
--- a/skeletons/BMPString.c
+++ b/skeletons/BMPString.c
@@ -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)
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index 6e55b3e..64d946a 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -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]),
@@ -264,6 +266,35 @@
 	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,
@@ -280,3 +311,18 @@
 
 	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/skeletons/BOOLEAN.h b/skeletons/BOOLEAN.h
index 217d0f1..8ea2892 100644
--- a/skeletons/BOOLEAN.h
+++ b/skeletons/BOOLEAN.h
@@ -28,6 +28,8 @@
 xer_type_encoder_f BOOLEAN_encode_xer;
 per_type_decoder_f BOOLEAN_decode_uper;
 per_type_encoder_f BOOLEAN_encode_uper;
+per_type_decoder_f BOOLEAN_decode_aper;
+per_type_encoder_f BOOLEAN_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c
index ccb003e..d19a5d3 100644
--- a/skeletons/ENUMERATED.c
+++ b/skeletons/ENUMERATED.c
@@ -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/skeletons/ENUMERATED.h b/skeletons/ENUMERATED.h
index 542dcae..5c4a2ed 100644
--- a/skeletons/ENUMERATED.h
+++ b/skeletons/ENUMERATED.h
@@ -17,6 +17,8 @@
 
 per_type_decoder_f ENUMERATED_decode_uper;
 per_type_encoder_f ENUMERATED_encode_uper;
+per_type_decoder_f ENUMERATED_decode_aper;
+per_type_encoder_f ENUMERATED_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c
index c398d2b..934b8a2 100644
--- a/skeletons/GeneralString.c
+++ b/skeletons/GeneralString.c
@@ -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/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c
index 7e14477..9fd36d2 100644
--- a/skeletons/GeneralizedTime.c
+++ b/skeletons/GeneralizedTime.c
@@ -181,6 +181,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)
diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c
index e572ccd..5f62486 100644
--- a/skeletons/GraphicString.c
+++ b/skeletons/GraphicString.c
@@ -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/skeletons/IA5String.c b/skeletons/IA5String.c
index b856d30..766963c 100644
--- a/skeletons/IA5String.c
+++ b/skeletons/IA5String.c
@@ -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/skeletons/INTEGER.c b/skeletons/INTEGER.c
index eed8217..1107e20 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -30,6 +30,8 @@
 #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,
@@ -410,7 +412,7 @@
 					(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);
 					dec_value = el->nat_value;
 					state = ST_END_ENUM;
@@ -608,7 +610,7 @@
 				if(uper_get_constrained_whole_number(pd,
 					&uvalue, ct->range_bits))
 					ASN__DECODE_STARVED;
-				ASN_DEBUG("Got value %lu + low %ld",
+				ASN_DEBUG("Got value %lu + low %lld",
 					uvalue, ct->lower_bound);
 				uvalue += ct->lower_bound;
 				if(asn_ulong2INTEGER(st, uvalue))
@@ -665,6 +667,149 @@
 	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) {
+			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 {
+				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;
+			}
+			return rval;
+		} else {
+			_ASN_DECODE_FAILED;
+		}
+	} 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 = aper_get_length(pd, -1, -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_enc_rval_t
 INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
@@ -699,7 +844,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");
@@ -716,7 +861,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");
@@ -743,7 +888,7 @@
 	}
 
 	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;
 	}
@@ -762,6 +907,129 @@
 
 #endif	/* ASN_DISABLE_PER_SUPPORT */
 
+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);
+}
+
 int
 asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
 	uint8_t *b, *end;
@@ -823,6 +1091,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;
@@ -855,6 +1183,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;
@@ -880,6 +1240,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;
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
index 9a88097..5e0d94a 100644
--- a/skeletons/INTEGER.h
+++ b/skeletons/INTEGER.h
@@ -18,7 +18,7 @@
 
 /* Map with <tag> to integer value association */
 typedef struct asn_INTEGER_enum_map_s {
-	long		 nat_value;	/* associated native integer value */
+	int64_t		 nat_value;	/* associated native integer value */
 	size_t		 enum_len;	/* strlen("tag") */
 	const char	*enum_name;	/* "tag" */
 } asn_INTEGER_enum_map_t;
@@ -41,6 +41,8 @@
 xer_type_encoder_f INTEGER_encode_xer;
 per_type_decoder_f INTEGER_decode_uper;
 per_type_encoder_f INTEGER_encode_uper;
+per_type_decoder_f INTEGER_decode_aper;
+per_type_encoder_f INTEGER_encode_aper;
 
 /***********************************
  * Some handy conversion routines. *
@@ -52,8 +54,12 @@
  * -1/ERANGE: Value encoded is out of range for long representation
  * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()).
  */
+int asn_INTEGER2int64(const INTEGER_t *i, int64_t *l);
+int asn_INTEGER2uint64(const INTEGER_t *i, uint64_t *l);
 int asn_INTEGER2long(const INTEGER_t *i, long *l);
 int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l);
+int asn_int642INTEGER(INTEGER_t *i, int64_t l);
+int asn_uint642INTEGER(INTEGER_t *i, uint64_t l);
 int asn_long2INTEGER(INTEGER_t *i, long l);
 int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l);
 
diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c
index 8d681c8..a6cc761 100644
--- a/skeletons/ISO646String.c
+++ b/skeletons/ISO646String.c
@@ -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/skeletons/NULL.c b/skeletons/NULL.c
index 62bc91e..a0da602 100644
--- a/skeletons/NULL.c
+++ b/skeletons/NULL.c
@@ -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]),
@@ -136,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) {
@@ -149,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/skeletons/NULL.h b/skeletons/NULL.h
index 131e775..90784d8 100644
--- a/skeletons/NULL.h
+++ b/skeletons/NULL.h
@@ -25,6 +25,8 @@
 xer_type_encoder_f NULL_encode_xer;
 per_type_decoder_f NULL_decode_uper;
 per_type_encoder_f NULL_encode_uper;
+per_type_decoder_f NULL_decode_aper;
+per_type_encoder_f NULL_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c
index 78366af..5b427ab 100644
--- a/skeletons/NativeEnumerated.c
+++ b/skeletons/NativeEnumerated.c
@@ -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;
@@ -205,3 +262,72 @@
 	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);
+}
+
diff --git a/skeletons/NativeEnumerated.h b/skeletons/NativeEnumerated.h
index c59bb1b..95f0531 100644
--- a/skeletons/NativeEnumerated.h
+++ b/skeletons/NativeEnumerated.h
@@ -24,6 +24,8 @@
 xer_type_encoder_f NativeEnumerated_encode_xer;
 per_type_decoder_f NativeEnumerated_decode_uper;
 per_type_encoder_f NativeEnumerated_encode_uper;
+per_type_decoder_f NativeEnumerated_decode_aper;
+per_type_encoder_f NativeEnumerated_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
index e8ce6d2..157d40a 100644
--- a/skeletons/NativeInteger.c
+++ b/skeletons/NativeInteger.c
@@ -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]),
@@ -267,6 +269,42 @@
 	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
+			ASN_DEBUG("NativeInteger %s got value %ld",
+				td->name, *native);
+	}
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+
+	return rval;
+}
+
 asn_enc_rval_t
 NativeInteger_encode_uper(asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
@@ -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/skeletons/NativeInteger.h b/skeletons/NativeInteger.h
index 4e63a83..14aa1a4 100644
--- a/skeletons/NativeInteger.h
+++ b/skeletons/NativeInteger.h
@@ -29,6 +29,8 @@
 xer_type_encoder_f NativeInteger_encode_xer;
 per_type_decoder_f NativeInteger_decode_uper;
 per_type_encoder_f NativeInteger_encode_uper;
+per_type_decoder_f NativeInteger_decode_aper;
+per_type_encoder_f NativeInteger_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c
index ad6f28c..7db8bae 100644
--- a/skeletons/NativeReal.c
+++ b/skeletons/NativeReal.c
@@ -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]),
@@ -228,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.
  */
@@ -257,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/skeletons/NativeReal.h b/skeletons/NativeReal.h
index 68a81d9..94ed9de 100644
--- a/skeletons/NativeReal.h
+++ b/skeletons/NativeReal.h
@@ -27,6 +27,8 @@
 xer_type_encoder_f NativeReal_encode_xer;
 per_type_decoder_f NativeReal_decode_uper;
 per_type_encoder_f NativeReal_encode_uper;
+per_type_decoder_f NativeReal_decode_aper;
+per_type_encoder_f NativeReal_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c
index 887b3f5..1ed6316 100644
--- a/skeletons/NumericString.c
+++ b/skeletons/NumericString.c
@@ -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/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index d0f8b31..8a78265 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -27,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)
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
index 5420ded..c667e8f 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -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)
@@ -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,7 +1756,7 @@
 	}
 
 	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" : "");
@@ -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,6 +1842,173 @@
 	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) {
diff --git a/skeletons/OCTET_STRING.h b/skeletons/OCTET_STRING.h
index 013c7b1..bc25666 100644
--- a/skeletons/OCTET_STRING.h
+++ b/skeletons/OCTET_STRING.h
@@ -32,6 +32,8 @@
 xer_type_encoder_f OCTET_STRING_encode_xer_utf8;
 per_type_decoder_f OCTET_STRING_decode_uper;
 per_type_encoder_f OCTET_STRING_encode_uper;
+per_type_decoder_f OCTET_STRING_decode_aper;
+per_type_encoder_f OCTET_STRING_encode_aper;
 
 /******************************
  * Handy conversion routines. *
diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c
index 31bc1b2..f049c1c 100644
--- a/skeletons/ObjectDescriptor.c
+++ b/skeletons/ObjectDescriptor.c
@@ -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/skeletons/PrintableString.c b/skeletons/PrintableString.c
index 7b6828d..a0b263d 100644
--- a/skeletons/PrintableString.c
+++ b/skeletons/PrintableString.c
@@ -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/skeletons/REAL.c b/skeletons/REAL.c
index 0a25062..a157d9b 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -51,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]),
@@ -390,6 +392,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;
diff --git a/skeletons/REAL.h b/skeletons/REAL.h
index af3e84c..503e254 100644
--- a/skeletons/REAL.h
+++ b/skeletons/REAL.h
@@ -21,6 +21,8 @@
 xer_type_encoder_f REAL_encode_xer;
 per_type_decoder_f REAL_decode_uper;
 per_type_encoder_f REAL_encode_uper;
+per_type_decoder_f REAL_decode_aper;
+per_type_encoder_f REAL_encode_aper;
 
 /***********************************
  * Some handy conversion routines. *
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index 352ce79..eaaa9f3 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -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)
diff --git a/skeletons/T61String.c b/skeletons/T61String.c
index 115d7d4..4a6ad47 100644
--- a/skeletons/T61String.c
+++ b/skeletons/T61String.c
@@ -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/skeletons/TeletexString.c b/skeletons/TeletexString.c
index faad697..40b5c4e 100644
--- a/skeletons/TeletexString.c
+++ b/skeletons/TeletexString.c
@@ -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/skeletons/UTCTime.c b/skeletons/UTCTime.c
index 3983d76..1666a8e 100644
--- a/skeletons/UTCTime.c
+++ b/skeletons/UTCTime.c
@@ -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/skeletons/UTF8String.c b/skeletons/UTF8String.c
index d666a4e..43a8e83 100644
--- a/skeletons/UTF8String.c
+++ b/skeletons/UTF8String.c
@@ -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)
diff --git a/skeletons/UniversalString.c b/skeletons/UniversalString.c
index 21753eb..b5d63ab 100644
--- a/skeletons/UniversalString.c
+++ b/skeletons/UniversalString.c
@@ -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/skeletons/VideotexString.c b/skeletons/VideotexString.c
index 09967db..e6fc423 100644
--- a/skeletons/VideotexString.c
+++ b/skeletons/VideotexString.c
@@ -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/skeletons/VisibleString.c b/skeletons/VisibleString.c
index 0f4dec5..83bdb75 100644
--- a/skeletons/VisibleString.c
+++ b/skeletons/VisibleString.c
@@ -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/skeletons/asn_internal.h b/skeletons/asn_internal.h
index 9c94ca6..56d4651 100644
--- a/skeletons/asn_internal.h
+++ b/skeletons/asn_internal.h
@@ -20,7 +20,7 @@
 #endif
 
 /* Environment version might be used to avoid running with the old library */
-#define	ASN1C_ENVIRONMENT_VERSION	923	/* Compile-time version */
+#define	ASN1C_ENVIRONMENT_VERSION	924	/* Compile-time version */
 int get_asn1c_environment_version(void);	/* Run-time version */
 
 #define	CALLOC(nmemb, size)	calloc(nmemb, size)
@@ -47,13 +47,17 @@
 int asn_debug_indent;
 #define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0)
 #endif	/* ASN_THREAD_SAFE */
-#define	ASN_DEBUG(fmt, args...)	do {			\
+extern int asn_debug; /* Allow option on execution */
+#define	ASN_DEBUG(fmt, args...) \
+if (asn_debug) {    \
+    do {			\
 		int adi = asn_debug_indent;		\
 		while(adi--) fprintf(stderr, " ");	\
 		fprintf(stderr, fmt, ##args);		\
 		fprintf(stderr, " (%s:%d)\n",		\
 			__FILE__, __LINE__);		\
-	} while(0)
+	} while(0);  \
+}
 #else	/* !__GNUC__ */
 void ASN_DEBUG_f(const char *fmt, ...);
 #define	ASN_DEBUG	ASN_DEBUG_f
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
index 6116e6a..dbca5ae 100644
--- a/skeletons/constr_CHOICE.c
+++ b/skeletons/constr_CHOICE.c
@@ -905,7 +905,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) {
@@ -918,7 +999,7 @@
 
 	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;
@@ -988,7 +1069,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/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
index e824a22..ddcbb39 100644
--- a/skeletons/constr_CHOICE.h
+++ b/skeletons/constr_CHOICE.h
@@ -48,6 +48,8 @@
 xer_type_encoder_f CHOICE_encode_xer;
 per_type_decoder_f CHOICE_decode_uper;
 per_type_encoder_f CHOICE_encode_uper;
+per_type_decoder_f CHOICE_decode_aper;
+per_type_encoder_f CHOICE_encode_aper;
 asn_outmost_tag_f CHOICE_outmost_tag;
 
 #ifdef __cplusplus
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 5923023..9e6cc16 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -1242,6 +1242,219 @@
 	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);
+		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 %d bits (%x..)",
+			td->name, 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;
+}
+
 static int
 SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr,
 		asn_per_outp_t *po1, asn_per_outp_t *po2) {
@@ -1285,7 +1498,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;
 
@@ -1423,3 +1636,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/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h
index c2aeb66..d181848 100644
--- a/skeletons/constr_SEQUENCE.h
+++ b/skeletons/constr_SEQUENCE.h
@@ -52,6 +52,8 @@
 xer_type_encoder_f SEQUENCE_encode_xer;
 per_type_decoder_f SEQUENCE_decode_uper;
 per_type_encoder_f SEQUENCE_encode_uper;
+per_type_decoder_f SEQUENCE_decode_aper;
+per_type_encoder_f SEQUENCE_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c
index 8a08ee8..25f272b 100644
--- a/skeletons/constr_SEQUENCE_OF.c
+++ b/skeletons/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/skeletons/constr_SEQUENCE_OF.h b/skeletons/constr_SEQUENCE_OF.h
index e2272f3..94a7cd5 100644
--- a/skeletons/constr_SEQUENCE_OF.h
+++ b/skeletons/constr_SEQUENCE_OF.h
@@ -22,9 +22,11 @@
 #define	SEQUENCE_OF_decode_ber	SET_OF_decode_ber
 #define	SEQUENCE_OF_decode_xer	SET_OF_decode_xer
 #define	SEQUENCE_OF_decode_uper	SET_OF_decode_uper
+#define	SEQUENCE_OF_decode_aper	SET_OF_decode_aper
 der_type_encoder_f SEQUENCE_OF_encode_der;
 xer_type_encoder_f SEQUENCE_OF_encode_xer;
 per_type_encoder_f SEQUENCE_OF_encode_uper;
+per_type_encoder_f SEQUENCE_OF_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index 55a0bad..b575b28 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -573,6 +573,181 @@
 	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_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_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, i;
+	int t2m_build_own = (specs->tag2el_count != td->elements_count);
+	asn_TYPE_tag2member_t *t2m;
+	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 = (asn_TYPE_tag2member_t *)alloca(
+			td->elements_count * sizeof(t2m[0]));
+	if(!t2m) _ASN_ENCODE_FAILED; /* There are such platforms */
+		t2m_count = 0;
+	} else {
+		/*
+		 * There is no untagged CHOICE in this SET.
+		 * Employ existing table.
+		 */
+		t2m = specs->tag2el;
+		t2m_count = specs->tag2el_count;
+	}
+
+	/*
+	 * Gather the length of the underlying members sequence.
+	 */
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn_TYPE_member_t *elm = &td->elements[edx];
+		asn_enc_rval_t tmper;
+		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[t2m_count].el_no = edx;
+					t2m[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[t2m_count].el_no = edx;
+			t2m[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, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
+	} else {
+		/*
+		 * Tags are already sorted by the compiler.
+		 */
+	}
+
+	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;			\
diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h
index 6a3a1aa..11b7153 100644
--- a/skeletons/constr_SET.h
+++ b/skeletons/constr_SET.h
@@ -53,7 +53,9 @@
 xer_type_decoder_f SET_decode_xer;
 xer_type_encoder_f SET_encode_xer;
 per_type_decoder_f SET_decode_uper;
+per_type_decoder_f SET_decode_aper;
 per_type_encoder_f SET_encode_uper;
+per_type_encoder_f SET_encode_aper;
 
 /***********************
  * Some handy helpers. *
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index 2dbc6e5..152efab 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -885,7 +885,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 */
@@ -902,7 +902,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;
@@ -952,3 +952,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/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h
index 75e18cf..8ddd0e3 100644
--- a/skeletons/constr_SET_OF.h
+++ b/skeletons/constr_SET_OF.h
@@ -34,6 +34,8 @@
 xer_type_encoder_f SET_OF_encode_xer;
 per_type_decoder_f SET_OF_decode_uper;
 per_type_encoder_f SET_OF_encode_uper;
+per_type_decoder_f SET_OF_decode_aper;
+per_type_encoder_f SET_OF_encode_aper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index a9cd86d..13c60f3 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -99,6 +99,8 @@
 	xer_type_encoder_f *xer_encoder;	/* [Canonical] XER encoder */
 	per_type_decoder_f *uper_decoder;	/* Unaligned PER decoder */
 	per_type_encoder_f *uper_encoder;	/* Unaligned PER encoder */
+	per_type_decoder_f *aper_decoder;	/* Aligned PER decoder */
+	per_type_encoder_f *aper_encoder;	/* Aligned PER encoder */
 
 	/***********************************************************************
 	 * Internally useful members. Not to be used by applications directly. *
diff --git a/skeletons/per_decoder.c b/skeletons/per_decoder.c
index 461b726..a85efb8 100644
--- a/skeletons/per_decoder.c
+++ b/skeletons/per_decoder.c
@@ -37,6 +37,35 @@
 }
 
 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 {
+				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
 uper_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;
@@ -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/skeletons/per_decoder.h b/skeletons/per_decoder.h
index 8397a54..5541bae 100644
--- a/skeletons/per_decoder.h
+++ b/skeletons/per_decoder.h
@@ -38,8 +38,30 @@
 	int unused_bits		/* Number of unused tailing bits, 0..7 */
 	);
 
+/*
+ * Aligned PER decoder of a "complete encoding" as per X.691#10.1.
+ * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3.
+ */
+asn_dec_rval_t aper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx,
+									struct asn_TYPE_descriptor_s *type_descriptor,	/* Type to decode */
+									void **struct_ptr,	/* Pointer to a target structure's pointer */
+									const void *buffer,	/* Data to be decoded */
+									size_t size		/* Size of data buffer */
+									);
 
 /*
+ * Aligned PER decoder of any ASN.1 type. May be invoked by the application.
+ * WARNING: This call returns the number of BITS read from the stream. Beware.
+ */
+asn_dec_rval_t aper_decode(struct asn_codec_ctx_s *opt_codec_ctx,
+						   struct asn_TYPE_descriptor_s *type_descriptor,	/* Type to decode */
+						   void **struct_ptr,	/* Pointer to a target structure's pointer */
+						   const void *buffer,	/* Data to be decoded */
+						   size_t size,		/* Size of data buffer */
+						   int skip_bits,		/* Number of unused leading bits, 0..7 */
+						   int unused_bits		/* Number of unused tailing bits, 0..7 */
+					       );
+/*
  * Type of the type-specific PER decoder function.
  */
 typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx,
diff --git a/skeletons/per_encoder.c b/skeletons/per_encoder.c
index 47f3c91..7939b97 100644
--- a/skeletons/per_encoder.c
+++ b/skeletons/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;
@@ -93,6 +106,35 @@
 	}
 }
 
+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/skeletons/per_encoder.h b/skeletons/per_encoder.h
index 95a6506..e3b9190 100644
--- a/skeletons/per_encoder.h
+++ b/skeletons/per_encoder.h
@@ -38,6 +38,12 @@
 	size_t buffer_size	/* Initial buffer size (max) */
 );
 
+asn_enc_rval_t aper_encode_to_buffer(
+	struct asn_TYPE_descriptor_s *type_descriptor,
+	void *struct_ptr,	   /* Structure to be encoded */
+	void *buffer,		   /* Pre-allocated buffer */
+	size_t buffer_size	   /* Initial buffer size (max) */
+);
 /*
  * A variant of uper_encode_to_buffer() which allocates buffer itself.
  * Returns the number of bytes in the buffer or -1 in case of failure.
@@ -52,6 +58,11 @@
 	void **buffer_r		/* Buffer allocated and returned */
 );
 
+ssize_t
+aper_encode_to_new_buffer(struct asn_TYPE_descriptor_s *td,
+						  asn_per_constraints_t *constraints,
+						  void *sptr,
+						  void **buffer_r);
 /*
  * Type of the generic PER encoder function.
  */
diff --git a/skeletons/per_opentype.c b/skeletons/per_opentype.c
index 404aa72..eb82bbc 100644
--- a/skeletons/per_opentype.c
+++ b/skeletons/per_opentype.c
@@ -53,6 +53,35 @@
 	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;
+		toGo -= maySave;
+	}
+
+	FREEMEM(buf);
+	if(toGo) return -1;
+
+	ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)",
+			  td->name, size);
+
+	return 0;
+}
+
 static asn_dec_rval_t
 uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
 	asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
diff --git a/skeletons/per_opentype.h b/skeletons/per_opentype.h
index facfaa6..2117efe 100644
--- a/skeletons/per_opentype.h
+++ b/skeletons/per_opentype.h
@@ -15,6 +15,8 @@
 
 int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po);
 
+int aper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/skeletons/per_support.c b/skeletons/per_support.c
index 5ecdc2e..21ea239 100644
--- a/skeletons/per_support.c
+++ b/skeletons/per_support.c
@@ -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.
  */
@@ -104,7 +114,7 @@
 
 	accum &= (((uint32_t)1 << nbits) - 1);
 
-	ASN_DEBUG("  [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]",
+	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),
@@ -123,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);
@@ -187,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
@@ -211,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
@@ -237,6 +298,40 @@
 	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;
+}
+
 /*
  * X.691-11/2008, #11.6
  * Encoding of a normally small non-negative whole number
@@ -245,6 +340,7 @@
 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);
@@ -405,6 +501,61 @@
 	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.
@@ -444,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;
@@ -458,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.
@@ -481,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/skeletons/per_support.h b/skeletons/per_support.h
index a75ac94..181fe24 100644
--- a/skeletons/per_support.h
+++ b/skeletons/per_support.h
@@ -24,8 +24,8 @@
 	} flags;
 	int  range_bits;		/* Full number of bits in the range */
 	int  effective_bits;		/* Effective bits */
-	long lower_bound;		/* "lb" value */
-	long upper_bound;		/* "ub" value */
+	int64_t lower_bound;		/* "lb" value */
+	int64_t upper_bound;		/* "ub" value */
 } asn_per_constraint_t;
 typedef const struct asn_per_constraints_s {
 	struct asn_per_constraint_s value;
@@ -39,9 +39,9 @@
  */
 typedef struct asn_per_data_s {
   const uint8_t *buffer;  /* Pointer to the octet stream */
-         size_t  nboff;   /* Bit offset to the meaningful bit */
-         size_t  nbits;   /* Number of bits in the stream */
-         size_t  moved;   /* Number of bits moved through this bit stream */
+		 size_t  nboff;   /* Bit offset to the meaningful bit */
+		 size_t  nbits;   /* Number of bits in the stream */
+		 size_t  moved;   /* Number of bits moved through this bit stream */
   int (*refill)(struct asn_per_data_s *);
   void *refill_key;
 } asn_per_data_t;
@@ -71,15 +71,22 @@
 			int effective_bound_bits,
 			int *repeat);
 
+ssize_t aper_get_length(asn_per_data_t *pd,
+						int range,
+						int effective_bound_bits,
+						int *repeat);
+
 /*
  * Get the normally small length "n".
  */
 ssize_t uper_get_nslength(asn_per_data_t *pd);
+ssize_t aper_get_nslength(asn_per_data_t *pd);
 
 /*
  * Get the normally small non-negative whole number.
  */
 ssize_t uper_get_nsnnwn(asn_per_data_t *pd);
+ssize_t aper_get_nsnnwn(asn_per_data_t *pd, int range);
 
 /* X.691-2008/11, #11.5.6 */
 int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits);
@@ -110,6 +117,10 @@
 int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits);
 int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits);
 
+/* Align the current bit position to octet bundary */
+int aper_put_align(asn_per_outp_t *po);
+int32_t aper_get_align(asn_per_data_t *pd);
+
 /*
  * Put the length "n" to the Unaligned PER stream.
  * This function returns the number of units which may be flushed
@@ -117,17 +128,23 @@
  */
 ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length);
 
+ssize_t aper_put_length(asn_per_outp_t *po, int range, size_t length);
+
 /*
  * Put the normally small length "n" to the Unaligned PER stream.
  * Returns 0 or -1.
  */
 int uper_put_nslength(asn_per_outp_t *po, size_t length);
 
+int aper_put_nslength(asn_per_outp_t *po, size_t length);
+
 /*
  * Put the normally small non-negative whole number.
  */
 int uper_put_nsnnwn(asn_per_outp_t *po, int n);
 
+int aper_put_nsnnwn(asn_per_outp_t *po, int range, int number);
+
 #ifdef __cplusplus
 }
 #endif