date decoding fixes and tests
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 34d4dbc..00b10cb 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -33,7 +33,11 @@
#include "qcbor/qcbor_decode.h"
#include "qcbor/qcbor_spiffy_decode.h"
-#include "ieee754.h"
+#include "ieee754.h" // Does not use math.h
+
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#include <math.h> // For isnan(). TODO: list
+#endif
/*
@@ -1549,7 +1553,7 @@
*/
static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
{
- QCBORError nReturn = QCBOR_SUCCESS;
+ QCBORError uReturn = QCBOR_SUCCESS;
pDecodedItem->val.epochDate.fSecondsFraction = 0;
@@ -1560,11 +1564,10 @@
break;
case QCBOR_TYPE_UINT64:
- if(pDecodedItem->val.uint64 > INT64_MAX) {
- nReturn = QCBOR_ERR_DATE_OVERFLOW;
- goto Done;
- }
- pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
+ // This only happens for CBOR type 0 > INT64_MAX so it is
+ // always an overflow.
+ uReturn = QCBOR_ERR_DATE_OVERFLOW;
+ goto Done;
break;
case QCBOR_TYPE_DOUBLE:
@@ -1590,13 +1593,16 @@
//
// Without the 0x7ff there is a ~30 minute range of time
// values 10 billion years in the past and in the future
- // where this this code would go wrong and some compilers
- // will generate warnings or errors.
+ // where this code would go wrong. Some compilers
+ // will generate warnings or errors without the 0x7ff
+ // because of the precision issue.
const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
pDecodedItem->val.dfnum :
(double)pDecodedItem->val.fnum;
- if(d > (double)(INT64_MAX - 0x7ff)) {
- nReturn = QCBOR_ERR_DATE_OVERFLOW;
+ if(isnan(d) ||
+ d > (double)(INT64_MAX - 0x7ff) ||
+ d < (double)(INT64_MIN + 0x7ff)) {
+ uReturn = QCBOR_ERR_DATE_OVERFLOW;
goto Done;
}
pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
@@ -1604,24 +1610,23 @@
d - (double)pDecodedItem->val.epochDate.nSeconds;
}
#else
- /* Disabling float support causes a floating point
- data to error in the default below. The above code
- requires floating point conversion to integers and
- comparison which requires either floating point HW
+ /* Disabling float support causes a floating-point
+ date to error in the default below. The above code
+ requires floating-point conversion to integers and
+ comparison which requires either floating-point HW
or a SW library. */
- nReturn = QCBOR_ERR_FLOAT_DATE_DISABLED;
+ uReturn = QCBOR_ERR_FLOAT_DATE_DISABLED;
#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
break;
-
default:
- nReturn = QCBOR_ERR_BAD_OPT_TAG;
+ uReturn = QCBOR_ERR_BAD_OPT_TAG;
goto Done;
}
pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
Done:
- return nReturn;
+ return uReturn;
}
@@ -2481,8 +2486,8 @@
/* Get the item */
QCBORItem Item;
uReturn = QCBORDecode_GetNext(pMe, &Item);
- if(uReturn != QCBOR_SUCCESS) {
- /* Got non-well-formed CBOR */
+ if(QCBORDecode_IsNotWellFormed(uReturn)) {
+ /* Got non-well-formed CBOR so map can't even be decoded. */
goto Done;
}
@@ -2533,7 +2538,7 @@
to match the labels.
*/
uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
- if(uReturn) {
+ if(uReturn != QCBOR_SUCCESS) {
goto Done;
}
@@ -2549,8 +2554,8 @@
DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Done2:
- /* For all items not found, set the data type to QCBOR_TYPE_NONE */
- for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
+ /* For all items not found, set the data type to QCBOR_TYPE_NONE */
+ for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
if(!(uFoundItemBitMap & (0x01ULL << i))) {
pItemArray[i].uDataType = QCBOR_TYPE_NONE;
}
@@ -3215,6 +3220,91 @@
+
+
+static void ProcessEpochDate(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ // Already in error state, do nothing
+ return;
+ }
+
+ QCBORError uErr;
+
+ const TagSpecification TagSpec =
+ {
+ uTagRequirement,
+ {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
+ {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT}
+ };
+
+ // TODO: this will give a unexpected type error instead of
+ // overflow error for QCBOR_TYPE_UINT64 because TagSpec
+ // only has three target types.
+ uErr = CheckTagRequirement(TagSpec, pItem->uDataType);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
+ uErr = DecodeDateEpoch(pItem);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+ *pnTime = pItem->val.epochDate.nSeconds;
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+void QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ // Already in error state, do nothing
+ return;
+ }
+
+ QCBORItem Item;
+ pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
+
+ ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
+}
+
+
+void
+QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+ ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
+}
+
+
+void
+QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+ ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
+}
+
+
+
+
void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe,
TagSpecification TagSpec,
UsefulBufC *pBstr)
@@ -3529,8 +3619,6 @@
-#include <math.h>
-
static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
{