INTEGER XER decoding

diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index c4fb972..1037bdd 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -183,6 +183,7 @@
 INTEGER__xer_body_decode(INTEGER_t *st, void *chunk_buf, size_t chunk_size) {
 	long sign = 1;
 	long value;
+	char *lp;
 	char *lstart = (char *)chunk_buf;
 	char *lstop = chunk_buf + chunk_size;
 	enum {
@@ -190,12 +191,13 @@
 		ST_WAITDIGITS,
 		ST_DIGITS,
 	} state = ST_SKIPSPACE;
+
 	/*
 	 * We may receive a tag here. But we aren't ready to deal with it yet.
 	 * So, just use stroul()-like code and serialize the result.
 	 */
-	for(value = 0; lstart < lstop; lstart++) {
-		int lv = *lstart;
+	for(value = 0, lp = lstart; lp < lstop; lp++) {
+		int lv = *lp;
 		switch(lv) {
 		case 0x09: case 0x0a: case 0x0d: case 0x20:
 			if(state == ST_SKIPSPACE) continue;
@@ -217,20 +219,29 @@
 		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
 			if(state != ST_DIGITS) state = ST_DIGITS;
 
-			value = value * 10 + (lv - 0x30);
+		    {
+			long new_value = value * 10;
+
+			if(new_value / 10 != value)
+				/* Overflow */
+				return -1;
+
+			value = new_value + (lv - 0x30);
 			/* Check for two's complement overflow */
 			if(value < 0) {
 				/* Check whether it is a LONG_MIN */
 				if(sign == -1
 				&& value == ~((unsigned long)-1 >> 1)) {
-					sign = 0;
+					sign = 1;
 				} else {
 					/* Overflow */
 					return -1;
 				}
 			}
+		    }
 			continue;
 		}
+		break;
 	}
 
 	if(state != ST_DIGITS)
@@ -241,7 +252,7 @@
 	if(asn_long2INTEGER(st, value))
 		return -1;
 
-	return lstop - lstart;
+	return lp - lstart;
 }
 
 asn_dec_rval_t
diff --git a/skeletons/asn_codecs_prim.c b/skeletons/asn_codecs_prim.c
index e0b545a..8791475 100644
--- a/skeletons/asn_codecs_prim.c
+++ b/skeletons/asn_codecs_prim.c
@@ -143,12 +143,38 @@
 	int want_more;
 };
 
+/*
+ * Check whether this buffer consists of entirely XER whitespace characters.
+ */
+static int
+xer_decode__check_whitespace(void *chunk_buf, size_t chunk_size) {
+	char *p = (char *)chunk_buf;
+	char *pend = p + chunk_size;
+	for(; p < pend; p++) {
+		switch(*p) {
+		/* X.693, #8.1.4
+		 * HORISONTAL TAB (9)
+		 * LINE FEED (10)
+		 * CARRIAGE RETURN (13)
+		 * SPACE (32)
+		 */
+		case 0x09: case 0x0a: case 0x0d: case 0x20:
+			break;
+		default:
+			return 0;
+		}
+	}
+	return 1;	/* All whitespace */
+}
+
 static int
 xer_decode__unexpected_tag(void *key, void *chunk_buf, size_t chunk_size) {
 	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
 	ssize_t decoded;
 
 	if(arg->decoded_something) {
+		if(xer_decode__check_whitespace(chunk_buf, chunk_size))
+			return chunk_size;
 		/*
 		 * Decoding was done once already. Prohibit doing it again.
 		 */
@@ -171,6 +197,8 @@
 	ssize_t decoded;
 
 	if(arg->decoded_something) {
+		if(xer_decode__check_whitespace(chunk_buf, chunk_size))
+			return chunk_size;
 		/*
 		 * Decoding was done once already. Prohibit doing it again.
 		 */
diff --git a/skeletons/tests/check-INTEGER.c b/skeletons/tests/check-INTEGER.c
index ea686b4..81aae6e 100644
--- a/skeletons/tests/check-INTEGER.c
+++ b/skeletons/tests/check-INTEGER.c
@@ -78,6 +78,34 @@
 	}
 }
 
+static void
+check_xer(int tofail, char *xmldata, long orig_value) {
+	INTEGER_t *st = 0;
+	asn_dec_rval_t rc;
+	long value;
+	int ret;
+
+	printf("[%s] vs %ld:\n", xmldata, orig_value);
+
+	rc = xer_decode(0, &asn_DEF_INTEGER, (void *)&st,
+		xmldata, strlen(xmldata));
+	if(rc.code != RC_OK) {
+		assert(tofail);
+		printf("\tfailed, as expected\n");
+		return;
+	}
+	assert(!tofail);
+
+	ret = asn_INTEGER2long(st, &value);
+	assert(ret == 0);
+
+	printf("\t%ld\n", value);
+
+	assert(value == orig_value);
+
+	asn_DEF_INTEGER.free_struct(&asn_DEF_INTEGER, st, 0);
+}
+
 int
 main(int ac, char **av) {
 	uint8_t buf1[] = { 1 };
@@ -110,5 +138,40 @@
 	CHECK(buf12, -32768, 0);
 	CHECK(buf13, -128, 0);
 
+	check_xer(-1, "", 0);
+	check_xer(-1, "<INTEGER></INTEGER>", 0);
+	check_xer(-1, "<INTEGER>-</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>+</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>+-</INTEGER>", 0);
+	check_xer(0, "<INTEGER>+0</INTEGER>", 0);
+	check_xer(0, "<INTEGER>-0</INTEGER>", 0);
+	check_xer(0, "<INTEGER>+1</INTEGER>", 1);
+	check_xer(0, "<INTEGER>-1</INTEGER>", -1);
+	check_xer(0, "<INTEGER>1</INTEGER>", 1);
+	check_xer(0, "<INTEGER>-15</INTEGER>", -15);
+	check_xer(0, "<INTEGER>+15</INTEGER>", 15);
+	check_xer(0, "<INTEGER>15</INTEGER>", 15);
+	check_xer(0, "<INTEGER> 15</INTEGER>", 15);
+	check_xer(0, "<INTEGER> 15 </INTEGER>", 15);
+	check_xer(0, "<INTEGER>15 </INTEGER>", 15);
+	check_xer(0, "<INTEGER> +15 </INTEGER>", 15);
+	check_xer(-1, "<INTEGER> +15 -</INTEGER>", 0);
+	check_xer(-1, "<INTEGER> +15 1</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>+ 15</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>12<z>34</INTEGER>", 0);
+	check_xer(0, "<INTEGER>1234</INTEGER>", 1234);
+	check_xer(-1, "<INTEGER>1234 5678</INTEGER>", 0);
+	check_xer(0, "<INTEGER>-2147483647</INTEGER>", -2147483647);
+	check_xer(0, "<INTEGER>-2147483648</INTEGER>", -2147483648);
+	check_xer(0, "<INTEGER>+2147483647</INTEGER>", 2147483647);
+	check_xer(0, "<INTEGER>2147483647</INTEGER>", 2147483647);
+	check_xer(-1, "<INTEGER>2147483648</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>2147483649</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>3147483649</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>4147483649</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>5147483649</INTEGER>", 0);	/* unobvious */
+	check_xer(-1, "<INTEGER>9147483649</INTEGER>", 0);
+	check_xer(-1, "<INTEGER>9999999999</INTEGER>", 0);
+
 	return 0;
 }