date decoding fixes and tests
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index bb53c24..bbcf2cd 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -338,7 +338,9 @@
double dfnum;
/** The value for @c uDataType @ref QCBOR_TYPE_FLOAT. */
float fnum;
- /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
+ /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH.
+ Floating-point dates that are NaN, +Inifinity or -Inifinity
+ decode with the @ref QCBOR_ERR_DATE_OVERFLOW error. */
struct {
int64_t nSeconds;
double fSecondsFraction;
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index 9af3a59..2b4ded7 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -640,21 +640,25 @@
@brief Decode the next item as an epoch date.
@param[in] pCtx The decode context.
- @param[in] uTagRequirement One of @c QCBOR_TAGSPEC_MATCH_XXX.
- @param[out] pnTime The decoded URI.
+ @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ @param[out] pnTime The decoded epoch date.
+
+ This will handle floating-point dates, but always returns them as an int64_t
+ discarding the fractional part. Use QCBORDecode_GetNext() instead of this to get the
+ fractional part.
See @ref Decode-Errors for discussion on how error handling works.
See @ref Tag-Matcing for discussion on tag requirements.
*/
-void QCBORDecode_GetEpocDate(QCBORDecodeContext *pCtx,
+void QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx,
uint8_t uTagRequirement,
int64_t *pnTime);
-static void QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime);
+void QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime);
void QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx,
const char *szLabel,
@@ -694,7 +698,7 @@
QCBORDecode_GetUInt64ConvertAll() and
QCBORDecode_GetDoubleConvertAll() which can convert big numbers.
*/
-// Improveent: Add function that at least convert integers
+// Improvement: Add function that at least convert integers to big nums
void QCBORDecode_GetBignum(QCBORDecodeContext *pCtx,
uint8_t uTagRequirement,
UsefulBufC *pValue,
@@ -961,8 +965,8 @@
Note that this doesn not actually remove the base64 encoding.
*/
static void QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
static void QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx,
int64_t nLabel,
@@ -1075,7 +1079,13 @@
This puts the decoder in bounded mode which narrows
decoding to the map entered and enables
- getting items by label.
+ getting items by label. Note that all items
+ in the map must be well-formed and valid to be
+ able to search it by label because a full traversal
+ is done for each search. If not, the search will
+ retun an error for the item that is not well-formed
+ and valid. This may not be the item with the label
+ that is the subject of the search.
Nested maps can be decoded like this by entering
each map in turn.
@@ -1697,6 +1707,7 @@
// Semi private
#define QCBOR_TAGSPEC_NUM_TYPES 3
+// TODO: make content types 4 to help out epoch dates?
/* TODO: This structure can probably be rearranged so the initialization
of it takes much less code. */
typedef struct {
@@ -2196,27 +2207,6 @@
}
-inline static void
-QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *puTime)
-{
- const TagSpecification TagSpec =
- {
- uTagRequirement,
- {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
- {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_NONE}
- };
-
- QCBORItem Item;
- QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
- *puTime = Item.val.int64; // TODO: lots of work to do here to
- // handle the variety of date types
- // This can't stay as an inline function. May have to rewrite date handling
-}
-
-
#ifdef __cplusplus
}
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)
{
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 2d53f4b..d882d99 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -2101,9 +2101,15 @@
0xc0, // tag for string date
0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string
+ 0xc0, // tag for string date
+ 0x00, // Wrong type for a string date
+
0xc1, // tag for epoch date
0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
+ 0xc1,
+ 0x62, 'h', 'i', // wrong type tagged
+
// CBOR_TAG_B64
0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags
0x1a, 0x53, 0x72, 0x4E, 0x01,
@@ -2122,10 +2128,20 @@
//0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large
0xc1, // tag for epoch date
- 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe // 9223372036854773760 largest supported
+ 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported
+
+ 0xc1, // tag for epoch date
+ 0xfa, 0x7f, 0xc0, 0x00, 0x00, // Single-precision NaN
+
+ 0xc1,
+ 0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +infinity
+
+ 0xc1, // tag for epoch date
+ 0xf9, 0xfc, 0x00, // -Infinity
};
+
// have to check float expected only to within an epsilon
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
static int CHECK_EXPECTED_DOUBLE(double val, double expected) {
@@ -2142,69 +2158,79 @@
int32_t DateParseTest()
{
QCBORDecodeContext DCtx;
- QCBORItem Item;
- QCBORError nCBORError;
+ QCBORItem Item;
+ QCBORError uError;
QCBORDecode_Init(&DCtx,
UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput),
QCBOR_DECODE_MODE_NORMAL);
- const uint64_t uTags[] = {15};
- QCBORTagListIn TagList = {1, uTags};
-
- QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList);
-
// String date
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ if((uError = QCBORDecode_GetNext(&DCtx, &Item))) {
return -1;
+ }
if(Item.uDataType != QCBOR_TYPE_DATE_STRING ||
UsefulBuf_Compare(Item.val.dateString, UsefulBuf_FromSZ("1985-04-12"))){
return -2;
}
- // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ // Wrong type for a string date
+ uError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uError != QCBOR_ERR_BAD_OPT_TAG) {
return -3;
+ }
+
+ // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
+ if((uError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return -4;
+ }
if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
Item.val.epochDate.nSeconds != 1400000000 ||
Item.val.epochDate.fSecondsFraction != 0 ) {
- return -4;
+ return -5;
+ }
+
+ // Wrong type for an epoch date
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_OPT_TAG) {
+ return -6;
}
// Epoch date with extra CBOR_TAG_B64 tag that doesn't really mean anything
// but want to be sure extra tag doesn't cause a problem
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
- return -5;
+ if((uError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return -7;
+ }
if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
Item.val.epochDate.nSeconds != 1400000001 ||
Item.val.epochDate.fSecondsFraction != 0 ||
!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_B64)) {
- return -6;
+ return -8;
}
// Epoch date that is too large for our representation
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
- return -7;
+ return -9;
}
- // Epoch date in float format with fractional seconds
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
- return -8;
+ // Epoch date in float format with fractional seconds
+ if((uError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return -10;
+ }
if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
Item.val.epochDate.nSeconds != 1 ||
CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) {
- return -9;
+ return -11;
}
// Epoch date float that is too large for our representation
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
- return -10;
+ return -12;
}
// Epoch date double that is just slightly too large
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
- return -11;
+ return -13;
}
// Largest double epoch date supported
@@ -2212,30 +2238,188 @@
Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
Item.val.epochDate.nSeconds != 9223372036854773760 ||
Item.val.epochDate.nSeconds == 0) {
- return -12;
+ return -14;
}
+
+ // Nan
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
+ return -15;
+ }
+
+ // +Inifinity double-precision
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
+ return -16;
+ }
+
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+ // -Inifinity half-precision
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
+ return -17;
+ }
#else
- if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
- return -80;
- }
- if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
- return -80;
- }
- if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
- return -80;
- }
- if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
- return -80;
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_HALF_PRECISION_DISABLED) {
+ return -18;
}
#endif
+#else
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -19;
+ }
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -20;
+ }
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -21;
+ }
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -22;
+ }
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -23;
+ }
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -24;
+ }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_DISABLED) {
+ return -25;
+ }
+#else
+ if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_HALF_PRECISION_DISABLED) {
+ return -26;
+ }
+#endif
- // TODO: could use a few more tests with float, double, and half precsion
- // and negative (but coverage is still pretty good)
+#endif
return 0;
}
+
+static uint8_t spDateTestInput2[] = {
+ 0xbf,
+
+ 0x05,
+ 0xc1, // tag for epoch date
+ 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer
+
+ 0x00,
+ 0xc0, // tag for string date
+ 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string
+
+ 0x01,
+ 0xc1, // tag for epoch date
+ 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
+
+ // Untagged integer 0
+ 0x08,
+ 0x00,
+
+ // Utagged date string with string label y
+ 0x61, 0x79,
+ 0x6a, '2','0','8','5','-','0','4','-','1','2', // Date string
+
+ // Untagged -1000 with label z
+ 0x61, 0x7a,
+ 0x39, 0x03, 0xe7,
+
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+ 0x07,
+ 0xc1, // tag for epoch date
+ 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported
+
+ // Untagged single-precision float with value 3.14 with string label x
+ 0x61, 0x78,
+ 0xFA, 0x40, 0x48, 0xF5, 0xC3,
+
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+ // Untagged half-precision float with value -2
+ 0x09,
+ 0xF9, 0xC0, 0x00,
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+
+ 0xff,
+};
+
+int32_t SpiffyDateDecodeTest()
+{
+ QCBORDecodeContext DC;
+ //QCBORItem Item;
+ QCBORError uError;
+ int64_t nEpochDate1, nEpochDate3, nEpochDate6;
+ UsefulBufC StringDate1, StringDate2;
+
+ QCBORDecode_Init(&DC,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput2),
+ QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_EnterMap(&DC);
+ QCBORDecode_GetEpochDateInMapN(&DC, 5, QCBOR_TAG_REQUIREMENT_MATCH_TAG, &nEpochDate1);
+ uError = QCBORDecode_GetAndResetError(&DC);
+ if(uError == QCBOR_SUCCESS) {
+ return -999;
+ }
+ QCBORDecode_GetEpochDateInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_MATCH_TAG, &nEpochDate1);
+ QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &StringDate1);
+ QCBORDecode_GetEpochDateInMapN(&DC, 8, QCBOR_TAG_REQUIREMENT_NO_TAG, &nEpochDate3);
+ QCBORDecode_GetDateStringInMapSZ(&DC, "y", QCBOR_TAG_REQUIREMENT_NO_TAG, &StringDate2);
+ QCBORDecode_GetEpochDateInMapSZ(&DC, "z", QCBOR_TAG_REQUIREMENT_NO_TAG, &nEpochDate6);
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+ int64_t nEpochDate5, nEpochDate2;
+ QCBORDecode_GetEpochDateInMapN(&DC, 7, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &nEpochDate2);
+ QCBORDecode_GetEpochDateInMapSZ(&DC, "x", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &nEpochDate5);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+ int64_t nEpochDate4;
+ QCBORDecode_GetEpochDateInMapN(&DC, 9, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &nEpochDate4);
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+
+ QCBORDecode_ExitMap(&DC);
+ uError = QCBORDecode_Finish(&DC);
+ if(uError) {
+ return 1;
+ }
+
+ if(nEpochDate1 != 1400000000) {
+ return 100;
+ }
+
+ if(nEpochDate3 != 0) {
+ return 102;
+ }
+
+ if(nEpochDate6 != -1000) {
+ return 105;
+ }
+
+ if(UsefulBuf_Compare(StringDate1, UsefulBuf_FromSZ("1985-04-12"))) {
+ return 106;
+ }
+
+ if(UsefulBuf_Compare(StringDate2, UsefulBuf_FromSZ("2085-04-12"))) {
+ return 107;
+ }
+
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+ if(nEpochDate2 != 9223372036854773760ULL) {
+ return 101;
+ }
+ if(nEpochDate5 != 3) {
+ return 104;
+ }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+ if(nEpochDate4 != -2) {
+ return 103;
+ }
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+
+ return 0;
+}
+
+
+
// Really simple basic input for tagging test
static uint8_t spOptTestInput[] = {
0xd9, 0xd9, 0xf7, // CBOR magic number
@@ -4724,9 +4908,15 @@
if(Item.uDataType != QCBOR_TYPE_DATE_STRING) {
return 2;
}
-
+
// Get a second item
uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_ERR_BAD_OPT_TAG) {
+ return 66;
+ }
+
+ // Get a third item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(uCBORError != QCBOR_SUCCESS) {
return 2;
}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 08f1759..d0ba252 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -161,12 +161,18 @@
/*
- Thest the date types -- epoch and strings
+ Test the date types -- epoch and strings
*/
int32_t DateParseTest(void);
/*
+ Test spiffy date decoding functions
+ */
+int32_t SpiffyDateDecodeTest(void);
+
+
+/*
Test optional tags like the CBOR magic number.
*/
int32_t OptTagParseTest(void);
diff --git a/test/run_tests.c b/test/run_tests.c
index 0adccd4..be180a7 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -87,6 +87,7 @@
TEST_ENTRY(BignumParseTest),
TEST_ENTRY(OptTagParseTest),
TEST_ENTRY(DateParseTest),
+ TEST_ENTRY(SpiffyDateDecodeTest),
TEST_ENTRY(ShortBufferParseTest2),
TEST_ENTRY(ShortBufferParseTest),
TEST_ENTRY(ParseDeepArrayTest),