fix UPER decoding of large [bit-]strings of size a multiple of 16K
diff --git a/tests/tests-randomized/bundles/03-BIT-STRING-bundle.txt b/tests/tests-randomized/bundles/03-BIT-STRING-bundle.txt
index 2835b3c..f2d253e 100644
--- a/tests/tests-randomized/bundles/03-BIT-STRING-bundle.txt
+++ b/tests/tests-randomized/bundles/03-BIT-STRING-bundle.txt
@@ -17,3 +17,9 @@
 T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(31,...))
 T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..32))
 T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..31,...))
+T ::= BIT STRING { foo(0) } (SIZE(65535))       -- RMAX=65540
+T ::= BIT STRING { foo(0) } (SIZE(65536))       -- RMAX=65540
+T ::= BIT STRING { foo(0) } (SIZE(65537))       -- RMAX=65540
+T ::= BIT STRING { foo(0) } (SIZE(65535,...))   -- RMAX=65540
+T ::= BIT STRING { foo(0) } (SIZE(65536,...))   -- RMAX=65540
+T ::= BIT STRING { foo(0) } (SIZE(65537,...))   -- RMAX=65540
diff --git a/tests/tests-randomized/bundles/04-VisibleString-bundle.txt b/tests/tests-randomized/bundles/04-VisibleString-bundle.txt
index ec03664..55a658b 100644
--- a/tests/tests-randomized/bundles/04-VisibleString-bundle.txt
+++ b/tests/tests-randomized/bundles/04-VisibleString-bundle.txt
@@ -16,11 +16,12 @@
 T ::= VisibleString (SIZE(1..128))
 T ::= VisibleString (SIZE(1..129))
 T ::= VisibleString (SIZE(5) INTERSECTION FROM("A".."Z"))
-RMAX=64000 VisibleString (SIZE(64000))   -- Length is not encoded, #11.9.3.3
-RMAX=33000 T ::= VisibleString (SIZE(32000..32002))
-RMAX=33000 T ::= VisibleString (SIZE(32000..32002)) (FROM("A".."B"))
-RMAX=33000 T ::= VisibleString (SIZE(32000..32002,...)) (FROM("A".."B"))
-RMAX=65536 T ::= VisibleString (SIZE(65530..65535))
-RMAX=65536 T ::= VisibleString (SIZE(65530..65536))
 T ::= VisibleString (SIZE(4..6) INTERSECTION (FROM("A".."B")))
 T ::= VisibleString (SIZE(4..6,...) INTERSECTION (FROM("A".."B")))
+VisibleString (SIZE(64000))                 -- RMAX=64000, #11.9.3.3
+T ::= VisibleString (SIZE(32000..32002))    -- RMAX=33000
+T ::= VisibleString (SIZE(32000..32002)) (FROM("A".."B"))       -- RMAX=33000
+T ::= VisibleString (SIZE(32000..32002,...)) (FROM("A".."B"))   -- RMAX=33000
+T ::= VisibleString (SIZE(65530..65535))    -- RMAX=65536
+T ::= VisibleString (SIZE(65530..65536))    -- RMAX=65536
+T ::= VisibleString (SIZE(65535..65550))    -- RMAX=66000
diff --git a/tests/tests-randomized/bundles/README b/tests/tests-randomized/bundles/README
index 29c1aab..e962eed 100644
--- a/tests/tests-randomized/bundles/README
+++ b/tests/tests-randomized/bundles/README
@@ -14,9 +14,9 @@
 
  * By default, the random value generator attempts to generate values
    limited to very roughly to around 128 bytes. If huge values are desired
-   (perhaps due to large constraints), the RMAX=<size> prefix can be specified
-   on a line:
+   (perhaps due to large constraints), the RMAX=<size> setting can be specified
+   in the ASN.1 comments:
 
-        RMAX=64000 T ::= VisibleString (SIZE(64000))
+        T ::= VisibleString (SIZE(64000))    -- RMAX=64000
    
 
diff --git a/tests/tests-randomized/check-bundles.sh b/tests/tests-randomized/check-bundles.sh
index 12f6e89..5c8bd2e 100755
--- a/tests/tests-randomized/check-bundles.sh
+++ b/tests/tests-randomized/check-bundles.sh
@@ -148,12 +148,11 @@
     local asn="$1"
     shift
 
-    # Create "INTEGER (1..2)" from "RMAX=5 T ::= INTEGER (1..2) -- Comment"
+    # Create "INTEGER (1..2)" from "T ::= INTEGER (1..2) -- RMAX=5"
     local short_asn=$(echo "$asn" | sed -e 's/ *--.*//;s/RMAX=[^ ]* //;')
     if [ $(echo "$short_asn" | grep -c "::=") = 1 ]; then
         short_asn=$(echo "$short_asn" | sed -e 's/.*::= *//')
     fi
-    asn=$(echo "$asn" | sed -e 's/RMAX=[^ ]* //;')
 
     test ! -f Makefile.am   # Protection from accidental clobbering
     echo "Test DEFINITIONS ::= BEGIN $asn" > test.asn1
diff --git a/tests/tests-skeletons/Makefile.am b/tests/tests-skeletons/Makefile.am
index aebd2ca..5b8de97 100644
--- a/tests/tests-skeletons/Makefile.am
+++ b/tests/tests-skeletons/Makefile.am
@@ -15,6 +15,7 @@
     check-OER-support       \
     check-OER-INTEGER       \
     check-OER-NativeEnumerated \
+    check-PER-support       \
     check-PER-UniversalString  \
     check-PER-INTEGER
 
diff --git a/tests/tests-skeletons/check-PER-support.c b/tests/tests-skeletons/check-PER-support.c
new file mode 100644
index 0000000..e2cc9a1
--- /dev/null
+++ b/tests/tests-skeletons/check-PER-support.c
@@ -0,0 +1,85 @@
+#include <assert.h>
+#include <per_support.h>
+
+static void put(asn_per_outp_t *po, size_t length) {
+    fprintf(stderr, "put(%zd)\n", length);
+    do {
+        int need_eom = 123;
+        ssize_t may_write = uper_put_length(po, length, &need_eom);
+        fprintf(stderr, "  put %zu\n", may_write);
+        assert(may_write >= 0);
+        assert(may_write <= length);
+        assert(need_eom != 123);
+        length -= may_write;
+        if(need_eom) {
+            assert(length == 0);
+            if(uper_put_length(po, 0, 0)) {
+                assert(!"Unreachable");
+            }
+            fprintf(stderr, "  put EOM 0\n");
+        }
+    } while(length);
+    fprintf(stderr, "put(...) in %zu bits\n", po->nboff);
+    assert(po->nboff != 0);
+    assert(po->flushed_bytes == 0);
+}
+
+static size_t get(asn_per_outp_t *po) {
+    asn_bit_data_t data;
+    memset(&data, 0, sizeof(data));
+    data.buffer = po->tmpspace;
+    data.nboff = 0;
+    data.nbits = 8 * (po->buffer - po->tmpspace) + po->nboff;
+
+    fprintf(stderr, "get(): %s\n", asn_bit_data_string(&data));
+
+    size_t length = 0;
+    int repeat = 0;
+    do {
+        ssize_t n = uper_get_length(&data, -1, 0, &repeat);
+        fprintf(stderr, "  get = %zu +%zd\n", length, n);
+        assert(n >= 0);
+        length += n;
+    } while(repeat);
+    fprintf(stderr, "get() = %zu\n", length);
+
+    return length;
+}
+
+static void
+check_round_trip(size_t length) {
+    fprintf(stderr, "\nRound-trip for %zu\n", length);
+    asn_per_outp_t po;
+
+    memset(&po, 0, sizeof(po));
+    po.buffer = po.tmpspace;
+    po.nbits = 8 * sizeof(po.tmpspace);
+
+    put(&po, length);
+    size_t recovered = get(&po);
+
+    assert(recovered == length);
+}
+
+int main() {
+
+    check_round_trip(0);
+    check_round_trip(1);
+    check_round_trip(127);
+    check_round_trip(128);
+    check_round_trip(129);
+    check_round_trip(255);
+    check_round_trip(256);
+    check_round_trip(65534);
+    check_round_trip(65535);
+    check_round_trip(65536);
+    check_round_trip(65538);
+    check_round_trip(128000);
+    for(size_t i = 1; i < 10; i++) {
+        check_round_trip(i*16384 - 1);
+        check_round_trip(i*16384);
+        check_round_trip(i*16384 + 1);
+    }
+
+}
+
diff --git a/tests/tests-skeletons/check-PER.c b/tests/tests-skeletons/check-PER.c
deleted file mode 100644
index 8f629f3..0000000
--- a/tests/tests-skeletons/check-PER.c
+++ /dev/null
@@ -1,389 +0,0 @@
-#include <stdio.h>
-#include <assert.h>
-
-#include <asn_bit_data.c>
-#include <per_support.c>
-#include <per_support.h>
-
-static void
-check_per_decoding() {
-	uint8_t buf[] = { 0xB7, 0x19, 0x2F, 0xEE, 0xAD };
-	uint8_t tmpbuf[10];
-	int32_t z;
-	asn_per_data_t pos;
-	memset(&pos, 0, sizeof(pos));
-
-	pos.buffer = buf;
-	pos.nboff = 0;
-	pos.nbits = sizeof(buf) * 8;
-
-	z = per_get_few_bits(&pos, 32);
-	assert(z == -1);
-	assert(pos.nbits == sizeof(buf) * 8);
-
-	z = per_get_few_bits(&pos, 0);
-	assert(z == 0);
-	assert(pos.nboff == 0);
-	assert(pos.nbits == sizeof(buf) * 8);
-
-	z = per_get_few_bits(&pos, 1);
-	assert(z == 1);
-	assert(pos.nboff == 1);
-	assert(pos.nbits == sizeof(buf) * 8);
-
-	z = per_get_few_bits(&pos, 2);
-	assert(z == 1);
-	assert(pos.nboff == 3);
-	assert(pos.nbits == sizeof(buf) * 8);
-
-	z = per_get_few_bits(&pos, 2);
-	assert(z == 2);
-	assert(pos.nboff == 5);
-	assert(pos.nbits == sizeof(buf) * 8);
-
-	z = per_get_few_bits(&pos, 3);
-	assert(z == 7);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == sizeof(buf) * 8);
-
-	z = per_get_few_bits(&pos, 8);
-	assert(z == 0x19);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == (sizeof(buf) - 1) * 8);
-
-	z = per_get_few_bits(&pos, 1);
-	assert(z == 0);
-	assert(pos.nboff == 1);
-	assert(pos.nbits == (sizeof(buf) - 2) * 8);
-
-	z = per_get_few_bits(&pos, 3);
-	assert(z == 2);
-	assert(pos.nboff == 4);
-	assert(pos.nbits == (sizeof(buf) - 2) * 8);
-
-	z = per_get_few_bits(&pos, 8);
-	assert(z == 254);
-	assert(pos.nboff == 12);
-
-	pos.buffer = buf;
-	pos.nboff = 2;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_few_bits(&pos, 24);
-	assert(z == 14443711);
-
-	pos.buffer = (unsigned char *)"\001";
-	pos.nboff = 7;
-	pos.nbits = 7;
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 7);
-	assert(pos.nbits == 7);
-	assert(z == -1);
-
-	pos.buffer = (unsigned char *)"\001";
-	pos.nboff = 7;
-	pos.nbits = 8;
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == 8);
-	assert(z == 1);
-
-	pos.buffer = (unsigned char *)"\000";
-	pos.nboff = 7;
-	pos.nbits = 8;
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == 8);
-	assert(z == 0);
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == 8);
-	assert(z == -1);
-
-	pos.buffer = (unsigned char *)"\000";
-	pos.nboff = 7;
-	pos.nbits = 9;
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == 9);
-	assert(z == 0);
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 1);
-	assert(pos.nbits == 1);
-	assert(z == 0);
-
-	pos.buffer = (unsigned char *)"\001";
-	pos.nboff = 7;
-	pos.nbits = 9;
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 8);
-	assert(pos.nbits == 9);
-	assert(z == 1);
-	z = per_get_few_bits(&pos, 1);
-	assert(pos.nboff == 1);
-	assert(pos.nbits == 1);
-	assert(z == 0);
-
-	/* Get full 31-bit range */
-	pos.buffer = buf;
-	pos.nboff = 7;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_few_bits(&pos, 31);
-	assert(z == 1179384747);
-
-	/* Get a bit shifted range */
-	pos.buffer = buf;
-	pos.nboff = 6;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_few_bits(&pos, 31);
-	assert(z == 1663434197);
-
-	pos.buffer = buf;
-	pos.nboff = 0;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_many_bits(&pos, tmpbuf, 0, sizeof(buf) * 8);
-	assert(z == 0);
-	assert(buf[0] == tmpbuf[0]);
-	assert(buf[1] == tmpbuf[1]);
-	assert(buf[2] == tmpbuf[2]);
-	assert(buf[3] == tmpbuf[3]);
-	assert(buf[4] == tmpbuf[4]);
-
-	pos.buffer = buf;
-	pos.nboff = 1;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_many_bits(&pos, tmpbuf, 0, sizeof(buf) * 8);
-	assert(z == -1);
-
-	pos.buffer = buf;
-	pos.nboff = 1;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_many_bits(&pos, tmpbuf, 0, sizeof(buf) * 8 - 1);
-	assert(z == 0);
-	assert(tmpbuf[0] == 110);
-	assert(tmpbuf[1] == 50);
-	assert(tmpbuf[2] == 95);
-	assert(tmpbuf[3] == 221);
-	assert(tmpbuf[4] == 90);
-
-	pos.buffer = buf;
-	pos.nboff = 1;
-	pos.nbits = sizeof(buf) * 8;
-	z = per_get_many_bits(&pos, tmpbuf, 1, sizeof(buf) * 8 - 1);
-	assert(z == 0);
-	assert(tmpbuf[0] == 55);
-	assert(tmpbuf[0] != buf[0]);
-	assert(tmpbuf[1] == buf[1]);
-	assert(tmpbuf[2] == buf[2]);
-	assert(tmpbuf[3] == buf[3]);
-	assert(tmpbuf[4] == buf[4]);
-}
-
-static int Ignore(const void *data, size_t size, void *op_key) {
-    (void)data;
-    (void)size;
-    (void)op_key;
-	return 0;
-}
-
-static void
-check_per_encoding() {
-	asn_per_outp_t po;
-	int ret;
-
-	po.buffer = po.tmpspace;
-	po.nboff = 0;
-	po.nbits = 0;
-	po.output = Ignore;
-	po.op_key = 0;
-	po.tmpspace[0] = 0xff;
-
-	ret = per_put_few_bits(&po, 0, 0);
-	assert(ret == 0);
-	assert(po.nboff == 0);
-	assert(po.buffer == po.tmpspace);
-	assert(po.tmpspace[0] == 0xff);
-
-	ret = per_put_few_bits(&po, 0, 1);
-	assert(ret == 0);
-	assert(po.nboff == 1);
-	assert(po.nbits == 8 * sizeof(po.tmpspace));
-	assert(po.buffer == po.tmpspace);
-	assert(po.tmpspace[0] == 0x00);
-
-	ret = per_put_few_bits(&po, 1, 1);
-	assert(ret == 0);
-	assert(po.nboff == 2);
-	assert(po.nbits == 8 * sizeof(po.tmpspace));
-	assert(po.buffer == po.tmpspace);
-	assert(po.tmpspace[0] == 0x40);
-
-	ret = per_put_few_bits(&po, 1, 1);
-	assert(ret == 0);
-	assert(po.nboff == 3);
-	assert(po.nbits == 8 * sizeof(po.tmpspace));
-	assert(po.buffer == po.tmpspace);
-	assert(po.tmpspace[0] == 0x60);
-
-	ret = per_put_few_bits(&po, 15, 5);
-	assert(ret == 0);
-	assert(po.nboff == 8);
-	assert(po.nbits == 8 * sizeof(po.tmpspace));
-	assert(po.buffer == po.tmpspace);
-	assert(po.tmpspace[0] == 0x6F);
-
-	ret = per_put_few_bits(&po, 0xf0ff, 16);
-	assert(ret == 0);
-	assert(po.nboff == 16);
-	assert(po.nbits == 8 * sizeof(po.tmpspace) - 8);
-	assert(po.buffer == po.tmpspace + 1);
-	assert(po.tmpspace[0] == 0x6F);
-	assert(po.tmpspace[1] == 0xf0);
-	assert(po.tmpspace[2] == 0xff);
-
-	po.nboff--;
-
-	ret = per_put_few_bits(&po, 2, 1);
-	assert(ret == 0);
-	assert(po.nboff == 8);
-	assert(po.nbits == 8 * sizeof(po.tmpspace) - 16);
-	assert(po.buffer == po.tmpspace + 2);
-	assert(po.tmpspace[0] == 0x6F);
-	assert(po.tmpspace[1] == 0xf0);
-	assert(po.tmpspace[2] == 0xfe);
-
-	ret = per_put_few_bits(&po, 2, 32);
-	assert(ret == -1);
-
-	ret = per_put_few_bits(&po, 2, -1);
-	assert(ret == -1);
-
-	ret = per_put_few_bits(&po, -1, 31);
-	assert(ret == 0);
-	assert(po.nboff == 31);
-	assert(po.nbits == 8 * sizeof(po.tmpspace) - 24);
-	assert(po.buffer == po.tmpspace + 3);
-	assert(po.tmpspace[0] == 0x6F);
-	assert(po.tmpspace[1] == 0xf0);
-	assert(po.tmpspace[2] == 0xfe);
-	assert(po.tmpspace[3] == 0xff);
-	assert(po.tmpspace[4] == 0xff);
-	assert(po.tmpspace[5] == 0xff);
-	assert(po.tmpspace[6] == 0xfe);
-
-}
-
-/*
- * Add N bits after P bits. Should result in N+P bits added.
- */
-static void
-check_per_encoding_auto() {
-    int prior, next;
-    int ret, i;
-
-    for(prior = 0; prior <= 31; prior++) {
-      for(next = 0; next <= 31; next++) {
-        asn_per_outp_t po;
-        po.buffer = po.tmpspace;
-        po.nboff = 0;
-        po.nbits = 0;
-        po.output = Ignore;
-        po.op_key = 0;
-        po.tmpspace[0] = 0xff;
-
-        ret = per_put_few_bits(&po, -1, prior);
-        assert(ret == 0);
-
-		ASN_DEBUG(" (out{nboff=%d,nbits=%d,buf_offset=%d})", (int)po.nboff, (int)po.nbits, (int)(po.buffer - po.tmpspace));
-
-        ret = per_put_few_bits(&po, -1, next);
-        assert(ret == 0);
-
-		ASN_DEBUG(" (out{nboff=%d,nbits=%d,buf_offset=%d})", (int)po.nboff, (int)po.nbits, (int)(po.buffer - po.tmpspace));
-
-		ASN_DEBUG("Putting %d + %d bits (%d/%d), got %d bytes and %d bits",
-            prior, next, (prior + next) / 8, (prior + next) % 8,
-            (int)(po.buffer - po.tmpspace), (int)po.nboff);
-        assert((po.buffer - po.tmpspace) * 8 + po.nboff == (size_t)(prior + next));
-        for(i = 0; i < (po.buffer - po.tmpspace); i++)
-            assert(po.tmpspace[0] == (unsigned char)-1);
-      }
-    }
-}
-
-static void
-check_per_encoding_sweep_with(uint8_t buf[], int already_bits, int add_bits) {
-	size_t buf_size = 8;
-	asn_per_data_t pos;
-	asn_per_outp_t out;
-	int32_t d_already;
-	int32_t d_add;
-	int32_t d_left;
-	int left_bits;
-
-	memset(&pos, 0, sizeof(pos));
-	pos.buffer = buf;
-	pos.nboff = 0;
-	pos.nbits = buf_size * 8;
-
-	memset(&out, 0, sizeof(out));
-	out.buffer = out.tmpspace;
-	out.nbits = 8 * sizeof(out.tmpspace);
-	assert(sizeof(out.tmpspace) >= buf_size);
-	memcpy(out.buffer, buf, buf_size);
-
-	d_already = per_get_few_bits(&pos, already_bits);
-	d_add = per_get_few_bits(&pos, add_bits);
-
-	per_put_few_bits(&out, d_already, already_bits);
-	per_put_few_bits(&out, d_add, add_bits);
-	if(out.nboff % 8) {
-		left_bits = 8 - (out.nboff % 8);
-		d_left = per_get_few_bits(&pos, left_bits);
-	} else {
-		left_bits = 0;
-		d_left = 0;
-	}
-	per_put_few_bits(&out, d_left, left_bits);
-	assert(0 == (out.nboff % 8));
-
-	if(0 != memcmp(out.tmpspace, buf, buf_size)) {
-		printf("IN: ");
-		for(size_t i = 0; i < buf_size; i++)
-			printf(" %02x", buf[i]);
-		printf("\nOUT:");
-		for(size_t i = 0; i < buf_size; i++)
-			printf(" %02x", out.tmpspace[i]);
-		printf(" (out{nboff=%d,left=%d,%02x})\n", (int)out.nboff, left_bits, (int)d_left);
-		assert(0 == memcmp(out.tmpspace, buf, buf_size));
-	}
-}
-
-static void
-check_per_encoding_sweep() {
-	uint8_t buf[3][8] = {
-		{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA },
-		{ 0xB7, 0x19, 0x2F, 0xEE, 0xAD, 0x11, 0xAA, 0x55 },
-		{ 0xEE, 0xAD, 0x11, 0xAA, 0x55, 0xB7, 0x19, 0x2F }
-	};
-	int already_bits;
-	int add_bits;
-	int buf_idx;
-
-	for(buf_idx = 0; buf_idx < 3; buf_idx++) {
-	 for(already_bits = 0; already_bits < 24; already_bits++) {
-	  for(add_bits = 0; add_bits <= 31; add_bits++) {
-	   /*fprintf(stderr, "PER %d += %d\n", already_bits, add_bits);*/
-	   check_per_encoding_sweep_with(buf[buf_idx], already_bits, add_bits);
-	  }
-	 }
-	}
-}
-
-int
-main() {
-	check_per_decoding();
-	check_per_encoding();
-	check_per_encoding_auto();
-	check_per_encoding_sweep();
-	return 0;
-}