Browse Source

fix: add support for big integer (see X509SerialNumber in ISO1)

git-svn-id: https://svn.code.sf.net/p/openv2g/code/trunk@112 d9f2db14-54d0-4bde-b00c-16405c910529
daniel_peintner 7 years ago
parent
commit
5e02082f8b

+ 202 - 4
src/codec/DecoderChannel.c

@@ -167,7 +167,7 @@ int decodeUnsignedInteger(bitstream_t* stream, exi_integer_t* iv) {
 int decodeUnsignedInteger16(bitstream_t* stream, uint16_t* uint16) {
 	unsigned int mShift = 0;
 	int errn = 0;
-	uint8_t b;
+	uint8_t b = 0;
 	*uint16 = 0;
 
 	do {
@@ -190,7 +190,7 @@ int decodeUnsignedInteger32(bitstream_t* stream, uint32_t* uint32) {
 	/* 0XXXXXXX ... 1XXXXXXX 1XXXXXXX */
 	unsigned int mShift = 0;
 	int errn = 0;
-	uint8_t b;
+	uint8_t b = 0;
 	*uint32 = 0;
 
 	do {
@@ -261,7 +261,183 @@ int decodeUnsignedInteger64(bitstream_t* stream, uint64_t* uint64) {
 
 	return errn;
 }
-
+
+
+void _reverseArray(uint8_t *array, int number) {
+    int x, t;
+    number--;
+
+    for(x = 0; x < number; x ++, number --) {
+        t = array[x];
+        array[x] = array[number];
+        array[number] = t;
+    }
+}
+
+/**
+ * Decode an arbitrary precision non negative integer using a sequence of
+ * octets. The most significant bit of the last octet is set to zero to
+ * indicate sequence termination. Only seven bits per octet are used to
+ * store the integer's value.
+ */
+int decodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t* len) {
+	int errn = 0;
+	uint8_t b = 0;
+	unsigned int mShift1 = 0;
+	unsigned int mShift2 = 0;
+	unsigned int mShift3 = 0;
+	unsigned int mShift4 = 0;
+	unsigned int nBytesRead = 0;
+	unsigned int nBitsAvailable = 0;
+	uint64_t uint64_1 = 0;
+	uint64_t uint64_2 = 0;
+	uint64_t uint64_3 = 0;
+	uint64_t uint64_4 = 0;
+
+	*len = 0;
+
+	do {
+		errn = decode(stream, &b);
+		nBytesRead++;
+		nBitsAvailable += 7;
+
+		if(nBytesRead <= 8) {
+			uint64_1 += ((uint64_t) (b & 127)) << mShift1;
+			mShift1 += 7;
+		} else if(nBytesRead <= 16) {
+			uint64_2 += ((uint64_t) (b & 127)) << mShift2;
+			mShift2 += 7;
+		} else if(nBytesRead <= 24) {
+			uint64_3 += ((uint64_t) (b & 127)) << mShift3;
+			mShift3 += 7;
+		} else if(nBytesRead <= 32) {
+			uint64_4 += ((uint64_t) (b & 127)) << mShift4;
+			mShift4 += 7;
+		} else {
+			return -1; // too large
+		}
+	} while (errn == 0 && (b >> 7) == 1);
+
+	// shift actual data into array
+	if(uint64_4 != 0) {
+		// 7 octets for uint64_1
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 1
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 2
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 3
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 4
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 5
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 6
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 7
+
+		// 7 octets for uint64_2
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 1
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 2
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 3
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 4
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 5
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 6
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 7
+
+		// 7 octets for uint64_3
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 1
+		uint64_3 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 2
+		uint64_3 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 3
+		uint64_3 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 4
+		uint64_3 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 5
+		uint64_3 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 6
+		uint64_3 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 7
+
+		// remaining octets of uint64_4
+		while (uint64_4 != 0 && errn == 0) {
+			data[(*len)++] = uint64_4 & 0xFF;
+			uint64_4 >>= 8;
+		}
+	} else if(uint64_3 != 0) {
+		// 7 octets for uint64_1
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 1
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 2
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 3
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 4
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 5
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 6
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 7
+
+		// 7 octets for uint64_2
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 1
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 2
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 3
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 4
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 5
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 6
+		uint64_2 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 7
+
+		// remaining octets of uint64_3
+		while (uint64_3 != 0 && errn == 0) {
+			data[(*len)++] = uint64_3 & 0xFF;
+			uint64_3 >>= 8;
+		}
+
+	} else if(uint64_2 != 0) {
+		// 7 octets for uint64_1
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 1
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 2
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 3
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 4
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 5
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 6
+		uint64_1 >>= 8;
+		data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 7
+		// remaining octets of uint64_2
+		while (uint64_2 != 0 && errn == 0) {
+			data[(*len)++] = uint64_2 & 0xFF;
+			uint64_2 >>= 8;
+		}
+	} else if(uint64_1 != 0) {
+		while (uint64_1 != 0 && errn == 0) {
+			data[(*len)++] = uint64_1 & 0xFF;
+			uint64_1 >>= 8;
+		}
+	}
+
+	_reverseArray(data, *len);
+
+	return errn;
+}
 
 int decodeInteger(bitstream_t* stream, exi_integer_t* iv) {
 	int b;
@@ -353,6 +529,28 @@ int decodeInteger64(bitstream_t* stream, int64_t* int64) {
 	}
 
 	return errn;
+}
+
+/**
+ * Decode an arbitrary precision integer using a sign bit followed by a
+ * sequence of octets. The most significant bit of the last octet is set to
+ * zero to indicate sequence termination. Only seven bits per octet are used
+ * to store the integer's value.
+ */
+int decodeIntegerBig(bitstream_t* stream, int* negative, size_t size, uint8_t* data, size_t* len) {
+	int errn = decodeBoolean(stream, negative);
+
+	if (errn == 0) {
+		if (*negative) {
+			/* For negative values, the Unsigned Integer holds the
+			 * magnitude of the value minus 1 */
+		} else {
+			/* positive */
+		}
+		errn = decodeUnsignedIntegerBig(stream, size, data, len);
+	}
+
+	return errn;
 }
 
 /**
@@ -554,7 +752,7 @@ int decodeBinary(bitstream_t* stream, exi_bytes_t* bytes) {
 int decodeBytes(bitstream_t* stream, size_t len, uint8_t* data) {
 	unsigned int i;
 	int errn = 0;
-	uint8_t b;
+	uint8_t b = 0;
 
 	for (i = 0; i < len && errn == 0; i++) {
 		errn = decode(stream, &b);

+ 36 - 2
src/codec/DecoderChannel.h

@@ -161,7 +161,24 @@ int decodeUnsignedIntegerSizeT(bitstream_t* stream, size_t* sizeT);
  * \return                  	Error-Code <> 0
  *
  */
-int decodeUnsignedInteger64(bitstream_t* stream, uint64_t* uint64);
+int decodeUnsignedInteger64(bitstream_t* stream, uint64_t* uint64);
+
+/**
+ * \brief 		Decode unsigned integer
+ *
+ * 				Decode an arbitrary precision non negative integer using
+ * 				a sequence of octets. The most significant bit of the last
+ * 				octet is set to zero to indicate sequence termination.
+ * 				Only seven bits per octet are used to store the integer's value.
+ *
+ * \param       stream   		Input Stream
+ * \param       size		   	size array
+ * \param       data		   	data array
+ * \param       len		   		length array
+ * \return                  	Error-Code <> 0
+ *
+ */
+int decodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t* len);
 
 
 /**
@@ -226,7 +243,24 @@ int decodeInteger32(bitstream_t* stream, int32_t* int32);
  *
  */
 int decodeInteger64(bitstream_t* stream, int64_t* int64);
-
+
+/**
+ * \brief 		Decode integer
+ *
+ * 				Decode an arbitrary precision integer using a sign bit
+ * 				followed by a sequence of octets. The most significant bit
+ * 				of the last octet is set to zero to indicate sequence termination.
+ * 				Only seven bits per octet are used to store the integer's value.
+ *
+ * \param       stream   		Input Stream
+ * \param       negative		negative integer
+ * \param       size		   	size array
+ * \param       data		   	data array
+ * \param       len		   		length array
+ * \return                  	Error-Code <> 0
+ *
+ */
+int decodeIntegerBig(bitstream_t* stream, int* negative, size_t size, uint8_t* data, size_t* len);
 
 /**
  * \brief 		Decode float

+ 1 - 6
src/codec/EXITypes.h

@@ -436,15 +436,10 @@ typedef struct {
 	/** LocalName */
 	exi_name_entry_t localName;
 } exi_qname_t;
-
-
+
 /*TODO Doxygen Documentation */
 
 
-
-
-
-
 /* ==================================== */
 /* URI and LocalName Entries */
 typedef struct exiNameTablePrepopulated {

+ 87 - 0
src/codec/EncoderChannel.c

@@ -203,6 +203,69 @@ int encodeUnsignedInteger64(bitstream_t* stream, uint64_t n) {
 	}
 
 	return errn;
+}
+
+void _shiftRight7(uint8_t* buf, int len) {
+	const int shift = 7;
+    unsigned char tmp = 0x00, tmp2 = 0x00;
+    for (int k = 0; k <= len; k++) {
+        if (k == 0) {
+            tmp = buf[k];
+            buf[k] >>= shift;
+        } else {
+            tmp2 = buf[k];
+            buf[k] >>= shift;
+            buf[k] |= ((tmp & 0x7F) << (8 - shift));
+
+            if (k != len) {
+                tmp = tmp2;
+            }
+        }
+    }
+}
+
+/**
+ * Encode an arbitrary precision non negative integer using a sequence of
+ * octets. The most significant bit of the last octet is set to zero to
+ * indicate sequence termination. Only seven bits per octet are used to
+ * store the integer's value.
+ */
+int encodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t len) {
+	int errn = 0;
+	int i;
+	int lenM1 = len - 1;
+	const int MAX_BIGINT_ARRAY = 25;
+	uint8_t lastEncode = 0;
+	uint8_t bytesToShift[MAX_BIGINT_ARRAY]; // MAXIMUM
+	size_t bitsToEncode = len * 8;
+
+	if(MAX_BIGINT_ARRAY <= len) {
+		return -1;
+	}
+
+	/* init */
+	for(i=0; i<MAX_BIGINT_ARRAY; i++) {
+		bytesToShift[i] = 0;
+	}
+
+	/* copy bytes first in same order for shifting */
+	for(i=0; i < len; i++) {
+		bytesToShift[i] = data[i];
+	}
+
+	while(bitsToEncode > 7) {
+		lastEncode = bytesToShift[lenM1];
+		lastEncode = lastEncode | 128;
+		errn = encode(stream, lastEncode);
+		_shiftRight7(bytesToShift, len);
+		bitsToEncode -= 7;
+	}
+
+	if (errn == 0) {
+		errn = encode(stream, bytesToShift[lenM1]);
+	}
+
+	return errn;
 }
 
 int encodeInteger(bitstream_t* stream, exi_integer_t* iv) {
@@ -312,6 +375,30 @@ int encodeInteger64(bitstream_t* stream, int64_t n) {
 		errn = encodeUnsignedInteger64(stream, (uint64_t)n);
 	}
 	return errn;
+}
+
+
+/**
+ * Encode an arbitrary precision integer using a sign bit followed by a
+ * sequence of octets. The most significant bit of the last octet is set to
+ * zero to indicate sequence termination. Only seven bits per octet are used
+ * to store the integer's value.
+ */
+int encodeIntegerBig(bitstream_t* stream, int negative, size_t size, uint8_t* data, size_t len) {
+	int errn;
+	/* signalize sign */
+	if (negative) {
+		errn = encodeBoolean(stream, 1);
+		/* For negative values, the Unsigned Integer holds the
+		 * magnitude of the value minus 1 */
+		/* n = (-n) - 1; */
+	} else {
+		errn = encodeBoolean(stream, 0);
+	}
+	if (errn == 0) {
+		errn = encodeUnsignedIntegerBig(stream, size, data, len);
+	}
+	return errn;
 }
 
 /**

+ 36 - 2
src/codec/EncoderChannel.h

@@ -146,7 +146,24 @@ int encodeUnsignedInteger32(bitstream_t* stream, uint32_t n);
  * \return                  	Error-Code <> 0
  *
  */
-int encodeUnsignedInteger64(bitstream_t* stream, uint64_t n);
+int encodeUnsignedInteger64(bitstream_t* stream, uint64_t n);
+
+/**
+ * \brief 		Encode unsigned integer
+ *
+ * 				Encode an arbitrary precision non negative integer using
+ * 				a sequence of octets. The most significant bit of the last
+ * 				octet is set to zero to indicate sequence termination.
+ * 				Only seven bits per octet are used to store the integer's value.
+ *
+ * \param       stream   		Output Stream
+ * \param       size		   	size array
+ * \param       data		   	data array
+ * \param       len		   		length array
+ * \return                  	Error-Code <> 0
+ *
+ */
+int encodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t len);
 
 
 /**
@@ -210,7 +227,24 @@ int encodeInteger32(bitstream_t* stream, int32_t n);
  *
  */
 int encodeInteger64(bitstream_t* stream, int64_t n);
-
+
+/**
+ * \brief 		Encode integer
+ *
+ * 				Encode an arbitrary precision integer using a sign boolean
+ * 				followed by a sequence of octets. The most significant bit
+ * 				of the last octet is set to zero to indicate sequence termination.
+ * 				Only seven bits per octet are used to store the integer's value.
+ *
+ * \param       stream   		Output Stream
+ * \param       negative		negative integer
+ * \param       size		   	size array
+ * \param       data		   	data array
+ * \param       len		   		length array
+ * \return                  	Error-Code <> 0
+ *
+ */
+int encodeIntegerBig(bitstream_t* stream, int negative, size_t size, uint8_t* data, size_t len);
 
 /**
  * \brief 		Encode float

+ 14 - 1
src/iso1/iso1EXIDatatypes.h

@@ -464,6 +464,7 @@ struct iso1KeyValueType {
 
 /* Complex type name='http://www.w3.org/2000/09/xmldsig#,X509IssuerSerialType',  base type name='anyType',  content type='ELEMENT',  isAbstract='false',  hasTypeId='false',  final='0',  block='0',  particle='("http://www.w3.org/2000/09/xmldsig#":X509IssuerName,"http://www.w3.org/2000/09/xmldsig#":X509SerialNumber)',  derivedBy='RESTRICTION'.  */
 #define iso1X509IssuerSerialType_X509IssuerName_CHARACTERS_SIZE 50 + EXTRA_CHAR 
+uint8_t characters[20];
 struct iso1X509IssuerSerialType {
 	/* element: "http://www.w3.org/2000/09/xmldsig#":X509IssuerName, http://www.w3.org/2001/XMLSchema,string */
 	struct {
@@ -471,7 +472,19 @@ struct iso1X509IssuerSerialType {
 		uint16_t charactersLen;
 	}  X509IssuerName ;
 	/* element: "http://www.w3.org/2000/09/xmldsig#":X509SerialNumber, http://www.w3.org/2001/XMLSchema,integer */
-	int64_t X509SerialNumber ;
+	/* int64_t X509SerialNumber; */
+	struct {
+		/** a sign value */
+		int negative;
+		/* container size */
+		size_t size;
+		/** array data container */
+		/* For negative values, the Unsigned Integer holds the
+		 * magnitude of the value minus 1 */
+		uint8_t* data;
+		/** array length (len <= size) */
+		size_t len;
+	} X509SerialNumber;
 };
 
 typedef enum {

+ 1 - 1
src/iso1/iso1EXIDatatypesDecoder.c

@@ -8060,7 +8060,7 @@ static int decode_iso1X509IssuerSerialType(bitstream_t* stream, struct iso1X509I
 					errn = decodeNBitUnsignedInteger(stream, 1, &eventCode);
 					if(errn == 0) {
 						if(eventCode == 0) {
-							errn = decodeInteger64(stream, &iso1X509IssuerSerialType->X509SerialNumber);
+							errn = decodeIntegerBig(stream, &iso1X509IssuerSerialType->X509SerialNumber.negative, iso1X509IssuerSerialType->X509SerialNumber.size, iso1X509IssuerSerialType->X509SerialNumber.data, &iso1X509IssuerSerialType->X509SerialNumber.len);
 						} else {
 							/* Second level event (e.g., xsi:type, xsi:nil, ...) */
 							errn = EXI_UNSUPPORTED_EVENT_CODE_CHARACTERISTICS;

+ 2 - 1
src/iso1/iso1EXIDatatypesEncoder.c

@@ -5814,7 +5814,8 @@ static int encode_iso1X509IssuerSerialType(bitstream_t* stream, struct iso1X509I
 					/* First(xsi:type)StartTag[CHARACTERS[INTEGER]] */
 					errn = encodeNBitUnsignedInteger(stream, 1, 0);
 					if(errn == 0) {
-						errn = encodeInteger64(stream, iso1X509IssuerSerialType->X509SerialNumber);
+						/* errn = encodeInteger64(stream, iso1X509IssuerSerialType->X509SerialNumber); */
+						errn = encodeIntegerBig(stream, iso1X509IssuerSerialType->X509SerialNumber.negative, iso1X509IssuerSerialType->X509SerialNumber.size, iso1X509IssuerSerialType->X509SerialNumber.data, iso1X509IssuerSerialType->X509SerialNumber.len);
 						/* valid EE */
 						errn = encodeNBitUnsignedInteger(stream, 1, 0);
 					}