introducing less strict semantics

diff --git a/libasn1fix/asn1fix_constraint_compat.c b/libasn1fix/asn1fix_constraint_compat.c
index f2f47fd..effa0ad 100644
--- a/libasn1fix/asn1fix_constraint_compat.c
+++ b/libasn1fix/asn1fix_constraint_compat.c
@@ -88,17 +88,21 @@
 }
 
 
-#define	DECL(foo, val1, val2)					\
+#define	DECL_RANGE(foo, val1, val2, pv)				\
 	static asn1cnst_range_t range_ ## foo = {		\
 			{ ARE_VALUE, 0, val1 },			\
 			{ ARE_VALUE, 0, val2 },			\
-			0, 0, 0, 0, 0, 0 }
+			0, 0, 0, 0, 0, 0, pv }
+
+#define	DECL(foo, val1, val2)		DECL_RANGE(foo, val1, val2, 0)
+#define	DECL_notPV(foo, val1, val2)	DECL_RANGE(foo, val1, val2, 1)
 
 asn1cnst_range_t *
 asn1constraint_default_alphabet(asn1p_expr_type_e expr_type) {
+	DECL_notPV(octstr,	0x00, 0xff);	/* Not PER-visible */
+	DECL_notPV(utf8,	0x00, 0x7fffffff);	/* Not PER-visible */
+	DECL(bmp,	0x00, 65533);	/* 64K-2 cells */
 	DECL(uint7,	0x00, 0x7f);
-	DECL(uint8,	0x00, 0xff);
-	DECL(uint16,	0x00, 0xffff);
 	DECL(uint31,	0x00, 0x7fffffff);
 	DECL(Space,	0x20, 0x20);
 	DECL(ApostropheAndParens, 0x27, 0x29);
@@ -127,38 +131,43 @@
 			&range_Plus, &range_MinusDot, &range_Digits, &range_Z };
 	static asn1cnst_range_t *range_GeneralizedTime_array[] = {
 			&range_PlusCommaMinusDot, &range_Digits, &range_Z };
+
+	static asn1cnst_range_t range_notPERVisible = {
+			{ ARE_MIN, 0, 0 },
+			{ ARE_MAX, 0, 0 },
+			0, 0, 0, 0, 0, 0, 1 };
 	static asn1cnst_range_t range_NumericString = {
 			{ ARE_VALUE, 0, 0x20 },
 			{ ARE_VALUE, 0, 0x39 },
 			range_NumericString_array,
 			sizeof(range_NumericString_array)
 				/sizeof(range_NumericString_array[0]),
-			0, 0, 0, 0 };
+			0, 0, 0, 0, 0 };
 	static asn1cnst_range_t range_PrintableString = {
 			{ ARE_VALUE, 0, 0x20 },
 			{ ARE_VALUE, 0, 0x7a },
 			range_PrintableString_array,
 			sizeof(range_PrintableString_array)
 				/sizeof(range_PrintableString_array[0]),
-			0, 0, 0, 0 };
+			0, 0, 0, 0, 0 };
 	static asn1cnst_range_t range_VisibleString = {
 			{ ARE_VALUE, 0, 0x20 },
 			{ ARE_VALUE, 0, 0x7e },
-			0, 0, 0, 0, 0, 0 };
+			0, 0, 0, 0, 0, 0, 0 };
 	static asn1cnst_range_t range_UTCTime = {
 			{ ARE_VALUE, 0, 0x2b },
 			{ ARE_VALUE, 0, 0x5a },
 			range_UTCTime_array,
 			sizeof(range_UTCTime_array)
 				/sizeof(range_UTCTime_array[0]),
-			0, 0, 0, 0 };
+			0, 0, 0, 0, 1 };
 	static asn1cnst_range_t range_GeneralizedTime = {
 			{ ARE_VALUE, 0, 0x2b },
 			{ ARE_VALUE, 0, 0x5a },
 			range_GeneralizedTime_array,
 			sizeof(range_GeneralizedTime_array)
 				/sizeof(range_GeneralizedTime_array[0]),
-			0, 0, 0, 0 };
+			0, 0, 0, 0, 1 };
 
 	switch(expr_type) {
 	case ASN_STRING_NumericString:
@@ -169,19 +178,42 @@
 		return &range_VisibleString;
 	case ASN_STRING_IA5String:
 		return &range_uint7;
-	case ASN_BASIC_OCTET_STRING:
-		return &range_uint8;
 	case ASN_STRING_BMPString:
-		return &range_uint16;
-	case ASN_STRING_UniversalString:
+		return &range_bmp;
 	case ASN_STRING_UTF8String:
+		/*
+		 * X.691, #9.3.6
+		 * Not a known-multipler character string type.
+		 */
+		assert(range_utf8.not_PER_visible);
+		return &range_utf8;
+	case ASN_STRING_UniversalString:
 		return &range_uint31;
 	case ASN_BASIC_UTCTime:
+		/* Permitted alphabet constraint is not applicable */
+		assert(range_UTCTime.not_PER_visible);
 		return &range_UTCTime;
 	case ASN_BASIC_GeneralizedTime:
+		/* Permitted alphabet constraint is not applicable */
+		assert(range_GeneralizedTime.not_PER_visible);
 		return &range_GeneralizedTime;
+	case ASN_BASIC_OCTET_STRING:
+		/*
+		 * Permitted alphabet constraint is not applicable
+		 * to this type. However, we support it, albeit not
+		 * in a strict PER mode.
+		 */
+		assert(range_octstr.not_PER_visible);
+		return &range_octstr;
 	default:
-		break;
+		if(!(expr_type & ASN_STRING_MASK))
+			break;
+		assert(expr_type & ASN_STRING_NKM_MASK);
+		/*
+		 * X.691, 9.3.6
+		 * Not a known-multiplier character string.
+		 */
+		return &range_notPERVisible;
 	}
 
 	return NULL;