optionality handling
diff --git a/ChangeLog b/ChangeLog
index eb8c8da..56273dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,5 @@
 
-0.9.22:	2007-Jun-23
+0.9.22:	2007-Jun-26
 
 	* Added -pdu=all and -pdu=<type> switches to asn1c.
 	* Added PER support for most known-multiplier string types:
@@ -15,6 +15,7 @@
 	  is encountered. (Severity: medium; Security impact: low)
 	* Fixed extensibility handling of second SEQUENCE production.
 	  (Severity: low; Security impact: none)
+	* Added DEFAULT handling for known multiplier string.
 
 0.9.21:	2006-Sep-17
 
diff --git a/asn1c/tests/check-126.-gen-PER.c b/asn1c/tests/check-126.-gen-PER.c
index 8b590b1..6a8e866 100644
--- a/asn1c/tests/check-126.-gen-PER.c
+++ b/asn1c/tests/check-126.-gen-PER.c
@@ -288,7 +288,10 @@
 	fwrite(buf, 1, buf_offset, stderr);
 	fprintf(stderr, "=== end ===\n");
 
-	assert(xer_encoding_equal(fbuf, size, buf, buf_offset));
+	if(fname[strlen(fname) - 4] == 'X')
+		assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
+	else
+		assert(xer_encoding_equal(fbuf, size, buf, buf_offset));
 
 	asn_DEF_PDU.free_struct(&asn_DEF_PDU, st, 0);
 }
diff --git a/asn1c/tests/data-126/data-126-15.out b/asn1c/tests/data-126/data-126-15.out
index 3de8374..e278c6b 100644
--- a/asn1c/tests/data-126/data-126-15.out
+++ b/asn1c/tests/data-126/data-126-15.out
Binary files differ
diff --git a/asn1c/tests/data-126/data-126-16.out b/asn1c/tests/data-126/data-126-16.out
index 8837192..bebf853 100644
--- a/asn1c/tests/data-126/data-126-16.out
+++ b/asn1c/tests/data-126/data-126-16.out
Binary files differ
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index d8aa01f..ef0c868 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -2057,6 +2057,35 @@
 }
 
 static int
+safe_string(const uint8_t *buf, int size) {
+	const uint8_t *end = buf + size;
+	for(; buf < end; buf++) {
+		int ch = *buf;
+		if((ch < 0x20 || ch > 0x7e) || ch == '"')
+			return 0;
+	}
+	return 1;
+}
+
+static void
+emit_default_value(arg_t *arg, asn1p_value_t *v) {
+
+	OUT("static uint8_t defv[] = ");
+	assert(v->type == ATV_STRING);
+
+	if(safe_string(v->value.string.buf, v->value.string.size)) {
+		OUT("\"%s\";\n", v->value.string.buf);
+	} else {
+		uint8_t *b = v->value.string.buf;
+		uint8_t *e = v->value.string.size + b;
+		OUT("{ ");
+		for(;b < e; b++)
+			OUT("0x%02x, ", *b);
+		OUT("0 };\n");
+	}
+}
+
+static int
 try_inline_default(arg_t *arg, asn1p_expr_t *expr, int out) {
 	int save_target = arg->target->target;
 	asn1p_expr_type_e etype = expr_get_type(arg, expr);
@@ -2074,7 +2103,14 @@
 			fits_long = asn1c_type_fits_long(arg, expr)!=FL_NOTFIT;
 		if(fits_long && !expr->marker.default_value->value.v_integer)
 			expr->marker.flags &= ~EM_INDIRECT;
-		if(!out) return 1;
+		if(!out) {
+			OUT("asn_DFL_%d_set_%" PRIdASN
+				",\t/* DEFAULT %" PRIdASN " */\n",
+				expr->_type_unique_index,
+				expr->marker.default_value->value.v_integer,
+				expr->marker.default_value->value.v_integer);
+			return 1;
+		}
 		REDIR(OT_STAT_DEFS);
 		OUT("static int asn_DFL_%d_set_%" PRIdASN "(int set_value, void **sptr) {\n",
 			expr->_type_unique_index,
@@ -2125,7 +2161,52 @@
 		//expr->marker.flags &= ~EM_INDIRECT;
 		return 0;
 	default:
-		break;
+	  if(etype & ASN_STRING_KM_MASK) {
+		if(expr->marker.default_value == NULL
+		|| expr->marker.default_value->type != ATV_STRING)
+			break;
+		if(!out) {
+			OUT("asn_DFL_%d_set,\t/* DEFAULT \"%s\" */\n",
+				expr->_type_unique_index,
+				expr->marker.default_value->value.string.buf);
+			return 1;
+		}
+		REDIR(OT_STAT_DEFS);
+		OUT("static int asn_DFL_%d_set(int set_value, void **sptr) {\n", expr->_type_unique_index);
+		INDENT(+1);
+		emit_default_value(arg, expr->marker.default_value);
+		OUT("%s *st = *sptr;\n", asn1c_type_name(arg, expr, TNF_CTYPE));
+		OUT("\n");
+		OUT("if(!st) {\n");
+		OUT("\tif(!set_value) return -1;\t/* Not a default value */\n");
+		OUT("\tst = (*sptr = CALLOC(1, sizeof(*st)));\n");
+		OUT("\tif(!st) return -1;\n");
+		OUT("}\n");
+		OUT("\n");
+		OUT("if(set_value) {\n");
+		INDENT(+1);
+			OUT("uint8_t *ptr = MALLOC(sizeof(defv));\n");
+			OUT("if(!ptr) return -1;\n");
+			OUT("memcpy(ptr, &defv, sizeof(defv));\n");
+			OUT("FREEMEM(st->buf);\n");
+			OUT("st->buf = ptr;\n");
+			OUT("st->size = sizeof(defv) - 1;\n");
+			OUT("return 0;\n");
+		INDENT(-1);
+		OUT("} else {\n");
+		INDENT(+1);
+			OUT("if(st->size != (sizeof(defv) - 1)\n");
+			OUT("|| memcmp(st->buf, &defv, sizeof(defv) - 1))\n");
+			OUT("\treturn 0;\n");
+			OUT("return 1;\n");
+		INDENT(-1);
+		OUT("}\n"); OUT("\n");
+		INDENT(-1);
+		OUT("}\n");
+		REDIR(save_target);
+		return 1;
+	  }
+	  break;
 	}
 	return 0;
 }
@@ -2247,11 +2328,6 @@
 	}
 	if(C99_MODE) OUT(".default_value = ");
 	if(try_inline_default(arg, expr, 0)) {
-		OUT("asn_DFL_%d_set_%" PRIdASN
-				",\t/* DEFAULT %" PRIdASN " */\n",
-			expr->_type_unique_index,
-			expr->marker.default_value->value.v_integer,
-			expr->marker.default_value->value.v_integer);
 	} else {
 		OUT("0,\n");
 	}
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index c824c04..f82ebc6 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -1337,6 +1337,7 @@
 						FREEMEM(opres);
 						_ASN_DECODE_FAILED;
 					}
+					ASN_DEBUG("Filled-in default");
 				}
 				/* The member is just not present */
 				continue;
@@ -1612,8 +1613,11 @@
 		}
 
 		/* Eliminate default values */
-		if(elm->default_value && elm->default_value(0, memb_ptr2) == 1)
+		ASN_DEBUG("Defv %p mptr %p\n", elm->default_value, memb_ptr2);
+		ASN_DEBUG("Do not encode default: %s\n", (*(char **)(*memb_ptr2)));
+		if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) {
 			continue;
+		}
 
 		er = elm->type->uper_encoder(elm->type, elm->per_constraints,
 			*memb_ptr2, po);
diff --git a/tests/126-per-extensions-OK.asn1.-Pgen-PER b/tests/126-per-extensions-OK.asn1.-Pgen-PER
index 7f7626a..326a705 100644
--- a/tests/126-per-extensions-OK.asn1.-Pgen-PER
+++ b/tests/126-per-extensions-OK.asn1.-Pgen-PER
@@ -140,6 +140,32 @@
 
 /*** <<< STAT-DEFS [Singleton] >>> ***/
 
+static int asn_DFL_2_set(int set_value, void **sptr) {
+	static uint8_t defv[] = "z";
+	IA5String_t *st = *sptr;
+	
+	if(!st) {
+		if(!set_value) return -1;	/* Not a default value */
+		st = (*sptr = CALLOC(1, sizeof(*st)));
+		if(!st) return -1;
+	}
+	
+	if(set_value) {
+		uint8_t *ptr = MALLOC(sizeof(defv));
+		if(!ptr) return -1;
+		memcpy(ptr, &defv, sizeof(defv));
+		FREEMEM(st->buf);
+		st->buf = ptr;
+		st->size = sizeof(defv) - 1;
+		return 0;
+	} else {
+		if(st->size != (sizeof(defv) - 1)
+		|| memcmp(st->buf, &defv, sizeof(defv) - 1))
+			return 0;
+		return 1;
+	}
+	
+}
 static asn_TYPE_member_t asn_MBR_Singleton_1[] = {
 	{ ATF_POINTER, 1, offsetof(struct Singleton, opt_z),
 		.tag = (ASN_TAG_CLASS_CONTEXT | (0 << 2)),
@@ -147,7 +173,7 @@
 		.type = &asn_DEF_IA5String,
 		.memb_constraints = 0,	/* Defer constraints checking to the member type */
 		.per_constraints = 0,	/* No PER visible constraints */
-		.default_value = 0,
+		.default_value = asn_DFL_2_set,	/* DEFAULT "z" */
 		.name = "opt-z"
 		},
 };