diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h index 1ace2bae..afcb8a5a 100644 --- a/inc/qcbor/qcbor_decode.h +++ b/inc/qcbor/qcbor_decode.h @@ -198,7 +198,7 @@ typedef enum { } QCBORDecodeMode; /** - * The maximum size of input to the decoder. Slightly less than UINT32_MAX + * The maximum size of input to the decoder. Slightly less than @c UINT32_MAX * to make room for some special indicator values. */ #define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2) @@ -1034,38 +1034,36 @@ QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - /** * @brief Get the current traversal cursort offset in the input CBOR. * - * @param[in] pCtx The decoder context. + * @param[in] pCtx The decoder context. * * @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, @c UINT32_MAX + * If the cursor is at the end of the input or in the error state, @c UINT32_MAX * is returned. * * When decoding map items, the * position returned is always of the label, never the * value. * - * For indefinite-length items, the CBOR break bytes are consumed - * when the last item in an indefinite length array or map is consumed + * For indefinite-length arrays and maps, the break byte is consumed + * when the last item in the array or map is consumed * so the cursor is at the next item to be decoded as expected. * * There are some special rules for the traversal cursor when - * fetching map items by label. See the decription of @SpiffyDecode. + * fetching map items by label. See the description of @SpiffyDecode. * - * There is no corresponding seek because it is too complicated + * There is no corresponding seek method because it is too complicated * to restore the internal decoder state that tracks nesting. */ uint32_t QCBORDecode_Tell(QCBORDecodeContext *pCtx); - /** * @brief Returns the tag numbers for an item. * @@ -1092,7 +1090,7 @@ QCBORDecode_Tell(QCBORDecodeContext *pCtx); * See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. * * To reduce memory used by a QCBORItem, tag numbers larger than - * UINT16_MAX are mapped so the tag numbers in @c uTags should be + * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be * accessed with this function rather than directly. * * This returns @ref CBOR_TAG_INVALID64 if any error occurred when @@ -1305,8 +1303,8 @@ QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError); * @return 0 on success -1 if not * * When decoding an integer, the CBOR decoder will return the value as - * an int64_t unless the integer is in the range of @c INT64_MAX and @c - * UINT64_MAX. That is, unless the value is so large that it can only be + * an int64_t unless the integer is in the range of @c INT64_MAX and + * @c UINT64_MAX. That is, unless the value is so large that it can only be * represented as a @c uint64_t, it will be an @c int64_t. * * CBOR itself doesn't size the individual integers it carries at @@ -1518,7 +1516,7 @@ QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, * been decoded. * * This is not backwards compatibile in two ways. First, it is limited - * to \ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was + * to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was * unlimited. Second, it will not inlucde the tags that QCBOR decodes * internally. * diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c index 146e10e2..799fff25 100644 --- a/src/qcbor_decode.c +++ b/src/qcbor_decode.c @@ -3138,22 +3138,20 @@ QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) uint32_t QCBORDecode_Tell(QCBORDecodeContext *pMe) { - size_t xx; + size_t uCursorOffset; - xx = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf)); - - if(xx == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) { + if(pMe->uLastError != QCBOR_SUCCESS) { return UINT32_MAX; - } else { - return (uint32_t)xx; } - /* + uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); - Confirm position is as expected in maps and arrays for - - definite length - - indefinite lengths - */ + if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) { + return UINT32_MAX; + } else { + /* Cast is safe because decoder input size is restricted. */ + return (uint32_t)uCursorOffset; + } } diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c index 321a7336..7b3d828e 100644 --- a/test/qcbor_decode_tests.c +++ b/test/qcbor_decode_tests.c @@ -8929,8 +8929,8 @@ int32_t TellTests(void) QCBORDecodeContext DCtx; QCBORItem Item; uint32_t uPosition; - int i; - int64_t n; + int nIndex; + int64_t nDecodedInt; static const uint32_t aPos[] = {0, 1, 17, 42, 50, 58, 72, 85, 98, 112, UINT32_MAX}; @@ -8943,10 +8943,10 @@ int32_t TellTests(void) 0); - for(i = 0; ; i++) { + for(nIndex = 0; ; nIndex++) { uPosition = QCBORDecode_Tell(&DCtx); - if(uPosition != aPos[i]) { - return i; + if(uPosition != aPos[nIndex]) { + return nIndex; } if(uPosition == UINT32_MAX) { @@ -8960,10 +8960,10 @@ int32_t TellTests(void) UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), 0); - for(i = 0; ; i++) { + for(nIndex = 0; ; nIndex++) { uPosition = QCBORDecode_Tell(&DCtx); - if(uPosition != aPosIndef[i]) { - return i + 100; + if(uPosition != aPosIndef[nIndex]) { + return nIndex + 100; } if(uPosition == UINT32_MAX) { @@ -8979,45 +8979,187 @@ int32_t TellTests(void) 0); QCBORDecode_EnterMap(&DCtx, &Item); if(QCBORDecode_Tell(&DCtx) != 1) { - return 200; + return 1001; } - QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &n); + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt); if(QCBORDecode_Tell(&DCtx) != 1) { - return 200; + return 1002; } QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); if(QCBORDecode_Tell(&DCtx) != 72) { - return 201; + return 1003; } - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &n); - if(n != 98) { - return 99; + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 1004; } /* Getting non-aggregate types doesn't affect cursor position. */ if(QCBORDecode_Tell(&DCtx) != 72) { - return 200; + return 1005; } QCBORDecode_VGetNext(&DCtx, &Item); if(QCBORDecode_Tell(&DCtx) != 85) { - return 202; + return 1006; } - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &n); - if(n != 98) { - return 99; + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 1007; } /* Getting non-aggregate types doesn't affect cursor position. */ if(QCBORDecode_Tell(&DCtx) != 85) { - return 200; + return 1008; } QCBORDecode_ExitMap(&DCtx); if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { - return 203; + return 1009; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 1010; + } + + + /* Next, some tests with entered maps and arrays */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), + 0); + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 2000; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 2001; + } + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + if(QCBORDecode_Tell(&DCtx) != 73) { + return 2002; + } + + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 2003; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 73) { + return 2004; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 86) { + return 2005; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 2006; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 86) { + return 2007; + } + + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 2008; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2010; + } + + + /* Error state test */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + 0); + /* Cause an error */ + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 3000; } + /* Empties tests */ + const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 4000; + } + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4001; + } + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 4002; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4001; + } + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 4002; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4010; + } + const uint8_t pMinimalIndefCBOR[] = {0xbf, 0xff}; // One empty map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalIndefCBOR),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 4100; + } + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4101; + } + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 4102; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4101; + } + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 4102; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4110; + } + /* Test on a CBOR sequence */ + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 5000; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5001; + } + if(QCBORDecode_Tell(&DCtx) != 11) { + return 5002; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5003; + } + if(QCBORDecode_Tell(&DCtx) != 12) { + return 5004; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5005; + } + if(QCBORDecode_Tell(&DCtx) != 17) { + return 5006; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5007; + } + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 5008; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 5010; + } return 0; }