32-bit integer decode/encode in per
diff --git a/asn1c/tests/check-127.-fnative-types.-gen-PER.c b/asn1c/tests/check-127.-fnative-types.-gen-PER.c
new file mode 100644
index 0000000..9cca644
--- /dev/null
+++ b/asn1c/tests/check-127.-fnative-types.-gen-PER.c
@@ -0,0 +1,69 @@
+#undef	NDEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <T.h>
+
+void
+verify(T_t *ti) {
+	asn_enc_rval_t er;
+	asn_dec_rval_t rv;
+	unsigned char buf[8];
+	T_t *to = 0;
+
+	fprintf(stderr, "IN: { %ld, %ld }\n",
+		ti->small32range, ti->full32range);
+
+	er = uper_encode_to_buffer(&asn_DEF_T, ti, buf, sizeof buf);
+	assert(er.encoded == 64);
+
+	rv = uper_decode(0, &asn_DEF_T, (void *)&to, buf, sizeof buf, 0, 0);
+	assert(rv.code == RC_OK);
+
+	fprintf(stderr, "ENC: %2x%2x%2x%2x %2x%2x%2x%2x\n",
+		buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7]);
+	fprintf(stderr, "OUT: { %ld, %ld } vs { %ld, %ld }\n",
+		ti->small32range, ti->full32range,
+		to->small32range, to->full32range);
+	assert(ti->small32range == to->small32range);
+	assert(ti->full32range == to->full32range);
+
+	xer_fprint(stderr, &asn_DEF_T, ti);
+	xer_fprint(stderr, &asn_DEF_T, to);
+}
+
+int main() {
+	T_t ti;
+
+	ti.small32range = 0;
+	ti.full32range = 0;
+	verify(&ti);
+
+	ti.small32range = -1;
+	ti.full32range = -1;
+	verify(&ti);
+
+	ti.small32range = -2000000000;
+	ti.full32range = (-2147483647L - 1);
+	verify(&ti);
+
+	ti.small32range = -1999999999;
+	ti.full32range = (-2147483647L);
+	verify(&ti);
+
+	ti.small32range = 2000000000;
+	ti.full32range = 2147483647;
+	verify(&ti);
+
+	ti.small32range = 1999999999;
+	ti.full32range = 2147483647 - 1;
+	verify(&ti);
+
+	return 0;
+}
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 0cbbbaa..60afa77 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -598,8 +598,18 @@
 		/* #10.5.6 */
 		ASN_DEBUG("Integer with range %d bits", ct->range_bits);
 		if(ct->range_bits >= 0) {
-			long value = per_get_few_bits(pd, ct->range_bits);
-			if(value < 0) _ASN_DECODE_STARVED;
+			long value;
+			if(ct->range_bits == 32) {
+				long lhalf;
+				value = per_get_few_bits(pd, 16);
+				if(value < 0) _ASN_DECODE_STARVED;
+				lhalf = per_get_few_bits(pd, 16);
+				if(lhalf < 0) _ASN_DECODE_STARVED;
+				value = (value << 16) | lhalf;
+			} else {
+				value = per_get_few_bits(pd, ct->range_bits);
+				if(value < 0) _ASN_DECODE_STARVED;
+			}
 			ASN_DEBUG("Got value %ld + low %ld",
 				value, ct->lower_bound);
 			value += ct->lower_bound;
@@ -695,9 +705,17 @@
 		/* #10.5.6 */
 		ASN_DEBUG("Encoding integer with range %d bits",
 			ct->range_bits);
-		if(per_put_few_bits(po, value - ct->lower_bound,
+		if(ct->range_bits == 32) {
+			/* TODO: extend to >32 bits */
+			long v = value - ct->lower_bound;
+			if(per_put_few_bits(po, v >> 1, 31)
+			|| per_put_few_bits(po, v, 1))
+				_ASN_ENCODE_FAILED;
+		} else {
+			if(per_put_few_bits(po, value - ct->lower_bound,
 				ct->range_bits))
-			_ASN_ENCODE_FAILED;
+				_ASN_ENCODE_FAILED;
+		}
 		_ASN_ENCODED_OK(er);
 	}
 
diff --git a/tests/127-per-long-OK.asn1 b/tests/127-per-long-OK.asn1
new file mode 100644
index 0000000..61d89aa
--- /dev/null
+++ b/tests/127-per-long-OK.asn1
@@ -0,0 +1,19 @@
+
+-- OK: Everything is fine
+
+-- iso.org.dod.internet.private.enterprise (1.3.6.1.4.1)
+-- .spelio.software.asn1c.test (9363.1.5.1)
+-- .127
+
+ModulePERLong
+	{ iso org(3) dod(6) internet (1) private(4) enterprise(1)
+		spelio(9363) software(1) asn1c(5) test(1) 127 }
+	DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+	T ::= SEQUENCE {
+		small32range	INTEGER (-2000000000..2000000000),
+		full32range	INTEGER (-2147483648..2147483647)
+	}
+
+END