per_get_undo()

git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@1319 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index ec04992..4267d84 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -1078,7 +1078,6 @@
 	oldpd->nbits -= consumed;
 	oldpd->buffer = pd->buffer;
 	oldpd->nboff = pd->nboff;
-	oldpd->nboff = pd->nbits;
 
 	if(arg->unclaimed) {
 		/* Refill the container */
@@ -1091,6 +1090,7 @@
 		pd->buffer = oldpd->buffer;
 		pd->nboff = oldpd->nboff - 1;
 		pd->nbits = oldpd->nbits;
+		pd->moved = oldpd->moved - 1;
 		ASN_DEBUG("====================");
 		return 0;
 	}
@@ -1110,12 +1110,12 @@
 	pd->buffer = oldpd->buffer;
 	pd->nboff = oldpd->nboff;
 	pd->nbits = oldpd->nbits;
+	pd->moved = oldpd->moved;
 	next_chunk_bits = next_chunk_bytes << 3;
 	avail = pd->nbits - pd->nboff;
-	ASN_DEBUG("now at %d bits, want %d",
+	ASN_DEBUG("now at %d bits, want %d, avail %d",
 		((((int)pd->buffer ) & 0x7) << 3) + pd->nboff,
-		next_chunk_bits);
-	ASN_DEBUG("avail = %d", avail);
+		next_chunk_bits, avail);
 	if(avail >= next_chunk_bits) {
 		pd->nbits = pd->nboff + next_chunk_bits;
 		arg->unclaimed = 0;
diff --git a/skeletons/per_decoder.c b/skeletons/per_decoder.c
index 2e460da..4e120a4 100644
--- a/skeletons/per_decoder.c
+++ b/skeletons/per_decoder.c
@@ -47,6 +47,7 @@
 		/* Return the number of consumed bits */
 		rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3)
 					+ pd.nboff - skip_bits;
+		assert(rval.consumed == pd.moved);
 	} else {
 		/* PER codec is not a restartable */
 		rval.consumed = 0;
diff --git a/skeletons/per_support.c b/skeletons/per_support.c
index 228fd11..f38422a 100644
--- a/skeletons/per_support.c
+++ b/skeletons/per_support.c
@@ -6,13 +6,23 @@
 #include <asn_internal.h>
 #include <per_support.h>
 
+void
+per_get_undo(asn_per_data_t *pd, int nbits) {
+	if(pd->nboff < nbits) {
+		assert(pd->nboff < nbits);
+	} else {
+		pd->nboff -= nbits;
+		pd->moved -= nbits;
+	}
+}
+
 /*
  * Extract a small number of bits (<= 31) from the specified PER data pointer.
  */
 int32_t
 per_get_few_bits(asn_per_data_t *pd, int nbits) {
 	size_t off;	/* Next after last bit offset */
-	ssize_t nleft;
+	ssize_t nleft;	/* Number of bits left in this stream */
 	uint32_t accum;
 	const uint8_t *buf;
 
@@ -48,7 +58,9 @@
 		pd->nbits  -= (pd->nboff & ~0x07);
 		pd->nboff  &= 0x07;
 	}
-	off = (pd->nboff += nbits);
+	pd->moved += nbits;
+	pd->nboff += nbits;
+	off = pd->nboff;
 	buf = pd->buffer;
 
 	/*
@@ -66,11 +78,14 @@
 	else if(nbits <= 31) {
 		asn_per_data_t tpd = *pd;
 		/* Here are we with our 31-bits limit plus 1..7 bits offset. */
-		tpd.nboff -= nbits;
+		per_get_undo(&tpd, nbits);
+		/* The number of available bits in the stream allow
+		 * for the following operations to take place without
+		 * invoking the ->refill() function */
 		accum  = per_get_few_bits(&tpd, nbits - 24) << 24;
 		accum |= per_get_few_bits(&tpd, 24);
 	} else {
-		pd->nboff -= nbits;	/* Oops, revert back */
+		per_get_undo(pd, nbits);
 		return -1;
 	}
 
diff --git a/skeletons/per_support.h b/skeletons/per_support.h
index c22bc72..bf06f05 100644
--- a/skeletons/per_support.h
+++ b/skeletons/per_support.h
@@ -37,11 +37,12 @@
  * This structure describes a position inside an incoming PER bit stream.
  */
 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 */
-        int (*refill)(struct asn_per_data_s *);
-	void *refill_key;
+  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 */
+  int (*refill)(struct asn_per_data_s *);
+  void *refill_key;
 } asn_per_data_t;
 
 /*
@@ -51,6 +52,9 @@
  */
 int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits);
 
+/* Undo the immediately preceeding "get_few_bits" operation */
+void per_get_undo(asn_per_data_t *per_data, int get_nbits);
+
 /*
  * Extract a large number of bits from the specified PER data pointer.
  * This function returns -1 if the specified number of bits could not be