Add EndCheck(); change QCBORDecode_Tell() behavior (#231)
QCBORDecode_Tell() returns the offset when at the end of the input rather than UINT32_MAX. This is a non-compatible change, but QCBORDecode_Tell() was very recently introduced and is not present in any official releases.
QCBORDecode_EndCheck() is added to check to see if the cursor is at the end of the input.
Addresses #230
* Add EndCheck(); change Tell() behavior
* Minor corrections
* Minor doc update
---------
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 918d162..387d3af 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -1053,9 +1053,13 @@
* @returns The traversal cursor offset or @c UINT32_MAX.
* The position returned is always the start of the next item that
- * would be next decoded with QCBORDecode_VGetNext(). If the cursor
- * is at the end of the input or in the error state, @c UINT32_MAX is
- * returned.
+ * would be next decoded with QCBORDecode_VGetNext(). The cursor
+ * returned may be at the end of the input in which case the next call
+ * to QCBORDecode_VGetNext() will result in the @ref
+ * QCBOR_ERR_NO_MORE_ITEMS. See also QCBORDecode_AtEnd().
+ *
+ * If the decoder is in error state from previous decoding,
+ * @c UINT32_MAX is returned.
*
* When decoding map items, the position returned is always of the
* label, never the value.
@@ -1083,11 +1087,27 @@
* There is no corresponding seek method because it is too complicated
* to restore the internal decoder state that tracks nesting.
*/
-uint32_t
+static uint32_t
QCBORDecode_Tell(QCBORDecodeContext *pCtx);
/**
+ * @brief Tell whether cursor is at end of the input.
+ *
+ * @param[in] pCtx The decoder context.
+ *
+ * @returns Error code possibly indicating end of input.
+ *
+ * This returns the same as QCBORDecode_GetError() except that @ref
+ * QCBOR_ERR_NO_MORE_ITEMS is returned if the travseral cursor is at
+ * the end of the CBOR input bytes (not the end of an entered array or
+ * map).
+ */
+QCBORError
+QCBORDecode_EndCheck(QCBORDecodeContext *pCtx);
+
+
+/**
* @brief Returns the tag numbers for an item.
*
* @param[in] pCtx The decoder context.
@@ -1567,6 +1587,17 @@
* Inline implementations of public functions defined above.
* ---- */
+static inline uint32_t
+QCBORDecode_Tell(QCBORDecodeContext *pMe)
+{
+ if(pMe->uLastError) {
+ return UINT32_MAX;
+ }
+
+ /* Cast is safe because decoder input size is restricted. */
+ return (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
+}
+
static inline QCBORError
QCBORDecode_GetError(QCBORDecodeContext *pMe)
{
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 3ed4d0f..9bd518e 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -3219,23 +3219,24 @@
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
-uint32_t
-QCBORDecode_Tell(QCBORDecodeContext *pMe)
+QCBORError
+QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
{
- size_t uCursorOffset;
+ size_t uCursorOffset;
+ QCBORError uErr;
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return UINT32_MAX;
+ uErr = QCBORDecode_GetError(pMe);
+ if(uErr != QCBOR_SUCCESS) {
+ return uErr;
}
uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
- return UINT32_MAX;
- } else {
- /* Cast is safe because decoder input size is restricted. */
- return (uint32_t)uCursorOffset;
+ return QCBOR_ERR_NO_MORE_ITEMS;
}
+
+ return QCBOR_SUCCESS;
}
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 0f48613..b79772d 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -10057,7 +10057,7 @@
// Improvement: rewrite so this can run with only integer labels
static const uint32_t aPos[] =
- {0, 1, 17, 42, 50, 58, 72, 85, 98, 112, UINT32_MAX};
+ {0, 1, 17, 42, 50, 58, 72, 85, 98, 112, 151};
QCBORDecode_Init(&DCtx,
UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
0);
@@ -10067,7 +10067,7 @@
return nIndex;
}
- if(uPosition == UINT32_MAX) {
+ if(QCBORDecode_EndCheck(&DCtx)) {
break;
}
@@ -10076,7 +10076,7 @@
#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
static const uint32_t aPosIndef[] =
- {0, 1, 17, 42, 50, 59, 73, 86, 99, 113, UINT32_MAX};
+ {0, 1, 17, 42, 50, 59, 73, 86, 99, 113, 154};
QCBORDecode_Init(&DCtx,
UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded),
0);
@@ -10087,7 +10087,7 @@
return nIndex + 100;
}
- if(uPosition == UINT32_MAX) {
+ if(QCBORDecode_EndCheck(&DCtx)) {
break;
}
@@ -10134,7 +10134,7 @@
}
QCBORDecode_ExitMap(&DCtx);
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+ if(QCBORDecode_Tell(&DCtx) != 151) {
return 1009;
}
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
@@ -10181,7 +10181,7 @@
}
QCBORDecode_ExitMap(&DCtx);
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+ if(QCBORDecode_Tell(&DCtx) != 154) {
return 2008;
}
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
@@ -10200,6 +10200,10 @@
if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
return 3000;
}
+ if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_MAP_NOT_ENTERED) {
+ return 3001;
+ }
+
/* Empties tests */
const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map
@@ -10207,19 +10211,25 @@
if(QCBORDecode_Tell(&DCtx) != 0) {
return 4000;
}
+ if(QCBORDecode_EndCheck(&DCtx) != QCBOR_SUCCESS) {
+ return 4008;
+ }
QCBORDecode_EnterMap(&DCtx, &Item);
if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
return 4001;
}
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+ if(QCBORDecode_Tell(&DCtx) != 1) {
return 4002;
}
QCBORDecode_ExitMap(&DCtx);
if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
- return 4001;
+ return 4003;
}
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
- return 4002;
+ if(QCBORDecode_Tell(&DCtx) != 1) {
+ return 4004;
+ }
+ if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) {
+ return 4005;
}
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
return 4010;
@@ -10235,15 +10245,18 @@
if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
return 4101;
}
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+ if(QCBORDecode_Tell(&DCtx) != 2) {
return 4102;
}
QCBORDecode_ExitMap(&DCtx);
if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
- return 4101;
+ return 4103;
}
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
- return 4102;
+ if(QCBORDecode_Tell(&DCtx) != 2) {
+ return 4104;
+ }
+ if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) {
+ return 4005;
}
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
return 4110;
@@ -10280,7 +10293,7 @@
if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
return 5007;
}
- if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+ if(QCBORDecode_Tell(&DCtx) != 20) {
return 5008;
}
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
@@ -10315,7 +10328,7 @@
}
static const uint32_t aEmptiesPos[] =
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, UINT32_MAX};
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15};
QCBORDecode_Init(&DCtx,
UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties),
0);
@@ -10325,7 +10338,7 @@
return nIndex + 200;
}
- if(uPosition == UINT32_MAX) {
+ if(QCBORDecode_EndCheck(&DCtx)) {
break;
}
@@ -10334,7 +10347,7 @@
#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
static const uint32_t aIndefEmptiesPos[] =
- {0, 1, 2, 4, 5, 7, 8, 10, 12, 13, 16, 19, UINT32_MAX};
+ {0, 1, 2, 4, 5, 7, 8, 10, 12, 13, 16, 19, 25};
QCBORDecode_Init(&DCtx,
UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmptiesIndef),
0);
@@ -10344,7 +10357,7 @@
return nIndex + 300;
}
- if(uPosition == UINT32_MAX) {
+ if(QCBORDecode_EndCheck(&DCtx)) {
break;
}