more PER support


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@1245 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c
index 55bb664..01b606b 100644
--- a/skeletons/GeneralString.c
+++ b/skeletons/GeneralString.c
@@ -22,7 +22,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_hex,
 	OCTET_STRING_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_uper,
 	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 f864d83..982cca5 100644
--- a/skeletons/GeneralizedTime.c
+++ b/skeletons/GeneralizedTime.c
@@ -147,6 +147,11 @@
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),  /* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))    /* ... OCTET STRING */
 };
+static asn_per_constraints_t asn_DEF_GeneralizedTime_constraints = {
+	{ APC_CONSTRAINED, 7, 7, 0x20, 0x7e },  /* Value */
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */
+	0, 0
+};
 asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = {
 	"GeneralizedTime",
 	"GeneralizedTime",
@@ -157,7 +162,8 @@
 	GeneralizedTime_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	GeneralizedTime_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_GeneralizedTime_tags,
 	sizeof(asn_DEF_GeneralizedTime_tags)
@@ -165,7 +171,7 @@
 	asn_DEF_GeneralizedTime_tags,
 	sizeof(asn_DEF_GeneralizedTime_tags)
 	  / sizeof(asn_DEF_GeneralizedTime_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_GeneralizedTime_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c
index 135cd73..7d59d52 100644
--- a/skeletons/GraphicString.c
+++ b/skeletons/GraphicString.c
@@ -22,7 +22,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_hex,
 	OCTET_STRING_encode_xer,	/* Can't expect it to be ASCII/UTF8 */
-	0, 0,
+	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_uper,
 	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 5c000b0..8d81e44 100644
--- a/skeletons/IA5String.c
+++ b/skeletons/IA5String.c
@@ -12,6 +12,11 @@
 	(ASN_TAG_CLASS_UNIVERSAL | (22 << 2)),	/* [UNIVERSAL 22] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
+static asn_per_constraints_t asn_DEF_IA5String_constraints = {
+	{ APC_CONSTRAINED, 7, 7, 0, 0x7f },	/* Value */
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },	/* Size */
+	0, 0
+};
 asn_TYPE_descriptor_t asn_DEF_IA5String = {
 	"IA5String",
 	"IA5String",
@@ -22,7 +27,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_IA5String_tags,
 	sizeof(asn_DEF_IA5String_tags)
@@ -30,7 +36,7 @@
 	asn_DEF_IA5String_tags,
 	sizeof(asn_DEF_IA5String_tags)
 	  / sizeof(asn_DEF_IA5String_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_IA5String_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c
index d164aa7..d6ded0e 100644
--- a/skeletons/ISO646String.c
+++ b/skeletons/ISO646String.c
@@ -12,6 +12,11 @@
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),	/* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
+static asn_per_constraints_t asn_DEF_ISO646String_constraints = {
+	{ APC_CONSTRAINED, 7, 7, 0x20, 0x7e },	/* Value */
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },	/* Size */
+	0, 0
+};
 asn_TYPE_descriptor_t asn_DEF_ISO646String = {
 	"ISO646String",
 	"ISO646String",
@@ -22,7 +27,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_ISO646String_tags,
 	sizeof(asn_DEF_ISO646String_tags)
@@ -30,8 +36,7 @@
 	asn_DEF_ISO646String_tags,
 	sizeof(asn_DEF_ISO646String_tags)
 	  / sizeof(asn_DEF_ISO646String_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_ISO646String_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
-
diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c
index 2b8ec16..a1ff91e 100644
--- a/skeletons/NativeReal.c
+++ b/skeletons/NativeReal.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2004, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 /*
@@ -12,6 +12,7 @@
 #include <asn_internal.h>
 #include <NativeReal.h>
 #include <REAL.h>
+#include <OCTET_STRING.h>
 
 /*
  * NativeReal basic type description.
@@ -29,7 +30,8 @@
 	NativeReal_encode_der,
 	NativeReal_decode_xer,
 	NativeReal_encode_xer,
-	0, 0,
+	NativeReal_decode_uper,
+	NativeReal_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NativeReal_tags,
 	sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
@@ -157,7 +159,74 @@
 	return erval;
 }
 
+/*
+ * Decode REAL type using PER.
+ */
+asn_dec_rval_t
+NativeReal_decode_uper(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_uper(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.
+ */
+asn_enc_rval_t
+NativeReal_encode_uper(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_uper(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 1f5266c..68a81d9 100644
--- a/skeletons/NativeReal.h
+++ b/skeletons/NativeReal.h
@@ -6,7 +6,7 @@
  * This type differs from the standard REAL in that it is modelled using
  * the fixed machine type (double), so it can hold only values of
  * limited precision. There is no explicit type (i.e., NativeReal_t).
- * Use of this type is normally enabled by -fnative-integers.
+ * Use of this type is normally enabled by -fnative-types.
  */
 #ifndef	ASN_TYPE_NativeReal_H
 #define	ASN_TYPE_NativeReal_H
@@ -25,6 +25,8 @@
 der_type_encoder_f NativeReal_encode_der;
 xer_type_decoder_f NativeReal_decode_xer;
 xer_type_encoder_f NativeReal_encode_xer;
+per_type_decoder_f NativeReal_decode_uper;
+per_type_encoder_f NativeReal_encode_uper;
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c
index cef64ea..7c4cc95 100644
--- a/skeletons/NumericString.c
+++ b/skeletons/NumericString.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
@@ -12,6 +12,31 @@
 	(ASN_TAG_CLASS_UNIVERSAL | (18 << 2)),	/* [UNIVERSAL 18] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
+static int asn_DEF_NumericString_v2c(unsigned int value) {
+	switch(value) {
+	case 0x20: return 0;
+	case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+	case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+		return value - (0x30 - 1);
+	}
+	return -1;
+}
+static int asn_DEF_NumericString_c2v(unsigned int code) {
+	if(code > 0) {
+		if(code <= 10)
+			return code + (0x30 - 1);
+		else
+			return -1;
+	} else {
+		return 0x20;
+	}
+}
+static asn_per_constraints_t asn_DEF_NumericString_constraints = {
+	{ APC_CONSTRAINED, 4, 4, 0x20, 0x39 },	/* Value */
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },	/* Size */
+	asn_DEF_NumericString_v2c,
+	asn_DEF_NumericString_c2v
+};
 asn_TYPE_descriptor_t asn_DEF_NumericString = {
 	"NumericString",
 	"NumericString",
@@ -22,7 +47,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_NumericString_tags,
 	sizeof(asn_DEF_NumericString_tags)
@@ -30,7 +56,7 @@
 	asn_DEF_NumericString_tags,
 	sizeof(asn_DEF_NumericString_tags)
 	  / sizeof(asn_DEF_NumericString_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_NumericString_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index b1666dc..9f6402e 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -4,6 +4,7 @@
  */
 #include <asn_internal.h>
 #include <OBJECT_IDENTIFIER.h>
+#include <OCTET_STRING.h>
 #include <limits.h>	/* for CHAR_BIT */
 #include <errno.h>
 
@@ -23,7 +24,8 @@
 	der_encode_primitive,
 	OBJECT_IDENTIFIER_decode_xer,
 	OBJECT_IDENTIFIER_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	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 3a83bd9..a9747c4 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -1197,6 +1197,93 @@
 		OCTET_STRING__convert_entrefs);
 }
 
+static int
+OCTET_STRING_per_get_expanded(asn_per_data_t *po, uint8_t *buf,
+		size_t size, long lb, long ub, int (*code2value)(unsigned int),
+		int unit_bits) {
+	uint8_t *end = buf + size;
+
+	ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d",
+		(int)size, lb, ub, unit_bits);
+
+	/* X.691: 27.5.4 */
+	if(ub <= (2 << (unit_bits - 1))) {
+		/* Decode without translation */
+		lb = 0;
+	} else if(code2value) {
+		for(; buf < end; buf++) {
+			int code = per_get_few_bits(po, unit_bits);
+			int value;
+			if(code < 0) return -1;	/* WMORE */
+			value = code2value(code);
+			if(value < 0) {
+				ASN_DEBUG("Code %d (0x%02x) is"
+					" not in map (%ld..%ld)",
+					code, code, lb, ub);
+				return 1;	/* FATAL */
+			}
+			*buf = value;
+		}
+		return 0;
+	}
+
+	for(; buf < end; buf++) {
+		int code = per_get_few_bits(po, unit_bits);
+		int ch = code + lb;
+		if(code < 0) return -1;	/* WMORE */
+		if(ch > ub) {
+			ASN_DEBUG("Code %d is out of range (%ld..%ld)",
+				ch, lb, ub);
+			return 1;	/* FATAL */
+		}
+		*buf = ch;
+	}
+
+	return 0;
+}
+
+static int
+OCTET_STRING_per_put_squeezed(asn_per_outp_t *po, const uint8_t *buf,
+		size_t size, long lb, long ub, int (*value2code)(unsigned int),
+		int unit_bits) {
+	const uint8_t *end = buf + size;
+
+	ASN_DEBUG("Squeezing %d bytes into (%ld..%ld):%d",
+		(int)size, lb, ub, unit_bits);
+
+	/* X.691: 27.5.4 */
+	if(ub <= (2 << (unit_bits - 1))) {
+		/* Encode as is */
+		lb = 0;
+	} else if(value2code) {
+		for(; buf < end; buf++) {
+			int code = value2code(*buf);
+			if(code < 0) {
+				ASN_DEBUG("Character %d (0x%02x) is"
+					" not in map (%ld..%ld)",
+					*buf, *buf, lb, ub);
+				return -1;
+			}
+			if(per_put_few_bits(po, code, unit_bits))
+				return -1;
+		}
+	}
+
+	for(ub -= lb; buf < end; buf++) {
+		int ch = *buf - lb;
+		if(ch < 0 || ch > ub) {
+			ASN_DEBUG("Character %d (0x%02x)"
+			" is out of range (%ld..%ld)",
+				*buf, *buf, lb, ub + lb);
+			return -1;
+		}
+		if(per_put_few_bits(po, ch, unit_bits))
+			return -1;
+	}
+
+	return 0;
+}
+
 asn_dec_rval_t
 OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
 	asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
@@ -1205,15 +1292,17 @@
 	asn_OCTET_STRING_specifics_t *specs = td->specifics
 		? (asn_OCTET_STRING_specifics_t *)td->specifics
 		: &asn_DEF_OCTET_STRING_specs;
-	asn_per_constraint_t *ct = constraints ? &constraints->size
-				: (td->per_constraints
-					? &td->per_constraints->size
-					: &asn_DEF_OCTET_STRING_constraint);
+	asn_per_constraints_t *pc = constraints ? constraints
+				: td->per_constraints;
+	asn_per_constraint_t *cv = pc ? &pc->value : 0;
+	asn_per_constraint_t *ct = pc ? &pc->size
+					: &asn_DEF_OCTET_STRING_constraint;
 	asn_dec_rval_t rval = { RC_OK, 0 };
 	BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
 	ssize_t consumed_myself = 0;
 	int repeat;
 	int unit_bits = (specs->subvariant != 1) * 7 + 1;
+	int expand = 0;
 
 	(void)opt_codec_ctx;
 
@@ -1225,8 +1314,13 @@
 		if(!st) RETURN(RC_FAIL);
 	}
 
-	ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d",
-		ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed",
+	if(cv && (cv->flags & APC_CONSTRAINED)) {
+		unit_bits = cv->range_bits;
+		if(unit_bits != 8) expand = 1;
+	}
+
+	ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",
+		ct->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
 		ct->lower_bound, ct->upper_bound, ct->effective_bits);
 
 	if(ct->flags & APC_EXTENSIBLE) {
@@ -1252,8 +1346,17 @@
 	/* 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(ct->effective_bits == 0) {
-		int ret = per_get_many_bits(pd, st->buf, 0,
+		int ret;
+		if(expand) {
+			ret = OCTET_STRING_per_get_expanded(pd, st->buf,
+				cv->upper_bound,
+				cv->lower_bound, cv->upper_bound,
+				pc->code2value, unit_bits);
+			if(ret > 0) RETURN(RC_FAIL);
+		} else {
+			ret = per_get_many_bits(pd, st->buf, 0,
 					    unit_bits * ct->upper_bound);
+		}
 		if(ret < 0) RETURN(RC_WMORE);
 		consumed_myself += unit_bits * ct->upper_bound;
 		st->buf[st->size] = 0;
@@ -1277,7 +1380,7 @@
 		ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
 			(long)ct->effective_bits, (long)len_bits,
 			repeat ? "repeat" : "once", td->name);
-		if(unit_bits == 1) {
+		if(unit_bits == 1 && !expand) {
 			len_bytes = (len_bits + 7) >> 3;
 			if(len_bits & 0x7)
 				st->bits_unused = 8 - (len_bits & 0x7);
@@ -1290,7 +1393,16 @@
 		if(!p) RETURN(RC_FAIL);
 		st->buf = (uint8_t *)p;
 
-		ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits);
+		if(expand) {
+			ret = OCTET_STRING_per_get_expanded(pd,
+				&st->buf[st->size], len_bytes,
+				cv->lower_bound, cv->upper_bound,
+				pc->code2value, unit_bits);
+			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);
@@ -1306,17 +1418,19 @@
 	asn_OCTET_STRING_specifics_t *specs = td->specifics
 		? (asn_OCTET_STRING_specifics_t *)td->specifics
 		: &asn_DEF_OCTET_STRING_specs;
-	asn_per_constraint_t *ct = constraints ? &constraints->size
-				: (td->per_constraints
-					? &td->per_constraints->size
-					: &asn_DEF_OCTET_STRING_constraint);
+	asn_per_constraints_t *pc = constraints ? constraints
+				: td->per_constraints;
+	asn_per_constraint_t *cv = pc ? &pc->value : 0;
+	asn_per_constraint_t *ct = pc ? &pc->size
+					: &asn_DEF_OCTET_STRING_constraint;
 	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
-	int unit_bits = (specs->subvariant != 1) * 7 + 1;
 	asn_enc_rval_t er;
 	int ct_extensible = ct->flags & APC_EXTENSIBLE;
 	int inext = 0;		/* Lies not within extension root */
+	int unit_bits = (specs->subvariant != 1) * 7 + 1;
 	int sizeinunits = st->size;
 	const uint8_t *buf;
+	int squeeze = 0;
 	int ret;
 
 	if(!st || !st->buf)
@@ -1328,13 +1442,18 @@
 		sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07);
 	}
 
+	if(cv && (cv->flags & APC_CONSTRAINED)) {
+		unit_bits = cv->range_bits;
+		if(unit_bits != 8) squeeze = 1;
+	}
+
 	ASN_DEBUG("Encoding %s into %d units of %d bits"
-		" (%d..%d, effective %d)%s",
+		" (%ld..%ld, effective %d)%s",
 		td->name, sizeinunits, unit_bits,
 		ct->lower_bound, ct->upper_bound,
 		ct->effective_bits, ct_extensible ? " EXT" : "");
 
-	/* Figure out wheter size lies within PER visible consrtaint */
+	/* Figure out wheter size lies within PER visible constraint */
 
 	if(ct->effective_bits >= 0) {
 		if(sizeinunits < ct->lower_bound
@@ -1365,7 +1484,14 @@
 		ret = per_put_few_bits(po, sizeinunits - ct->lower_bound,
 				ct->effective_bits);
 		if(ret) _ASN_ENCODE_FAILED;
-		ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits);
+		if(squeeze) {
+			ret = OCTET_STRING_per_put_squeezed(po, st->buf,
+				sizeinunits, cv->lower_bound, cv->upper_bound,
+				pc->value2code, unit_bits);
+		} else {
+			ret = per_put_many_bits(po, st->buf,
+				sizeinunits * unit_bits);
+		}
 		if(ret) _ASN_ENCODE_FAILED;
 		_ASN_ENCODED_OK(er);
 	}
@@ -1385,10 +1511,16 @@
 
 		ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits);
 
-		ret = per_put_many_bits(po, buf, maySave * unit_bits);
+		if(squeeze) {
+			ret = OCTET_STRING_per_put_squeezed(po, buf,
+				maySave, cv->lower_bound, cv->upper_bound,
+				pc->value2code, unit_bits);
+		} else {
+			ret = per_put_many_bits(po, buf, maySave * unit_bits);
+		}
 		if(ret) _ASN_ENCODE_FAILED;
 
-		if(unit_bits == 1)
+		if(unit_bits == 1 && !squeeze)
 			buf += maySave >> 3;
 		else
 			buf += maySave;
diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c
index 44cb5f6..cd8e8a3 100644
--- a/skeletons/ObjectDescriptor.c
+++ b/skeletons/ObjectDescriptor.c
@@ -22,7 +22,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	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 f588083..318bff1 100644
--- a/skeletons/PrintableString.c
+++ b/skeletons/PrintableString.c
@@ -1,17 +1,52 @@
 /*-
- * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004, 2006 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
 #include <PrintableString.h>
 
 /*
+ * ASN.1:1984 (X.409)
+ */
+static int _PrintableString_alphabet[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*                  */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*                  */
+ 1, 0, 0, 0, 0, 0, 0, 2, 3, 4, 0, 5, 6, 7, 8, 9,	/* .      '() +,-./ */
+10,11,12,13,14,15,16,17,18,19,20, 0, 0,21, 0,22,	/* 0123456789:  = ? */
+ 0,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,	/*  ABCDEFGHIJKLMNO */
+38,39,40,41,42,43,44,45,46,47,48, 0, 0, 0, 0, 0,	/* PQRSTUVWXYZ      */
+ 0,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,	/*  abcdefghijklmno */
+64,65,66,67,68,69,70,71,72,73,74, 0, 0, 0, 0, 0,	/* pqrstuvwxyz      */
+};
+static int _PrintableString_code2value[74] = { 
+32,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,
+55,56,57,58,61,63,65,66,67,68,69,70,71,72,73,74,
+75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,
+97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
+113,114,115,116,117,118,119,120,121,122};
+
+/*
  * PrintableString basic type description.
  */
 static ber_tlv_tag_t asn_DEF_PrintableString_tags[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (19 << 2)),	/* [UNIVERSAL 19] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
+static int asn_DEF_PrintableString_v2c(unsigned int value) {
+	return _PrintableString_alphabet[value > 255 ? 0 : value] - 1;
+}
+static int asn_DEF_PrintableString_c2v(unsigned int code) {
+	if(code < 74)
+		return _PrintableString_code2value[code];
+	return -1;
+}
+static asn_per_constraints_t asn_DEF_PrintableString_constraints = {
+	{ APC_CONSTRAINED, 4, 4, 0x20, 0x39 },	/* Value */
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },	/* Size */
+	asn_DEF_PrintableString_v2c,
+	asn_DEF_PrintableString_c2v
+};
 asn_TYPE_descriptor_t asn_DEF_PrintableString = {
 	"PrintableString",
 	"PrintableString",
@@ -22,7 +57,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_PrintableString_tags,
 	sizeof(asn_DEF_PrintableString_tags)
@@ -30,34 +66,12 @@
 	asn_DEF_PrintableString_tags,
 	sizeof(asn_DEF_PrintableString_tags)
 	  / sizeof(asn_DEF_PrintableString_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_PrintableString_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
 
-/*
- * ASN.1:1984 (X.409)
- */
-static int _PrintableString_alphabet[256] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 	/*               ' */
-0x41, 0x42, 0x00, 0x43, 0x44, 0x45, 0x46, 0x47, 	/* ( )   + , - . / */
-0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 	/* 0 1 2 3 4 5 6 7 */
-0x3d, 0x3e, 0x48, 0x00, 0x00, 0x49, 0x00, 0x4a, 	/* 8 9 :     =   ? */
-0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 	/*   A B C D E F G */
-0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 	/* H I J K L M N O */
-0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 	/* P Q R S T U V W */
-0x18, 0x19, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 	/* X Y Z           */
-0x00, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 	/*   a b c d e f g */
-0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 	/* h i j k l m n o */
-0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 	/* p q r s t u v w */
-0x32, 0x33, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 	/* x y z           */
-};
-
 int
 PrintableString_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 		asn_app_constraint_failed_f *ctfailcb, void *app_key) {
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index 51098c0..32f9221 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2004, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #if	defined(__alpha)
@@ -12,6 +12,7 @@
 #include <math.h>
 #include <errno.h>
 #include <REAL.h>
+#include <OCTET_STRING.h>
 
 #undef	INT_MAX
 #define	INT_MAX	((int)(((unsigned int)-1) >> 1))
@@ -42,7 +43,8 @@
 	der_encode_primitive,
 	REAL_decode_xer,
 	REAL_encode_xer,
-	0, 0,
+	REAL_decode_uper,
+	REAL_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_REAL_tags,
 	sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]),
@@ -341,6 +343,20 @@
 		buf_ptr, size, REAL__xer_body_decode);
 }
 
+asn_dec_rval_t
+REAL_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) {
+	(void)constraints;	/* No PER visible constraints */
+	return OCTET_STRING_decode_uper(opt_codec_ctx, td, 0, sptr, pd);
+}
+
+asn_enc_rval_t
+REAL_encode_uper(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_uper(td, 0, sptr, po);
+}
 
 int
 asn_REAL2double(const REAL_t *st, double *dbl_value) {
diff --git a/skeletons/REAL.h b/skeletons/REAL.h
index 28ccf28..af3e84c 100644
--- a/skeletons/REAL.h
+++ b/skeletons/REAL.h
@@ -19,6 +19,8 @@
 asn_struct_print_f REAL_print;
 xer_type_decoder_f REAL_decode_xer;
 xer_type_encoder_f REAL_encode_xer;
+per_type_decoder_f REAL_decode_uper;
+per_type_encoder_f REAL_encode_uper;
 
 /***********************************
  * Some handy conversion routines. *
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index 0181434..983fc09 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -5,6 +5,7 @@
  */
 #include <asn_internal.h>
 #include <RELATIVE-OID.h>
+#include <OCTET_STRING.h>
 #include <asn_codecs_prim.h>	/* Encoder and decoder of a primitive type */
 #include <limits.h>	/* for CHAR_BIT */
 #include <errno.h>
@@ -25,7 +26,8 @@
 	der_encode_primitive,
 	RELATIVE_OID_decode_xer,
 	RELATIVE_OID_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	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 25d887a..98461bb 100644
--- a/skeletons/T61String.c
+++ b/skeletons/T61String.c
@@ -22,7 +22,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_hex,
 	OCTET_STRING_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	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 b96cb3b..81e646b 100644
--- a/skeletons/TeletexString.c
+++ b/skeletons/TeletexString.c
@@ -22,7 +22,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_hex,
 	OCTET_STRING_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	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 2a27718..41a31dd 100644
--- a/skeletons/UTCTime.c
+++ b/skeletons/UTCTime.c
@@ -23,6 +23,11 @@
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),  /* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))    /* ... OCTET STRING */
 };
+static asn_per_constraints_t asn_DEF_UTCTime_constraints = {
+        { APC_CONSTRAINED, 7, 7, 0x20, 0x7e },  /* Value */
+        { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */
+        0, 0
+};
 asn_TYPE_descriptor_t asn_DEF_UTCTime = {
 	"UTCTime",
 	"UTCTime",
@@ -33,7 +38,8 @@
 	OCTET_STRING_encode_der,    /* Implemented in terms of OCTET STRING */
 	OCTET_STRING_decode_xer_utf8,
 	UTCTime_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UTCTime_tags,
 	sizeof(asn_DEF_UTCTime_tags)
@@ -41,7 +47,7 @@
 	asn_DEF_UTCTime_tags,
 	sizeof(asn_DEF_UTCTime_tags)
 	  / sizeof(asn_DEF_UTCTime_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_UTCTime_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
diff --git a/skeletons/UTF8String.c b/skeletons/UTF8String.c
index e3f7388..1e84815 100644
--- a/skeletons/UTF8String.c
+++ b/skeletons/UTF8String.c
@@ -23,7 +23,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_UTF8String_tags,
 	sizeof(asn_DEF_UTF8String_tags)
diff --git a/skeletons/VideotexString.c b/skeletons/VideotexString.c
index 5f5f33d..df7233e 100644
--- a/skeletons/VideotexString.c
+++ b/skeletons/VideotexString.c
@@ -22,7 +22,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_hex,
 	OCTET_STRING_encode_xer,
-	0, 0,
+	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_uper,
 	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 8796582..49a94c1 100644
--- a/skeletons/VisibleString.c
+++ b/skeletons/VisibleString.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
@@ -12,6 +12,11 @@
 	(ASN_TAG_CLASS_UNIVERSAL | (26 << 2)),	/* [UNIVERSAL 26] IMPLICIT ...*/
 	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
 };
+static asn_per_constraints_t asn_DEF_VisibleString_constraints = {
+	{ APC_CONSTRAINED, 7, 7, 0x20, 0x7e },	/* Value */
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },	/* Size */
+	0, 0
+};
 asn_TYPE_descriptor_t asn_DEF_VisibleString = {
 	"VisibleString",
 	"VisibleString",
@@ -22,7 +27,8 @@
 	OCTET_STRING_encode_der,
 	OCTET_STRING_decode_xer_utf8,
 	OCTET_STRING_encode_xer_utf8,
-	0, 0,
+	OCTET_STRING_decode_uper,
+	OCTET_STRING_encode_uper,
 	0, /* Use generic outmost tag fetcher */
 	asn_DEF_VisibleString_tags,
 	sizeof(asn_DEF_VisibleString_tags)
@@ -30,7 +36,7 @@
 	asn_DEF_VisibleString_tags,
 	sizeof(asn_DEF_VisibleString_tags)
 	  / sizeof(asn_DEF_VisibleString_tags[0]),
-	0,	/* No PER visible constraints */
+	&asn_DEF_VisibleString_constraints,
 	0, 0,	/* No members */
 	0	/* No specifics */
 };
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index 09f27db..96d2ae8 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -921,7 +921,7 @@
 				ASN_DEBUG("Failed to add element into %s",
 					td->name);
 				/* Fall through */
-				rv.code == RC_FAIL;
+				rv.code = RC_FAIL;
 			} else {
 				ASN_DEBUG("Failed decoding %s of %s (SET OF)",
 					elm->type->name, td->name);
diff --git a/skeletons/per_support.h b/skeletons/per_support.h
index 420bb83..2708724 100644
--- a/skeletons/per_support.h
+++ b/skeletons/per_support.h
@@ -29,6 +29,8 @@
 typedef struct asn_per_constraints_s {
 	asn_per_constraint_t value;
 	asn_per_constraint_t size;
+	int (*value2code)(unsigned int value);
+	int (*code2value)(unsigned int code);
 } asn_per_constraints_t;
 
 /*
diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c
index 4d4c9b5..b7fafe0 100644
--- a/skeletons/tests/check-OIDs.c
+++ b/skeletons/tests/check-OIDs.c
@@ -442,3 +442,7 @@
 
 	return 0;
 }
+
+asn_dec_rval_t OCTET_STRING_decode_uper(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_uper(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; }
diff --git a/skeletons/tests/check-REAL.c b/skeletons/tests/check-REAL.c
index 641da2d..3a868aa 100644
--- a/skeletons/tests/check-REAL.c
+++ b/skeletons/tests/check-REAL.c
@@ -286,3 +286,7 @@
 
 	return 0;
 }
+
+asn_dec_rval_t OCTET_STRING_decode_uper(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_uper(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; }