gsm48_decode_bcd_number2: fix ENOSPC edge case

Return ENOSPC if the decoding buffer is one byte too small, instead of
returning 0 and silently truncating the string. Add a new "truncated"
variable to detect if the loop breaks in the final iteration.

The string is not truncated if there is exactly one 0xf ('\0') higher
nibble remaining. This is covered by the existing test case "long
15-digit (maximum) MSISDN, limited buffer".

Related: OS#4049
Change-Id: Ie05900aca50cc7fe8a45d17844dbfcd905fd82fe
diff --git a/src/gsm/gsm48_ie.c b/src/gsm/gsm48_ie.c
index 59f931b..31028ba 100644
--- a/src/gsm/gsm48_ie.c
+++ b/src/gsm/gsm48_ie.c
@@ -82,6 +82,7 @@
 {
 	uint8_t in_len;
 	int i;
+	bool truncated = false;
 	if (output_len < 1)
 		return -ENOSPC;
 	*output = '\0';
@@ -94,14 +95,23 @@
 
 	for (i = 1 + h_len; i <= in_len; i++) {
 		/* lower nibble */
-		if (output_len <= 1)
+		if (output_len <= 1) {
+			truncated = true;
 			break;
+		}
 		*output++ = bcd_num_digits[bcd_lv[i] & 0xf];
 		output_len--;
 
 		/* higher nibble */
-		if (output_len <= 1)
+		if (output_len <= 1) {
+			/* not truncated if there is exactly one 0xf ('\0') higher nibble remaining */
+			if (i == in_len && (bcd_lv[i] & 0xf0) == 0xf0) {
+				break;
+			}
+
+			truncated = true;
 			break;
+		}
 		*output++ = bcd_num_digits[bcd_lv[i] >> 4];
 		output_len--;
 	}
@@ -109,7 +119,7 @@
 		*output++ = '\0';
 
 	/* Indicate whether the output was truncated */
-	if (i < in_len)
+	if (truncated)
 		return -ENOSPC;
 
 	return 0;