upgrade: PER related changes


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@1011 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index bd25b3d..251da39 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
@@ -356,7 +357,7 @@
 
 	if(!cb) {
 		erval.encoded = computed_size;
-		return erval;
+		_ASN_ENCODED_OK(erval);
 	}
 
 	/*
@@ -448,7 +449,7 @@
 		erval.encoded = computed_size;
 	}
 
-	return erval;
+	_ASN_ENCODED_OK(erval);
 }
 
 #undef	XER_ADVANCE
@@ -748,7 +749,7 @@
 		}
 		free(encs);
 	}
-	return er;
+	_ASN_ENCODED_OK(er);
 }
 
 int
@@ -850,3 +851,88 @@
 
 	return 0;
 }
+
+asn_dec_rval_t
+SET_OF_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_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;
+
+	/*
+	 * 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_FAILED;
+		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);
+		ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s",
+			(long)nelems, ct->lower_bound, td->name);
+		if(nelems < 0)  _ASN_DECODE_FAILED;
+		nelems += ct->lower_bound;
+	} else {
+		nelems = -1;
+	}
+
+	do {
+		int i;
+		if(nelems < 0) {
+			nelems = uper_get_length(pd,
+				ct ? ct->effective_bits : -1, &repeat);
+			ASN_DEBUG("Got to decode %d elements (eff %d)",
+				nelems, ct ? ct->effective_bits : -1);
+			if(nelems < 0) _ASN_DECODE_FAILED;
+		}
+
+		for(i = 0; i < nelems; i++) {
+			void *ptr = 0;
+			ASN_DEBUG("SET OF %s decoding", elm->type->name);
+			rv = elm->type->uper_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 */
+			} else {
+				ASN_DEBUG("Failed decoding %s of %s (SET OF)",
+					elm->type->name, td->name);
+			}
+			if(ptr) elm->type->free_struct(elm->type, ptr, 0);
+			_ASN_DECODE_FAILED;
+		}
+
+		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;
+}
+