Move tag-related and spiffy-related code to their own source files
qcbor_decode.c was just too big
* Move all tag-related code into qcbor_tag_decode.[ch]
* split out spiffy decode source and DecodeNesting
---------
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/src/decode_nesting.h b/src/decode_nesting.h
new file mode 100644
index 0000000..0e1c3a1
--- /dev/null
+++ b/src/decode_nesting.h
@@ -0,0 +1,419 @@
+/* ==========================================================================
+ * decode_nesting.c -- All inline implementation of QCBORDecodeNesting
+ *
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2021, Arm Limited.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Forked from qcbor_decode.c on 11/28/24
+ * ========================================================================== */
+
+#ifndef decode_nesting_h
+#define decode_nesting_h
+
+#include "qcbor/qcbor_private.h"
+
+
+/* When this was not all explicitly inline, the compiler decided to
+ * inline everything on its own, so we know there's no loss by
+ * making it all inline.
+ */
+
+static inline void
+DecodeNesting_Init(QCBORDecodeNesting *pNesting)
+{
+ /* Assumes that *pNesting has been zero'd before this call. */
+ pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
+ pNesting->pCurrent = &(pNesting->pLevels[0]);
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ /* Not a map or array */
+ return false;
+ }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+ if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
+ /* Is indefinite */
+ return false;
+ }
+
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+ /* All checks passed; is a definte length map or array */
+ return true;
+}
+
+
+static inline bool
+DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
+{
+ if(pNesting->pCurrentBounded == NULL) {
+ return false;
+ }
+
+ uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
+ if(uItemDataType != uType) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ return true;
+ }
+ if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
+ return true;
+ }
+ return false;
+}
+
+
+static inline bool
+DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrentBounded == NULL) {
+ /* No bounded map or array set up */
+ return false;
+ }
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ /* Not a map or array; end of those is by byte count */
+ return false;
+ }
+ if(!DecodeNesting_IsCurrentBounded(pNesting)) {
+ /* In a traveral at a level deeper than the bounded level */
+ return false;
+ }
+ /* Works for both definite- and indefinitelength maps/arrays */
+ if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
+ pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ /* Count is not zero, still unconsumed item */
+ return false;
+ }
+ /* All checks passed, got to the end of an array or map*/
+ return true;
+}
+
+
+static inline bool
+DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
+{
+ /* Must only be called on map / array */
+ if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ /* is a byte string */
+ return true;
+ }
+ return false;
+}
+
+
+static inline uint8_t
+DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
+{
+ const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
+ /* Limit in DecodeNesting_Descend against more than
+ * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
+ */
+ return (uint8_t)nLevel;
+}
+
+
+
+
+static inline void
+DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ /* Only call on a definite-length array / map */
+ pNesting->pCurrent->u.ma.uCountCursor--;
+}
+
+
+static inline void
+DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent->u.ma.uCountCursor = 0;
+}
+
+static inline void
+DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+ }
+}
+
+static inline void
+DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
+{
+ /* Only call on a definite-length array / map */
+ pNesting->pCurrent->u.ma.uCountCursor++;
+}
+
+
+
+
+static inline void
+DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
+}
+
+
+static inline QCBORError
+DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
+{
+ /* Error out if nesting is too deep */
+ if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
+ return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
+ }
+
+ /* The actual descend */
+ pNesting->pCurrent++;
+
+ pNesting->pCurrent->uLevelType = uType;
+
+ return QCBOR_SUCCESS;
+}
+
+static inline QCBORError
+DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
+ const uint8_t uQCBORType,
+ const uint16_t uCount)
+{
+ QCBORError uError = QCBOR_SUCCESS;
+
+ if(uCount == 0) {
+ /* Nothing to do for empty definite-length arrays. They are just are
+ * effectively the same as an item that is not a map or array.
+ */
+ goto Done;
+ /* Empty indefinite-length maps and arrays are handled elsewhere */
+ }
+
+ /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
+ * arrays and maps that are too long */
+
+ uError = DecodeNesting_Descend(pNesting, uQCBORType);
+ if(uError != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ pNesting->pCurrent->u.ma.uCountCursor = uCount;
+ pNesting->pCurrent->u.ma.uCountTotal = uCount;
+
+ DecodeNesting_ClearBoundedMode(pNesting);
+
+Done:
+ return uError;;
+}
+
+
+static inline QCBORError
+DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
+ uint32_t uEndOffset,
+ uint32_t uStartOffset)
+{
+ QCBORError uError;
+
+ uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
+ if(uError != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ /* Fill in the new byte string level */
+ pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
+ pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
+
+ /* Bstr wrapped levels are always bounded */
+ pNesting->pCurrentBounded = pNesting->pCurrent;
+
+Done:
+ return uError;;
+}
+
+
+static inline void
+DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent--;
+}
+
+
+
+
+static inline void
+DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent = pNesting->pCurrentBounded;
+}
+
+static inline void
+DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
+{
+ /* Should be only called on maps and arrays */
+ /*
+ * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
+ * larger than DecodeNesting_EnterBoundedMode which keeps it less than
+ * uin32_t so the cast is safe.
+ */
+ pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
+
+ if(bIsEmpty) {
+ pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
+ }
+}
+
+static inline QCBORError
+DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
+ bool bIsEmpty,
+ size_t uOffset)
+{
+ /*
+ * Should only be called on map/array.
+ *
+ * Have descended into this before this is called. The job here is
+ * just to mark it in bounded mode.
+ *
+ * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
+ * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
+ *
+ * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
+ */
+ if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ return QCBOR_ERR_INPUT_TOO_LARGE;
+ }
+
+ pNesting->pCurrentBounded = pNesting->pCurrent;
+
+ DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
+
+ return QCBOR_SUCCESS;
+}
+
+
+static inline uint32_t
+DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
+{
+ return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
+}
+
+
+static inline uint8_t
+DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
+{
+ const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
+ /* Limit in DecodeNesting_Descend against more than
+ * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
+ */
+ return (uint8_t)nLevel;
+}
+
+
+
+
+static inline uint32_t
+DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
+{
+ return pNesting->pCurrentBounded->u.ma.uStartOffset;
+}
+
+
+static inline void
+DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent = pNesting->pCurrentBounded - 1;
+}
+
+
+static inline void
+DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
+{
+ while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
+ pNesting->pCurrentBounded--;
+ if(DecodeNesting_IsCurrentBounded(pNesting)) {
+ break;
+ }
+ }
+}
+
+
+
+
+static inline void
+DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
+ QCBORDecodeNesting *pSave)
+{
+ *pSave = *pNesting;
+}
+
+
+static inline void
+DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
+ const QCBORDecodeNesting *pSave)
+{
+ *pNesting = *pSave;
+}
+
+#endif /* decode_nesting_h */
diff --git a/src/decode_private.h b/src/decode_private.h
index 506c668..c1d6f9f 100644
--- a/src/decode_private.h
+++ b/src/decode_private.h
@@ -1,79 +1,113 @@
-/*==============================================================================
- Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2024, Laurence Lundblade.
- Copyright (c) 2021, Arm Limited.
- All rights reserved.
+/* ==========================================================================
+ * decode_private.c -- semi-private & inline functions for qcbor_decode.c
+ *
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2021, Arm Limited.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Forked from qcbor_decode.c on 11/14/24
+ * ========================================================================== */
- Created on 11/14/24 from qcbor_decode.c
-
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors, nor the name "Laurence Lundblade" may be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- =============================================================================*/
#ifndef decode_private_h
#define decode_private_h
+#include "qcbor/qcbor_decode.h"
+#include "qcbor/qcbor_spiffy_decode.h" /* For QCBORItemCallback */
+/* These are decode functions used by the spiffy decode and number decode
+ * implementation. They are internal linkage and nothing to do with
+ * the public decode interface.
+ */
+
+/* Semi-private function. See qcbor_decode.c */
QCBORError
QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
QCBORItem *pDecodedItem);
-void
-QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumbers[],
- QCBORTagContentCallBack *pfCB,
- size_t uOffset);
-
-void
-QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- size_t uOffset);
-
+/* Semi-private function. See qcbor_decode.c */
void
QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset);
+ const char *szLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset);
+/* Semi-private function. See qcbor_decode.c */
void
QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset);
+ const int64_t nLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset);
+
+
+/* Semi-private function. See qcbor_decode.c */
+uint64_t
+QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
+ const uint16_t uMappedTagNumber);
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
+ const QCBORItem *pItemToConsume,
+ bool *pbBreak,
+ uint8_t *puNextNestLevel);
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
+ QCBORError uErr,
+ const size_t uOffset,
+ QCBORItem *pDecodedItem);
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe,
+ bool bMarkEnd,
+ bool *pbBreak);
+
+
+typedef struct {
+ void *pCBContext;
+ QCBORItemCallback pfCallback;
+} MapSearchCallBack;
+
+typedef struct {
+ size_t uStartOffset;
+ uint16_t uItemCount;
+} MapSearchInfo;
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
+ QCBORItem *pItemArray,
+ MapSearchInfo *pInfo,
+ MapSearchCallBack *pCallBack);
+
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
+ const uint32_t uEndOffset);
+
+
+static inline void
+QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
+{
+#ifndef QCBOR_DISABLE_TAGS
+ memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
+#else /* ! QCBOR_DISABLE_TAGS */
+ (void)pMe;
+ (void)pItem;
+#endif /* ! QCBOR_DISABLE_TAGS */
+}
+
+
static inline void
QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
@@ -84,7 +118,7 @@
}
*uOffset = QCBORDecode_Tell(pMe);
-#else
+#else /* ! QCBOR_DISABLE_TAGS */
*uOffset = SIZE_MAX;
#endif /* ! QCBOR_DISABLE_TAGS */
@@ -92,4 +126,25 @@
}
+
+
+/* Semi-private function. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumbers[],
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset);
+
+/* Semi-private function. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumber,
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset);
#endif /* decode_private_h */
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 7e2abad..257f8e7 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -36,6 +36,9 @@
#include "qcbor/qcbor_spiffy_decode.h"
#include "qcbor/qcbor_tag_decode.h"
#include "ieee754.h" /* Does not use math.h */
+#include "decode_private.h"
+#include "decode_nesting.h"
+
#if (defined(__GNUC__) && !defined(__clang__))
@@ -127,453 +130,6 @@
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
}
-/* Return true if the labels in Item1 and Item2 are the same.
- Works only for integer and string labels. Returns false
- for any other type. */
-static bool
-QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
-{
- if(Item1.uLabelType == QCBOR_TYPE_INT64) {
- if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
- return true;
- }
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
- if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
- return true;
- }
- } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
- if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
- return true;
- }
- } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
- if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
- return true;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
- }
-
- /* Other label types are never matched */
- return false;
-}
-
-
-/*
- Returns true if Item1 and Item2 are the same type
- or if either are of QCBOR_TYPE_ANY.
- */
-static bool
-QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
-{
- if(Item1.uDataType == Item2.uDataType) {
- return true;
- } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
- return true;
- } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
- return true;
- }
- return false;
-}
-
-
-/*===========================================================================
- DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
- ===========================================================================*/
-
-/*
- * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
- * the data structure all these functions work on.
- */
-
-
-static uint8_t
-DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
-{
- const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
- /* Limit in DecodeNesting_Descend against more than
- * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
- */
- return (uint8_t)nLevel;
-}
-
-
-static uint8_t
-DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
-{
- const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
- /* Limit in DecodeNesting_Descend against more than
- * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
- */
- return (uint8_t)nLevel;
-}
-
-
-static uint32_t
-DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
-{
- return pNesting->pCurrentBounded->u.ma.uStartOffset;
-}
-
-
-static bool
-DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- /* Not a map or array */
- return false;
- }
-
-#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
- if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
- /* Is indefinite */
- return false;
- }
-
-#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
-
- /* All checks passed; is a definte length map or array */
- return true;
-}
-
-static bool
-DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- /* is a byte string */
- return true;
- }
- return false;
-}
-
-
-static bool
-DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- return true;
- }
- if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
- return true;
- }
- return false;
-}
-
-
-static void
-DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
-{
- /* Should be only called on maps and arrays */
- /*
- * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
- * larger than DecodeNesting_EnterBoundedMode which keeps it less than
- * uin32_t so the cast is safe.
- */
- pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
-
- if(bIsEmpty) {
- pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
- }
-}
-
-
-static void
-DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
-}
-
-
-static bool
-DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrentBounded == NULL) {
- /* No bounded map or array set up */
- return false;
- }
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- /* Not a map or array; end of those is by byte count */
- return false;
- }
- if(!DecodeNesting_IsCurrentBounded(pNesting)) {
- /* In a traveral at a level deeper than the bounded level */
- return false;
- }
- /* Works for both definite- and indefinitelength maps/arrays */
- if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
- pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
- /* Count is not zero, still unconsumed item */
- return false;
- }
- /* All checks passed, got to the end of an array or map*/
- return true;
-}
-
-
-static bool
-DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
-{
- /* Must only be called on map / array */
- if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
-{
- if(pNesting->pCurrentBounded == NULL) {
- return false;
- }
-
- uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
- uItemDataType = QCBOR_TYPE_ARRAY;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
- if(uItemDataType != uType) {
- return false;
- }
-
- return true;
-}
-
-
-static void
-DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
-{
- /* Only call on a definite-length array / map */
- pNesting->pCurrent->u.ma.uCountCursor--;
-}
-
-
-static void
-DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
-{
- /* Only call on a definite-length array / map */
- pNesting->pCurrent->u.ma.uCountCursor++;
-}
-
-
-static void
-DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent--;
-}
-
-
-static QCBORError
-DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
-{
- /* Error out if nesting is too deep */
- if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
- return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
- }
-
- /* The actual descend */
- pNesting->pCurrent++;
-
- pNesting->pCurrent->uLevelType = uType;
-
- return QCBOR_SUCCESS;
-}
-
-
-static QCBORError
-DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
- bool bIsEmpty,
- size_t uOffset)
-{
- /*
- * Should only be called on map/array.
- *
- * Have descended into this before this is called. The job here is
- * just to mark it in bounded mode.
- *
- * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
- * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
- *
- * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
- */
- if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
- return QCBOR_ERR_INPUT_TOO_LARGE;
- }
-
- pNesting->pCurrentBounded = pNesting->pCurrent;
-
- DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
-
- return QCBOR_SUCCESS;
-}
-
-
-static QCBORError
-DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
- const uint8_t uQCBORType,
- const uint16_t uCount)
-{
- QCBORError uError = QCBOR_SUCCESS;
-
- if(uCount == 0) {
- /* Nothing to do for empty definite-length arrays. They are just are
- * effectively the same as an item that is not a map or array.
- */
- goto Done;
- /* Empty indefinite-length maps and arrays are handled elsewhere */
- }
-
- /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
- * arrays and maps that are too long */
-
- uError = DecodeNesting_Descend(pNesting, uQCBORType);
- if(uError != QCBOR_SUCCESS) {
- goto Done;
- }
-
- pNesting->pCurrent->u.ma.uCountCursor = uCount;
- pNesting->pCurrent->u.ma.uCountTotal = uCount;
-
- DecodeNesting_ClearBoundedMode(pNesting);
-
-Done:
- return uError;;
-}
-
-
-static void
-DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent = pNesting->pCurrentBounded - 1;
-}
-
-
-static void
-DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
-{
- while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
- pNesting->pCurrentBounded--;
- if(DecodeNesting_IsCurrentBounded(pNesting)) {
- break;
- }
- }
-}
-
-
-static void
-DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent = pNesting->pCurrentBounded;
-}
-
-
-static QCBORError
-DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
- uint32_t uEndOffset,
- uint32_t uStartOffset)
-{
- QCBORError uError;
-
- uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
- if(uError != QCBOR_SUCCESS) {
- goto Done;
- }
-
- /* Fill in the new byte string level */
- pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
- pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
-
- /* Bstr wrapped levels are always bounded */
- pNesting->pCurrentBounded = pNesting->pCurrent;
-
-Done:
- return uError;;
-}
-
-
-static void
-DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent->u.ma.uCountCursor = 0;
-}
-
-
-static void
-DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
- pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
- }
-}
-
-
-static void
-DecodeNesting_Init(QCBORDecodeNesting *pNesting)
-{
- /* Assumes that *pNesting has been zero'd before this call. */
- pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
- pNesting->pCurrent = &(pNesting->pLevels[0]);
-}
-
-
-static void
-DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
- QCBORDecodeNesting *pSave)
-{
- *pSave = *pNesting;
-}
-
-
-static void
-DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
- const QCBORDecodeNesting *pSave)
-{
- *pNesting = *pSave;
-}
-
-
-static uint32_t
-DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
-{
- return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
-}
-
@@ -1791,7 +1347,7 @@
*
* This is the reverse of MapTagNumber()
*/
-static uint64_t
+uint64_t
QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
const uint16_t uMappedTagNumber)
{
@@ -2121,7 +1677,7 @@
*
* Improvement: this could reduced further if indef is disabled
*/
-static QCBORError
+QCBORError
QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
{
QCBORError uReturn;
@@ -2253,7 +1809,7 @@
* item count or finding CBOR breaks. It detects the ends of the
* top-level sequence and of bstr-wrapped CBOR by byte count.
*/
-static QCBORError
+QCBORError
QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
bool *pbBreak,
QCBORItem *pDecodedItem,
@@ -2440,7 +1996,7 @@
* map. In that case, this is just a pass through for @c puNextNestLevel
* since there is nothing to do.
*/
-static QCBORError
+QCBORError
QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
const QCBORItem *pItemToConsume,
bool *pbBreak,
@@ -2644,7 +2200,7 @@
}
#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
-static QCBORError
+QCBORError
QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
QCBORError uErr,
const size_t uOffset,
@@ -2732,17 +2288,6 @@
}
-static void
-QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
-{
-#ifndef QCBOR_DISABLE_TAGS
- memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
-#else
- (void)pMe;
- (void)pItem;
-#endif
-}
-
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
@@ -2809,99 +2354,18 @@
}
-#ifndef QCBOR_DISABLE_TAGS
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
-uint64_t
-QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- uint8_t uIndex)
+void
+QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
{
- if(pItem->uDataType == QCBOR_TYPE_NONE) {
- return CBOR_TAG_INVALID64;
+ QCBORDecode_VGetNext(pMe, pDecodedItem);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
+ &pDecodedItem->uNextNestLevel);
}
- if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-uint64_t
-QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
- uint8_t uIndex)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return CBOR_TAG_INVALID64;
- }
- if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-static uint64_t
-QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
- const uint16_t puTagNumbers[],
- const uint32_t uIndex)
-{
- uint32_t uArrayIndex;
-
- /* Find number of tag numbers */
- for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
- if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
- break;
- }
- }
- if(uIndex > uArrayIndex) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-uint64_t
-QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const uint32_t uIndex)
-{
- if(pItem->uDataType == QCBOR_TYPE_NONE) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-uint64_t
-QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
- uint32_t uIndex)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return CBOR_TAG_INVALID64;
- }
- if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
}
@@ -2909,52 +2373,129 @@
* Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError
-QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
{
- QCBORItem Item;
- size_t uOffset;
- QCBORError uErr;
+ size_t uCursorOffset;
+ QCBORError uErr;
- const QCBORDecodeNesting SaveNesting = pMe->nesting;
- const UsefulInputBuf Save = pMe->InBuf;
-
- uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
- if(uOffset == pMe->uTagNumberCheckOffset) {
- pMe->uTagNumberIndex++;
- } else {
- pMe->uTagNumberIndex = 0;
- }
-
- *puTagNumber = CBOR_TAG_INVALID64;
- uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
- if(uErr) {
+ uErr = QCBORDecode_GetError(pMe);
+ if(uErr != QCBOR_SUCCESS) {
return uErr;
}
- *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
- if(*puTagNumber == CBOR_TAG_INVALID64 ||
- QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
- pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
- }
- pMe->uTagNumberCheckOffset = uOffset;
+ uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
- pMe->nesting = SaveNesting;
- pMe->InBuf = Save;
+ if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
+ return QCBOR_ERR_NO_MORE_ITEMS;
+ }
return QCBOR_SUCCESS;
}
-/*
- * Public function, see header qcbor/qcbor_decode.h file
+/**
+ * @brief Semi-private. Get pointer, length and item for an array or map.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] uType CBOR major type, either array/map.
+ * @param[out] pItem The item for the array/map.
+ * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
+ *
+ * The next item to be decoded must be a map or array as specified by @c uType.
+ *
+ * @c pItem will be filled in with the label and tags of the array or map
+ * in addition to @c pEncodedCBOR giving the pointer and length of the
+ * encoded CBOR.
+ *
+ * When this is complete, the traversal cursor is at the end of the array or
+ * map that was retrieved.
*/
void
-QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
+ const uint8_t uType,
+ QCBORItem *pItem,
+ UsefulBufC *pEncodedCBOR)
{
- pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
+ QCBORError uErr;
+ uint8_t uNestLevel;
+ size_t uStartingCursor;
+ size_t uStartOfReturned;
+ size_t uEndOfReturned;
+ size_t uTempSaveCursor;
+ bool bInMap;
+ QCBORItem LabelItem;
+ bool EndedByBreak;
+
+ uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+ bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
+
+ /* Could call GetNext here, but don't need to because this
+ * is only interested in arrays and maps. TODO: switch to GetNext()? */
+ uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
+ if(uErr != QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)uErr;
+ return;
+ }
+
+ uint8_t uItemDataType = pItem->uDataType;
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
+ if(uItemDataType != uType) {
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ return;
+ }
+
+ if(bInMap) {
+ /* If the item is in a map, the start of the array/map
+ * itself, not the label, must be found. Do this by
+ * rewinding to the starting position and fetching
+ * just the label data item. QCBORDecode_Private_GetNextTagNumber()
+ * doesn't do any of the array/map item counting or nesting
+ * level tracking. Used here it will just fetech the label
+ * data item.
+ *
+ * Have to save the cursor and put it back to the position
+ * after the full item once the label as been fetched by
+ * itself.
+ */
+ uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+ UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
+
+ /* Item has been fetched once so safe to ignore error */
+ (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
+
+ uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
+ UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
+ } else {
+ uStartOfReturned = uStartingCursor;
+ }
+
+ /* Consume the entire array/map to find the end */
+ uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
+ if(uErr != QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)uErr;
+ goto Done;
+ }
+
+ /* Fill in returned values */
+ uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
+ if(EndedByBreak) {
+ /* When ascending nesting levels, a break for the level above
+ * was consumed. That break is not a part of what is consumed here. */
+ uEndOfReturned--;
+ }
+ pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
+ pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
+
+Done:
+ return;
}
-#endif /* ! QCBOR_DISABLE_TAGS */
+
#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
@@ -3147,2108 +2688,6 @@
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
-{
- QCBORDecode_VGetNext(pMe, pDecodedItem);
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
- &pDecodedItem->uNextNestLevel);
- }
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
-{
- size_t uCursorOffset;
- QCBORError uErr;
-
- uErr = QCBORDecode_GetError(pMe);
- if(uErr != QCBOR_SUCCESS) {
- return uErr;
- }
-
- uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
- return QCBOR_ERR_NO_MORE_ITEMS;
- }
-
- return QCBOR_SUCCESS;
-}
-
-
-/**
- * @brief Rewind cursor to start as if map or array were just entered.
- *
- * @param[in] pMe The decoding context
- *
- * This affects the nesting tracking and the UsefulInputBuf.
- */
-static void
-QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
-{
- /* Reset nesting tracking to the deepest bounded level */
- DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
-
- DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
-
- /* Reposition traversal cursor to the start of the map/array */
- UsefulInputBuf_Seek(&(pMe->InBuf),
- DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_Rewind(QCBORDecodeContext *pMe)
-{
- if(pMe->nesting.pCurrentBounded != NULL) {
- /* In a bounded map, array or bstr-wrapped CBOR */
-
- if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
- /* In bstr-wrapped CBOR. */
-
- /* Reposition traversal cursor to start of wrapping byte string */
- UsefulInputBuf_Seek(&(pMe->InBuf),
- pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
- DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
-
- } else {
- /* In a map or array */
- QCBORDecode_Private_RewindMapOrArray(pMe);
- }
-
- } else {
- /* Not in anything bounded */
-
- /* Reposition traversal cursor to the start of input CBOR */
- UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
-
- /* Reset nesting tracking to beginning of input. */
- DecodeNesting_Init(&(pMe->nesting));
- }
-
- pMe->uLastError = QCBOR_SUCCESS;
-}
-
-
-
-
-
-typedef struct {
- void *pCBContext;
- QCBORItemCallback pfCallback;
-} MapSearchCallBack;
-
-typedef struct {
- size_t uStartOffset;
- uint16_t uItemCount;
-} MapSearchInfo;
-
-
-/**
- * @brief Search a map for a set of items.
- *
- * @param[in] pMe The decode context to search.
- * @param[in,out] pItemArray The items to search for and the items found.
- * @param[out] pInfo Several bits of meta-info returned by search.
- * @param[in] pCallBack Callback object or @c NULL.
- *
- * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
- *
- * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
- * were found for one of the labels being
- * search for. This duplicate detection is
- * only performed for items in pItemArray,
- * not every item in the map.
- *
- * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
- * wrong for the matchd label.
- *
- * @retval Also errors returned by QCBORDecode_GetNext().
- *
- * On input, @c pItemArray contains a list of labels and data types of
- * items to be found.
- *
- * On output, the fully retrieved items are filled in with values and
- * such. The label was matched, so it never changes.
- *
- * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
- *
- * This also finds the ends of maps and arrays when they are exited.
- */
-static QCBORError
-QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
- QCBORItem *pItemArray,
- MapSearchInfo *pInfo,
- MapSearchCallBack *pCallBack)
-{
- QCBORError uReturn;
- uint64_t uFoundItemBitMap = 0;
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- uReturn = pMe->uLastError;
- goto Done2;
- }
-
- if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
- pItemArray->uLabelType != QCBOR_TYPE_NONE) {
- /* QCBOR_TYPE_NONE as first item indicates just looking
- for the end of an array, so don't give error. */
- uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
- goto Done2;
- }
-
- if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
- // It is an empty bounded array or map
- if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
- // Just trying to find the end of the map or array
- pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
- uReturn = QCBOR_SUCCESS;
- } else {
- // Nothing is ever found in an empty array or map. All items
- // are marked as not found below.
- uReturn = QCBOR_SUCCESS;
- }
- goto Done2;
- }
-
- QCBORDecodeNesting SaveNesting;
- size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
- DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
-
- /* Reposition to search from the start of the map / array */
- QCBORDecode_Private_RewindMapOrArray(pMe);
-
- /*
- Loop over all the items in the map or array. Each item
- could be a map or array, but label matching is only at
- the main level. This handles definite- and indefinite-
- length maps and arrays. The only reason this is ever
- called on arrays is to find their end position.
-
- This will always run over all items in order to do
- duplicate detection.
-
- This will exit with failure if it encounters an
- unrecoverable error, but continue on for recoverable
- errors.
-
- If a recoverable error occurs on a matched item, then
- that error code is returned.
- */
- const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
- if(pInfo) {
- pInfo->uItemCount = 0;
- }
- uint8_t uNextNestLevel;
- do {
- /* Remember offset of the item because sometimes it has to be returned */
- const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- /* Get the item */
- QCBORItem Item;
- /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
- * because a label match is performed on recoverable errors to
- * be able to return the the error code for the found item. */
- QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
- if(QCBORDecode_IsUnrecoverableError(uResult)) {
- /* The map/array can't be decoded when unrecoverable errors occur */
- uReturn = uResult;
- goto Done;
- }
- if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
- /* Unexpected end of map or array. */
- uReturn = uResult;
- goto Done;
- }
-
- /* See if item has one of the labels that are of interest */
- bool bMatched = false;
- for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
- if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
- /* A label match has been found */
- if(uFoundItemBitMap & (0x01ULL << nIndex)) {
- uReturn = QCBOR_ERR_DUPLICATE_LABEL;
- goto Done;
- }
- if(uResult != QCBOR_SUCCESS) {
- /* The label matches, but the data item is in error.
- * It is OK to have recoverable errors on items that
- * are not matched. */
- uReturn = uResult;
- goto Done;
- }
- if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
- /* The data item is not of the type(s) requested */
- uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
- goto Done;
- }
-
- /* Successful match. Return the item. */
- pItemArray[nIndex] = Item;
- uFoundItemBitMap |= 0x01ULL << nIndex;
- if(pInfo) {
- pInfo->uStartOffset = uOffset;
- }
- bMatched = true;
- }
- }
-
-
- if(!bMatched && pCallBack != NULL) {
- /*
- Call the callback on unmatched labels.
- (It is tempting to do duplicate detection here, but that would
- require dynamic memory allocation because the number of labels
- that might be encountered is unbounded.)
- */
- uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
- if(uReturn != QCBOR_SUCCESS) {
- goto Done;
- }
- }
-
- /*
- Consume the item whether matched or not. This
- does the work of traversing maps and array and
- everything in them. In this loop only the
- items at the current nesting level are examined
- to match the labels.
- */
- uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
- if(uReturn != QCBOR_SUCCESS) {
- goto Done;
- }
-
- if(pInfo) {
- pInfo->uItemCount++;
- }
-
- } while (uNextNestLevel >= uMapNestLevel);
-
- uReturn = QCBOR_SUCCESS;
-
- const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- // Check here makes sure that this won't accidentally be
- // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
- // QCBOR_MAX_DECODE_INPUT_SIZE.
- // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
- if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
- uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
- goto Done;
- }
- /* Cast OK because encoded CBOR is limited to UINT32_MAX */
- pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
-
- Done:
- DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
- UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
-
- Done2:
- /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
- for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
- if(!(uFoundItemBitMap & (0x01ULL << i))) {
- pItemArray[i].uDataType = QCBOR_TYPE_NONE;
- pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
- }
- }
-
- return uReturn;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
-{
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
- if(pMe->uLastError == QCBOR_SUCCESS) {
- UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
- }
-}
-
-
-void
-QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
- if(pMe->uLastError == QCBOR_SUCCESS) {
- UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
- }
-#else
- (void)pMe;
- (void)szLabel;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-
-void
-QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
- QCBORItem *OneItemSeach,
- QCBORItem *pItem,
- size_t *puOffset)
-{
- QCBORError uErr;
- MapSearchInfo SearchInfo;
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
-
- if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
- uErr = QCBOR_ERR_LABEL_NOT_FOUND;
- }
- *pItem = OneItemSeach[0];
- *puOffset = SearchInfo.uStartOffset;
-
- if(uErr == QCBOR_SUCCESS) {
- QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
- }
-
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-static void
-QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
-{
- QCBORError uErr;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
-
- uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem)
-{
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
-}
-
-
-/**
- * @brief Get an item by label by type.
- *
- * @param[in] pMe The decode context.
- * @param[in] nLabel The label to search map for.
- * @param[in] uQcborType The QCBOR type to look for.
- * @param[out] pItem The item found.
- * @param[out] puOffset The offset of item for tag consumption check.
- *
- * This finds the item with the given label in currently open
- * map. This does not call QCBORDecode_Private_GetItemChecks()
- * to check tag number consumption or decode conformance.
- */
-void
-QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset)
-{
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
-
-#else
- (void)pMe;
- (void)szLabel;
- (void)uQcborType;
- (void)pItem;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-/**
- * @brief Get an item by string label of a particular type
- *
- * @param[in] pMe The decode context.
- * @param[in] szLabel The label to search map for.
- * @param[in] uQcborType The QCBOR type to look for.
- * @param[out] pItem The item found.
- * @param[out] puOffset The offset of item for tag consumption check.
- *
- * This finds the item with the given label in currently open
- * map. This does not call QCBORDecode_Private_GetItemChecks()
- * to check tag number consumption or decode conformance.
- */
-void
-QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
-
-#else
- (void)pMe;
- (void)szLabel;
- (void)uQcborType;
- (void)pItem;
- (void)puOffset;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-
-
-
-/**
- * @brief Semi-private. Get pointer, length and item for an array or map.
- *
- * @param[in] pMe The decode context.
- * @param[in] uType CBOR major type, either array/map.
- * @param[out] pItem The item for the array/map.
- * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
- *
- * The next item to be decoded must be a map or array as specified by @c uType.
- *
- * @c pItem will be filled in with the label and tags of the array or map
- * in addition to @c pEncodedCBOR giving the pointer and length of the
- * encoded CBOR.
- *
- * When this is complete, the traversal cursor is at the end of the array or
- * map that was retrieved.
- */
-void
-QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
- const uint8_t uType,
- QCBORItem *pItem,
- UsefulBufC *pEncodedCBOR)
-{
- QCBORError uErr;
- uint8_t uNestLevel;
- size_t uStartingCursor;
- size_t uStartOfReturned;
- size_t uEndOfReturned;
- size_t uTempSaveCursor;
- bool bInMap;
- QCBORItem LabelItem;
- bool EndedByBreak;
-
- uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
- bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
-
- /* Could call GetNext here, but don't need to because this
- * is only interested in arrays and maps. TODO: switch to GetNext()? */
- uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
- if(uErr != QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)uErr;
- return;
- }
-
- uint8_t uItemDataType = pItem->uDataType;
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
- uItemDataType = QCBOR_TYPE_ARRAY;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
- if(uItemDataType != uType) {
- pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
- return;
- }
-
- if(bInMap) {
- /* If the item is in a map, the start of the array/map
- * itself, not the label, must be found. Do this by
- * rewinding to the starting position and fetching
- * just the label data item. QCBORDecode_Private_GetNextTagNumber()
- * doesn't do any of the array/map item counting or nesting
- * level tracking. Used here it will just fetech the label
- * data item.
- *
- * Have to save the cursor and put it back to the position
- * after the full item once the label as been fetched by
- * itself.
- */
- uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
- UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
-
- /* Item has been fetched once so safe to ignore error */
- (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
-
- uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
- UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
- } else {
- uStartOfReturned = uStartingCursor;
- }
-
- /* Consume the entire array/map to find the end */
- uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
- if(uErr != QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)uErr;
- goto Done;
- }
-
- /* Fill in returned values */
- uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
- if(EndedByBreak) {
- /* When ascending nesting levels, a break for the level above
- * was consumed. That break is not a part of what is consumed here. */
- uEndOfReturned--;
- }
- pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
- pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
-
-Done:
- return;
-}
-
-
-/**
- * @brief Semi-private. Get pointer, length and item count of an array or map.
- *
- * @param[in] pMe The decode context.
- * @param[in] pTarget The label and type of the array or map to retrieve.
- * @param[out] pItem The item for the array/map.
- * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
- *
- * The next item to be decoded must be a map or array as specified by @c uType.
- *
- * When this is complete, the traversal cursor is unchanged.
- */void
-QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
- QCBORItem *pTarget,
- QCBORItem *pItem,
- UsefulBufC *pEncodedCBOR)
-{
- MapSearchInfo Info;
- QCBORDecodeNesting SaveNesting;
- size_t uSaveCursor;
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
- pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- /* Save the whole position of things so they can be restored.
- * so the cursor position is unchanged by this operation, like
- * all the other GetXxxxInMap() operations. */
- DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
- uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
- UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
- QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
-
- UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
- DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
-}
-
-
-
-
-static void
-QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORType,
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- size_t uOffset);
-
-/**
- * @brief Semi-private to get an string by label to match a tag specification.
- *
- * @param[in] pMe The decode context.
- * @param[in] nLabel Label to search map for.
- * @param[in] uTagRequirement Whether or not tag number is required.
- * See @ref QCBOR_TAG_REQUIREMENT_TAG.
- * @param[in] uQCBOR_Type QCBOR type to search for.
- * @param[in] uTagNumber Tag number to match.
- * @param[out] pString The string found.
- *
- * This finds the string with the given label in currently open
- * map. Then checks that its tag number and types matches the tag
- * specification. If not, an error is set in the decode context.
- */
-void
-QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- const uint8_t uQCBOR_Type,
- const uint64_t uTagNumber,
- UsefulBufC *pString)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- uQCBOR_Type,
- uTagNumber,
- QCBORDecode_StringsTagCB,
- uOffset);
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- *pString = Item.val.string;
- }
-}
-
-
-/**
- * @brief Semi-private to get an string by label to match a tag specification.
- *
- * @param[in] pMe The decode context.
- * @param[in] szLabel Label to search map for.
- * @param[in] uTagRequirement Whether or not tag number is required.
- * See @ref QCBOR_TAG_REQUIREMENT_TAG.
- * @param[in] uQCBOR_Type QCBOR type to search for.
- * @param[in] uTagNumber Tag number to match.
- * @param[out] pString The string found.
- *
- * This finds the string with the given label in currently open
- * map. Then checks that its tag number and types matches the tag
- * specification. If not, an error is set in the decode context.
- */
-void
-QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- uint8_t uQCBOR_Type,
- uint64_t uTagNumber,
- UsefulBufC *pString)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- uQCBOR_Type,
- uTagNumber,
- QCBORDecode_StringsTagCB,
- uOffset);
-
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- *pString = Item.val.string;
- }
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
-{
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
- QCBORItem *pItemList,
- void *pCallbackCtx,
- QCBORItemCallback pfCB)
-{
- MapSearchCallBack CallBack;
-
- CallBack.pCBContext = pCallbackCtx;
- CallBack.pfCallback = pfCB;
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
-}
-
-
-#ifndef QCBOR_DISABLE_TAGS
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
-{
- size_t uOffset;
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return pMe->uLastError;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
-
- uOffset = Info.uStartOffset;
- if(uOffset == pMe->uTagNumberCheckOffset) {
- pMe->uTagNumberIndex++;
- } else {
- pMe->uTagNumberIndex = 0;
- }
-
- *puTagNumber = CBOR_TAG_INVALID64;
-
- *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
- if(*puTagNumber == CBOR_TAG_INVALID64 ||
- QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
- pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
- }
- pMe->uTagNumberCheckOffset = uOffset;
-
- return uReturn;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- size_t uOffset;
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return pMe->uLastError;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
-
-
- uOffset = Info.uStartOffset;
- if(uOffset == pMe->uTagNumberCheckOffset) {
- pMe->uTagNumberIndex++;
- } else {
- pMe->uTagNumberIndex = 0;
- }
-
- *puTagNumber = CBOR_TAG_INVALID64;
-
- *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
- if(*puTagNumber == CBOR_TAG_INVALID64 ||
- QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
- pMe->uTagNumberIndex = 255; /* All tags clear for this item */
- }
- pMe->uTagNumberCheckOffset = uOffset;
-
- return uReturn;
-#else
- (void)pMe;
- (void)szLabel;
- (void)puTagNumber;
- return QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-#endif /* ! QCBOR_DISABLE_TAGS */
-
-
-/**
- * @brief Search for a map/array by label and enter it
- *
- * @param[in] pMe The decode context.
- * @param[in] pSearch The map/array to search for.
- *
- * @c pSearch is expected to contain one item of type map or array
- * with the label specified. The current bounded map will be searched for
- * this and if found will be entered.
- *
- * If the label is not found, or the item found is not a map or array,
- * the error state is set.
- */
-static void
-QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
-{
- QCBORError uErr;
- MapSearchInfo SearchInfo;
-
- // The first item in pSearch is the one that is to be
- // entered. It should be the only one filled in. Any other
- // will be ignored unless it causes an error.
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- if(pSearch->uDataType == QCBOR_TYPE_NONE) {
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
- return;
- }
-
-
- /* The map or array was found. Now enter it.
- *
- * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
- * next item for the pre-order traversal cursor to be the map/array
- * found by MapSearch(). The next few lines of code force the
- * cursor to that.
- *
- * There is no need to retain the old cursor because
- * QCBORDecode_EnterBoundedMapOrArray() will set it to the
- * beginning of the map/array being entered.
- *
- * The cursor is forced by: 1) setting the input buffer position to
- * the item offset found by MapSearch(), 2) setting the map/array
- * counter to the total in the map/array, 3) setting the nesting
- * level. Setting the map/array counter to the total is not
- * strictly correct, but this is OK because this cursor only needs
- * to be used to get one item and MapSearch() has already found it
- * confirming it exists.
- */
- UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
-
- DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
-
- DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
-
- QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
-{
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- /* The map to enter was found, now finish off entering it. */
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-#else
- (void)szLabel;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
-{
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-#else
- (void)szLabel;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-
-/**
- * @brief Semi-private to do the the work for EnterMap() and EnterArray().
- *
- * @param[in] pMe The decode context
- * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
- * @param[out] pItem The data item for the map or array entered.
- *
- * The next item in the traversal must be a map or array. This
- * consumes that item and does the book keeping to enter the map or
- * array.
- */
-void
-QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
- const uint8_t uType,
- QCBORItem *pItem)
-{
- QCBORError uErr;
-
- /* Must only be called on maps and arrays. */
- if(pMe->uLastError != QCBOR_SUCCESS) {
- // Already in error state; do nothing.
- return;
- }
-
- /* Get the data item that is the map or array being entered. */
- QCBORItem Item;
- uErr = QCBORDecode_GetNext(pMe, &Item);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- uint8_t uItemDataType = Item.uDataType;
-
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
- uItemDataType = QCBOR_TYPE_ARRAY;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
- if(uItemDataType != uType) {
- uErr = QCBOR_ERR_UNEXPECTED_TYPE;
- goto Done;
- }
-
- QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
-
-
- const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
- if(bIsEmpty) {
- if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
- // Undo decrement done by QCBORDecode_GetNext() so the the
- // the decrement when exiting the map/array works correctly
- pMe->nesting.pCurrent->u.ma.uCountCursor++;
- }
- // Special case to increment nesting level for zero-length maps
- // and arrays entered in bounded mode.
- DecodeNesting_Descend(&(pMe->nesting), uType);
- }
-
- pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
-
- uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
- UsefulInputBuf_Tell(&(pMe->InBuf)));
-
- if(pItem != NULL) {
- *pItem = Item;
- }
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-/**
- * @brief Exit a bounded map, array or bstr (semi-private).
- *
- * @param[in] pMe Decode context.
- * @param[in] uEndOffset The input buffer offset of the end of item exited.
- *
- * @returns QCBOR_SUCCESS or an error code.
- *
- * This is the common work for exiting a level that is a bounded map,
- * array or bstr wrapped CBOR.
- *
- * One chunk of work is to set up the pre-order traversal so it is at
- * the item just after the bounded map, array or bstr that is being
- * exited. This is somewhat complex.
- *
- * The other work is to level-up the bounded mode to next higest
- * bounded mode or the top level if there isn't one.
- */
-static QCBORError
-QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
- const uint32_t uEndOffset)
-{
- QCBORError uErr;
-
- /*
- * First the pre-order-traversal byte offset is positioned to the
- * item just after the bounded mode item that was just consumed.
- */
- UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
-
- /*
- * Next, set the current nesting level to one above the bounded
- * level that was just exited.
- *
- * DecodeNesting_CheckBoundedType() is always called before this
- * and makes sure pCurrentBounded is valid.
- */
- DecodeNesting_LevelUpCurrent(&(pMe->nesting));
-
- /*
- * This does the complex work of leveling up the pre-order
- * traversal when the end of a map or array or another bounded
- * level is reached. It may do nothing, or ascend all the way to
- * the top level.
- */
- uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- /*
- * This makes the next highest bounded level the current bounded
- * level. If there is no next highest level, then no bounded mode
- * is in effect.
- */
- DecodeNesting_LevelUpBounded(&(pMe->nesting));
-
- pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
-
-Done:
- return uErr;
-}
-
-
-/**
- * @brief Get started exiting a map or array (semi-private)
- *
- * @param[in] pMe The decode context
- * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
- *
- * This does some work for map and array exiting (but not
- * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
- * is called to do the rest.
- */
-void
-QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
- const uint8_t uType)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- /* Already in error state; do nothing. */
- return;
- }
-
- QCBORError uErr;
-
- if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
- uErr = QCBOR_ERR_EXIT_MISMATCH;
- goto Done;
- }
-
- /*
- Have to set the offset to the end of the map/array
- that is being exited. If there is no cached value,
- from previous map search, then do a dummy search.
- */
- if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
- QCBORItem Dummy;
- Dummy.uLabelType = QCBOR_TYPE_NONE;
- uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
- }
-
- uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-// TODO: re order this file with tags stuff last. bstr is a tag thing
-static QCBORError
-QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const size_t uOffset,
- const uint8_t *uQCBORTypes,
- const uint64_t *uTagNumbers,
- const uint8_t uTagRequirement,
- bool *bTypeMatched);
-
-/**
- * @brief The main work of entering some byte-string wrapped CBOR.
- *
- * @param[in] pMe The decode context.
- * @param[in] pItem The byte string item.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
- * @param[out] pBstr Pointer and length of byte string entered.
- *
- * This is called once the byte string item has been decoded to do all
- * the book keeping work for descending a nesting level into the
- * nested CBOR.
- *
- * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
- */
-static QCBORError
-QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const size_t uOffset,
- UsefulBufC *pBstr)
-{
- bool bTypeMatched;
- QCBORError uError;
-
- const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
- const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
-
-
- if(pBstr) {
- *pBstr = NULLUsefulBufC;
- }
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return pMe->uLastError;
- }
-
- if(pItem->uDataAlloc) {
- return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
- }
-
- uError = QCBORDecode_Private_CheckTagNType(pMe,
- pItem,
- uOffset,
- uTypes, // TODO: maybe this should be empty
- uTagNumbers,
- uTagRequirement,
- &bTypeMatched);
-
- if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
- uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
- }
-
-
- if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
- /* Reverse the decrement done by GetNext() for the bstr so the
- * increment in QCBORDecode_NestLevelAscender() called by
- * ExitBoundedLevel() will work right.
- */
- DecodeNesting_ReverseDecrement(&(pMe->nesting));
- }
-
- if(pBstr) {
- *pBstr = pItem->val.string;
- }
-
- /* This saves the current length of the UsefulInputBuf and then
- * narrows the UsefulInputBuf to start and length of the wrapped
- * CBOR that is being entered.
- *
- * Most of these calls are simple inline accessors so this doesn't
- * amount to much code.
- */
-
- const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
- /* This check makes the cast of uPreviousLength to uint32_t below safe. */
- if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
- uError = QCBOR_ERR_INPUT_TOO_LARGE;
- goto Done;
- }
-
- const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
- pItem->val.string.ptr);
- /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
- if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
- /* This should never happen because pItem->val.string.ptr should
- * always be valid since it was just returned.
- */
- uError = QCBOR_ERR_INPUT_TOO_LARGE;
- goto Done;
- }
-
- const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
-
- UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
- UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
-
- uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
- (uint32_t)uPreviousLength,
- (uint32_t)uStartOfBstr);
-Done:
- return uError;
-}
-
-
-static void
-QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
-{
-#ifndef QCBOR_DISABLE_TAGS
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- *uOffset = QCBORDecode_Tell(pMe);
-#else
- *uOffset = SIZE_MAX;
-
-#endif /* ! QCBOR_DISABLE_TAGS */
- pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pBstr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
- &Item,
- uTagRequirement,
- uOffset,
- pBstr);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pBstr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
- pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
- &Item,
- uTagRequirement,
- uOffset,
- pBstr);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pBstr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
- pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
- &Item,
- uTagRequirement,
- uOffset,
- pBstr);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- // Already in error state; do nothing.
- return;
- }
-
- if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
- pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
- return;
- }
-
- const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
-
- /*
- Reset the length of the UsefulInputBuf to what it was before
- the bstr wrapped CBOR was entered.
- */
- UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
- DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
-
-
- QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-
-/**
- * @brief Process simple type true and false, a boolean
- *
- * @param[in] pMe The decode context.
- * @param[in] pItem The item with either true or false.
- * @param[out] pBool The boolean value output.
- *
- * Sets the internal error if the item isn't a true or a false. Also
- * records any tag numbers as the tag numbers of the last item.
- */
-static void
-QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- bool *pBool)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- /* Already in error state, do nothing */
- return;
- }
-
- switch(pItem->uDataType) {
- case QCBOR_TYPE_TRUE:
- *pBool = true;
- break;
-
- case QCBOR_TYPE_FALSE:
- *pBool = false;
- break;
-
- default:
- pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
- break;
- }
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
-{
- QCBORItem Item;
- QCBORDecode_VGetNext(pMe, &Item);
- QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- bool *pValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- bool *pValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
-}
-
-
-/**
- * @brief Process simple values.
- *
- * @param[in] pMe The decode context.
- * @param[in] pItem The item with the simple value.
- * @param[out] puSimple The simple value output.
- *
- * Sets the internal error if the item isn't a true or a false. Also
- * records any tag numbers as the tag numbers of the last item.
- */
-static void
-QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- uint8_t *puSimple)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- /* It's kind of lame to remap true...undef back to simple values, but
- * this function isn't used much and to not do it would require
- * changing GetNext() behavior in an incompatible way.
- */
- switch(pItem->uDataType) {
- case QCBOR_TYPE_UKNOWN_SIMPLE:
- *puSimple = pItem->val.uSimple;
- break;
-
- case QCBOR_TYPE_TRUE:
- *puSimple = CBOR_SIMPLEV_TRUE;
- break;
-
- case QCBOR_TYPE_FALSE:
- *puSimple = CBOR_SIMPLEV_FALSE;
- break;
-
- case QCBOR_TYPE_NULL:
- *puSimple = CBOR_SIMPLEV_NULL;
- break;
-
- case QCBOR_TYPE_UNDEF:
- *puSimple = CBOR_SIMPLEV_UNDEF;
- break;
-
- default:
- pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
- return;
- }
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
-{
- QCBORItem Item;
- QCBORDecode_VGetNext(pMe, &Item);
- QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t *puSimpleValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t *puSimpleValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
-}
-
-
-
-
-#ifndef QCBOR_DISABLE_TAGS
-// TODO: uTagNumber might be better a list than calling this multiple times
-static QCBORError
-QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const uint64_t uTagNumber,
- const size_t uOffset)
-{
- if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
- /* There are no tag numbers at all, so no unprocessed */
- return QCBOR_SUCCESS;
- }
-
- /* There are some tag numbers, so keep checking. This check passes
- * if there is one and only one tag number that matches uTagNumber
- */
-
- // TODO: behave different in v1 and v2?
-
- const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
-
- if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
- /* The only tag number is the one we are processing so no unprocessed */
- return QCBOR_SUCCESS;
- }
-
- if(uOffset != pMe->uTagNumberCheckOffset) {
- /* processed tag numbers are for some other item, not us */
- return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
- }
-
- if(pMe->uTagNumberIndex != 1) {
- return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
- }
-
- return QCBOR_SUCCESS;
-}
-#endif
-
-
-static QCBORError
-QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const size_t uOffset,
- const uint8_t *uQCBORTypes,
- const uint64_t *uTagNumbers,
- const uint8_t uTagRequirement,
- bool *bTypeMatched)
-{
- const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
-
- *bTypeMatched = false;
- for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
- if(pItem->uDataType == *pTNum) {
- *bTypeMatched = true;
- break;
- }
- }
-
-#ifndef QCBOR_DISABLE_TAGS
- bool bTagNumberMatched;
- QCBORError uErr;
- const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
-
- bTagNumberMatched = false;
- for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
- if(uInnerTag == *pQType) {
- bTagNumberMatched = true;
- break;
- }
- }
-
-
- if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
- /* There must be a tag number */
- if(!bTagNumberMatched && !*bTypeMatched) {
- return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
- }
-
- } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
- if(bTagNumberMatched || *bTypeMatched) {
- return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
- }
-
- } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
- /* No check necessary */
- }
-
- /* Now check if there are extra tags and if there's an error in them */
- if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
- /* The flag to ignore extra is not set, so keep checking */
- for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
- uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
- if(uErr != QCBOR_SUCCESS) {
- return uErr;
- }
- }
- }
-
- return QCBOR_SUCCESS;
-#else
- (void)pMe;
- (void)uOffset;
- (void)uTagNumbers;
-
- if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
- return QCBOR_SUCCESS;
- } else {
- return QCBOR_ERR_UNEXPECTED_TYPE;
- }
-
-#endif
-
-}
-
-
-void
-QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumbers[],
- QCBORTagContentCallBack *pfCB,
- size_t uOffset)
-{
- QCBORError uErr;
- bool bTypeMatched;
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- uErr = QCBORDecode_Private_CheckTagNType(pMe,
- pItem,
- uOffset,
- uQCBORTypes,
- uTagNumbers,
- uTagRequirement,
- &bTypeMatched);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- if(!bTypeMatched) {
- /* Tag content wasn't previously processed, do it now */
- uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
- }
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-/*
- **/
-void
-QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- size_t uOffset)
-{
- uint64_t auTagNumbers[2];
-
- auTagNumbers[0] = uTagNumber;
- auTagNumbers[1] = CBOR_TAG_INVALID64;
-
- QCBORDecode_Private_ProcessTagItemMulti(pMe,
- pItem,
- uTagRequirement,
- uQCBORTypes,
- auTagNumbers,
- pfCB,
- uOffset);
-}
-
-
-static void
-QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORType,
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- const size_t uOffset)
-{
- uint8_t auQCBORType[2];
-
- auQCBORType[0] = uQCBORType;
- auQCBORType[1] = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_ProcessTagItem(pMe,
- pItem,
- uTagRequirement,
- auQCBORType,
- uTagNumber,
- pfCB,
- uOffset);
-}
-
-
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h file
- */
-void
-QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
- uint8_t uTagRequirement,
- int64_t *pnTime)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DATE_EPOCH,
- CBOR_TAG_DATE_EPOCH,
- QCBORDecode_DateEpochTagCB,
- uOffset);
- *pnTime = Item.val.epochDate.nSeconds;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h file
- */
-void
-QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DATE_EPOCH,
- CBOR_TAG_DATE_EPOCH,
- QCBORDecode_DateEpochTagCB,
- uOffset);
- *pnTime = Item.val.epochDate.nSeconds;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h file
- */
-void
-QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DATE_EPOCH,
- CBOR_TAG_DATE_EPOCH,
- QCBORDecode_DateEpochTagCB,
- uOffset);
- *pnTime = Item.val.epochDate.nSeconds;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h
- */
-void
-QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
- uint8_t uTagRequirement,
- int64_t *pnDays)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DAYS_EPOCH,
- CBOR_TAG_DAYS_EPOCH,
- QCBORDecode_DaysEpochTagCB,
- uOffset);
- *pnDays = Item.val.epochDays;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h
- */
-void
-QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnDays)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DAYS_EPOCH,
- CBOR_TAG_DAYS_EPOCH,
- QCBORDecode_DaysEpochTagCB,
- uOffset);
- *pnDays = Item.val.epochDays;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h
- */
-void
-QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- int64_t *pnDays)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DAYS_EPOCH,
- CBOR_TAG_DAYS_EPOCH,
- QCBORDecode_DaysEpochTagCB,
- uOffset);
- *pnDays = Item.val.epochDays;
-}
-
-
-
-
-void
-QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- const uint8_t uQCBOR_Type,
- const uint64_t uTagNumber,
- UsefulBufC *pStr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- uQCBOR_Type,
- uTagNumber,
- QCBORDecode_StringsTagCB,
- uOffset);
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- *pStr = Item.val.string;
- } else {
- *pStr = NULLUsefulBufC;
- }
-}
-
-
-
-static void
-QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- QCBORItem *pItem,
- UsefulBufC *pValue,
- bool *pbIsTag257,
- size_t uOffset)
-{
- QCBORError uErr;
-
- const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
-
- const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
-
- QCBORDecode_Private_ProcessTagItemMulti(pMe,
- pItem,
- uTagRequirement,
- puTypes,
- puTNs,
- QCBORDecode_MIMETagCB,
- uOffset);
- if(pMe->uLastError) {
- return;
- }
-
- if(pItem->uDataType == QCBOR_TYPE_MIME) {
- *pbIsTag257 = false;
- } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
- *pbIsTag257 = true;
- }
- *pValue = pItem->val.string;
-
-
- uErr = QCBOR_SUCCESS;
-
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-void
-QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_GetMIME(pMe,
- uTagRequirement,
- &Item,
- pMessage,
- pbIsTag257,
- uOffset);
-}
-
-void
-QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_GetMIME(pMe,
- uTagRequirement,
- &Item,
- pMessage,
- pbIsTag257,
- uOffset);
-}
-
-void
-QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_GetMIME(pMe,
- uTagRequirement,
- &Item,
- pMessage,
- pbIsTag257,
- uOffset);
-}
-
-
-
// Improvement: add methods for wrapped CBOR, a simple alternate
// to EnterBstrWrapped
diff --git a/src/qcbor_number_decode.c b/src/qcbor_number_decode.c
index 6873b94..5c6f3e3 100644
--- a/src/qcbor_number_decode.c
+++ b/src/qcbor_number_decode.c
@@ -1,5 +1,5 @@
/* ==========================================================================
- * number_decode.c -- Number decoding beyond the basic ints and floats
+ * qcbor_number_decode.c -- Number decoding beyond the basic ints and floats
*
* Copyright (c) 2016-2018, The Linux Foundation.
* Copyright (c) 2018-2024, Laurence Lundblade.
@@ -10,7 +10,7 @@
*
* See BSD-3-Clause license in README.md
*
- * Created on 11/14/24 from qcbor_decode.c
+ * Created on 11/14/24 from qcbor_decode.c
* ========================================================================== */
diff --git a/src/qcbor_spiffy_decode.c b/src/qcbor_spiffy_decode.c
new file mode 100644
index 0000000..5c25f54
--- /dev/null
+++ b/src/qcbor_spiffy_decode.c
@@ -0,0 +1,1197 @@
+
+
+/* ==========================================================================
+ * qcbor_spiffy_decode.c -- "Spiffy" QCBOR decoding
+ *
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2021, Arm Limited.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ *
+ * Created on 11/28/24 from qcbor_decode.c
+ * ========================================================================== */
+
+
+#include "qcbor/qcbor_decode.h"
+#include "qcbor/qcbor_spiffy_decode.h"
+// TODO: see about removing these two includes
+#include "qcbor/qcbor_tag_decode.h"
+#include "ieee754.h" /* Does not use math.h */
+#include "decode_private.h"
+#include "decode_nesting.h"
+
+
+
+#if (defined(__GNUC__) && !defined(__clang__))
+/*
+ * This is how the -Wmaybe-uninitialized compiler warning is
+ * handled. It can’t be ignored because some version of gcc enable it
+ * with -Wall which is a common and useful gcc warning option. It also
+ * can’t be ignored because it is the goal of QCBOR to compile clean
+ * out of the box in all environments.
+ *
+ * The big problem with -Wmaybe-uninitialized is that it generates
+ * false positives. It complains things are uninitialized when they
+ * are not. This is because it is not a thorough static analyzer. This
+ * is why “maybe” is in its name. The problem is it is just not
+ * thorough enough to understand all the code (and someone saw fit to
+ * put it in gcc and worse to enable it with -Wall).
+ *
+ * One solution would be to change the code so -Wmaybe-uninitialized
+ * doesn’t get confused, for example adding an unnecessary extra
+ * initialization to zero. (If variables were truly uninitialized, the
+ * correct path is to understand the code thoroughly and set them to
+ * the correct value at the correct time; in essence this is already
+ * done; -Wmaybe-uninitialized just can’t tell). This path is not
+ * taken because it makes the code bigger and is kind of the tail
+ * wagging the dog.
+ *
+ * The solution here is to just use a pragma to disable it for the
+ * whole file. Disabling it for each line makes the code fairly ugly
+ * requiring #pragma to push, pop and ignore. Another reason is the
+ * warnings issues vary by version of gcc and which optimization
+ * optimizations are selected. Another reason is that compilers other
+ * than gcc don’t have -Wmaybe-uninitialized.
+ *
+ * One may ask how to be sure these warnings are false positives and
+ * not real issues. 1) The code has been read carefully to check. 2)
+ * Testing is pretty thorough. 3) This code has been run through
+ * thorough high-quality static analyzers.
+ *
+ * In particularly, most of the warnings are about
+ * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
+ * *always* sets this value and test case confirm
+ * this. -Wmaybe-uninitialized just can't tell.
+ *
+ * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
+ */
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
+
+/* Return true if the labels in Item1 and Item2 are the same.
+ Works only for integer and string labels. Returns false
+ for any other type. */
+static bool
+QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
+{
+ if(Item1.uLabelType == QCBOR_TYPE_INT64) {
+ if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
+ return true;
+ }
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
+ if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
+ return true;
+ }
+ } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
+ if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
+ return true;
+ }
+ } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
+ if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
+ return true;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+ }
+
+ /* Other label types are never matched */
+ return false;
+}
+
+
+
+/*
+ Returns true if Item1 and Item2 are the same type
+ or if either are of QCBOR_TYPE_ANY.
+ */
+static bool
+QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
+{
+ if(Item1.uDataType == Item2.uDataType) {
+ return true;
+ } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
+ return true;
+ } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @brief Rewind cursor to start as if map or array were just entered.
+ *
+ * @param[in] pMe The decoding context
+ *
+ * This affects the nesting tracking and the UsefulInputBuf.
+ */
+static void
+QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
+{
+ /* Reset nesting tracking to the deepest bounded level */
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
+ /* Reposition traversal cursor to the start of the map/array */
+ UsefulInputBuf_Seek(&(pMe->InBuf),
+ DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_Rewind(QCBORDecodeContext *pMe)
+{
+ if(pMe->nesting.pCurrentBounded != NULL) {
+ /* In a bounded map, array or bstr-wrapped CBOR */
+
+ if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
+ /* In bstr-wrapped CBOR. */
+
+ /* Reposition traversal cursor to start of wrapping byte string */
+ UsefulInputBuf_Seek(&(pMe->InBuf),
+ pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ } else {
+ /* In a map or array */
+ QCBORDecode_Private_RewindMapOrArray(pMe);
+ }
+
+ } else {
+ /* Not in anything bounded */
+
+ /* Reposition traversal cursor to the start of input CBOR */
+ UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
+
+ /* Reset nesting tracking to beginning of input. */
+ DecodeNesting_Init(&(pMe->nesting));
+ }
+
+ pMe->uLastError = QCBOR_SUCCESS;
+}
+
+
+
+
+/**
+ * @brief Search a map for a set of items.
+ *
+ * @param[in] pMe The decode context to search.
+ * @param[in,out] pItemArray The items to search for and the items found.
+ * @param[out] pInfo Several bits of meta-info returned by search.
+ * @param[in] pCallBack Callback object or @c NULL.
+ *
+ * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
+ *
+ * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
+ * were found for one of the labels being
+ * search for. This duplicate detection is
+ * only performed for items in pItemArray,
+ * not every item in the map.
+ *
+ * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
+ * wrong for the matchd label.
+ *
+ * @retval Also errors returned by QCBORDecode_GetNext().
+ *
+ * On input, @c pItemArray contains a list of labels and data types of
+ * items to be found.
+ *
+ * On output, the fully retrieved items are filled in with values and
+ * such. The label was matched, so it never changes.
+ *
+ * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
+ *
+ * This also finds the ends of maps and arrays when they are exited.
+ */
+QCBORError
+QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
+ QCBORItem *pItemArray,
+ MapSearchInfo *pInfo,
+ MapSearchCallBack *pCallBack)
+{
+ QCBORError uReturn;
+ uint64_t uFoundItemBitMap = 0;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ uReturn = pMe->uLastError;
+ goto Done2;
+ }
+
+ if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
+ pItemArray->uLabelType != QCBOR_TYPE_NONE) {
+ /* QCBOR_TYPE_NONE as first item indicates just looking
+ for the end of an array, so don't give error. */
+ uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
+ goto Done2;
+ }
+
+ if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
+ // It is an empty bounded array or map
+ if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
+ // Just trying to find the end of the map or array
+ pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
+ uReturn = QCBOR_SUCCESS;
+ } else {
+ // Nothing is ever found in an empty array or map. All items
+ // are marked as not found below.
+ uReturn = QCBOR_SUCCESS;
+ }
+ goto Done2;
+ }
+
+ QCBORDecodeNesting SaveNesting;
+ size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
+ DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
+
+ /* Reposition to search from the start of the map / array */
+ QCBORDecode_Private_RewindMapOrArray(pMe);
+
+ /*
+ Loop over all the items in the map or array. Each item
+ could be a map or array, but label matching is only at
+ the main level. This handles definite- and indefinite-
+ length maps and arrays. The only reason this is ever
+ called on arrays is to find their end position.
+
+ This will always run over all items in order to do
+ duplicate detection.
+
+ This will exit with failure if it encounters an
+ unrecoverable error, but continue on for recoverable
+ errors.
+
+ If a recoverable error occurs on a matched item, then
+ that error code is returned.
+ */
+ const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
+ if(pInfo) {
+ pInfo->uItemCount = 0;
+ }
+ uint8_t uNextNestLevel;
+ do {
+ /* Remember offset of the item because sometimes it has to be returned */
+ const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+ /* Get the item */
+ QCBORItem Item;
+ /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
+ * because a label match is performed on recoverable errors to
+ * be able to return the the error code for the found item. */
+ QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
+ if(QCBORDecode_IsUnrecoverableError(uResult)) {
+ /* The map/array can't be decoded when unrecoverable errors occur */
+ uReturn = uResult;
+ goto Done;
+ }
+ if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
+ /* Unexpected end of map or array. */
+ uReturn = uResult;
+ goto Done;
+ }
+
+ /* See if item has one of the labels that are of interest */
+ bool bMatched = false;
+ for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
+ if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
+ /* A label match has been found */
+ if(uFoundItemBitMap & (0x01ULL << nIndex)) {
+ uReturn = QCBOR_ERR_DUPLICATE_LABEL;
+ goto Done;
+ }
+ if(uResult != QCBOR_SUCCESS) {
+ /* The label matches, but the data item is in error.
+ * It is OK to have recoverable errors on items that
+ * are not matched. */
+ uReturn = uResult;
+ goto Done;
+ }
+ if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
+ /* The data item is not of the type(s) requested */
+ uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
+ goto Done;
+ }
+
+ /* Successful match. Return the item. */
+ pItemArray[nIndex] = Item;
+ uFoundItemBitMap |= 0x01ULL << nIndex;
+ if(pInfo) {
+ pInfo->uStartOffset = uOffset;
+ }
+ bMatched = true;
+ }
+ }
+
+
+ if(!bMatched && pCallBack != NULL) {
+ /*
+ Call the callback on unmatched labels.
+ (It is tempting to do duplicate detection here, but that would
+ require dynamic memory allocation because the number of labels
+ that might be encountered is unbounded.)
+ */
+ uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
+ if(uReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+ /*
+ Consume the item whether matched or not. This
+ does the work of traversing maps and array and
+ everything in them. In this loop only the
+ items at the current nesting level are examined
+ to match the labels.
+ */
+ uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
+ if(uReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ if(pInfo) {
+ pInfo->uItemCount++;
+ }
+
+ } while (uNextNestLevel >= uMapNestLevel);
+
+ uReturn = QCBOR_SUCCESS;
+
+ const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+ // Check here makes sure that this won't accidentally be
+ // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
+ // QCBOR_MAX_DECODE_INPUT_SIZE.
+ // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
+ if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+ /* Cast OK because encoded CBOR is limited to UINT32_MAX */
+ pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
+
+ Done:
+ DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
+ UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
+
+ Done2:
+ /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
+ for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
+ if(!(uFoundItemBitMap & (0x01ULL << i))) {
+ pItemArray[i].uDataType = QCBOR_TYPE_NONE;
+ pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
+ }
+ }
+
+ return uReturn;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+ }
+}
+
+
+void
+QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+ }
+#else
+ (void)pMe;
+ (void)szLabel;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+void
+QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
+ QCBORItem *OneItemSeach,
+ QCBORItem *pItem,
+ size_t *puOffset)
+{
+ QCBORError uErr;
+ MapSearchInfo SearchInfo;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
+
+ if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
+ uErr = QCBOR_ERR_LABEL_NOT_FOUND;
+ }
+ *pItem = OneItemSeach[0];
+ *puOffset = SearchInfo.uStartOffset;
+
+ if(uErr == QCBOR_SUCCESS) {
+ QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
+ }
+
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+static void
+QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
+{
+ QCBORError uErr;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
+
+ uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem)
+{
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
+}
+
+
+/**
+ * @brief Get an item by label by type.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] nLabel The label to search map for.
+ * @param[in] uQcborType The QCBOR type to look for.
+ * @param[out] pItem The item found.
+ * @param[out] puOffset The offset of item for tag consumption check.
+ *
+ * This finds the item with the given label in currently open
+ * map. This does not call QCBORDecode_Private_GetItemChecks()
+ * to check tag number consumption or decode conformance.
+ */
+void
+QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset)
+{
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
+
+#else
+ (void)pMe;
+ (void)szLabel;
+ (void)uQcborType;
+ (void)pItem;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+/**
+ * @brief Get an item by string label of a particular type
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] szLabel The label to search map for.
+ * @param[in] uQcborType The QCBOR type to look for.
+ * @param[out] pItem The item found.
+ * @param[out] puOffset The offset of item for tag consumption check.
+ *
+ * This finds the item with the given label in currently open
+ * map. This does not call QCBORDecode_Private_GetItemChecks()
+ * to check tag number consumption or decode conformance.
+ */
+void
+QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
+
+#else
+ (void)pMe;
+ (void)szLabel;
+ (void)uQcborType;
+ (void)pItem;
+ (void)puOffset;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+
+
+
+
+/**
+ * @brief Semi-private. Get pointer, length and item count of an array or map.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pTarget The label and type of the array or map to retrieve.
+ * @param[out] pItem The item for the array/map.
+ * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
+ *
+ * The next item to be decoded must be a map or array as specified by @c uType.
+ *
+ * When this is complete, the traversal cursor is unchanged.
+ */void
+QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
+ QCBORItem *pTarget,
+ QCBORItem *pItem,
+ UsefulBufC *pEncodedCBOR)
+{
+ MapSearchInfo Info;
+ QCBORDecodeNesting SaveNesting;
+ size_t uSaveCursor;
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ /* Save the whole position of things so they can be restored.
+ * so the cursor position is unchanged by this operation, like
+ * all the other GetXxxxInMap() operations. */
+ DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
+ uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+ UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+ QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
+
+ UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
+ DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
+}
+
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
+{
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
+ QCBORItem *pItemList,
+ void *pCallbackCtx,
+ QCBORItemCallback pfCB)
+{
+ MapSearchCallBack CallBack;
+
+ CallBack.pCBContext = pCallbackCtx;
+ CallBack.pfCallback = pfCB;
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
+}
+
+
+
+
+/**
+ * @brief Search for a map/array by label and enter it
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pSearch The map/array to search for.
+ *
+ * @c pSearch is expected to contain one item of type map or array
+ * with the label specified. The current bounded map will be searched for
+ * this and if found will be entered.
+ *
+ * If the label is not found, or the item found is not a map or array,
+ * the error state is set.
+ */
+static void
+QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
+{
+ QCBORError uErr;
+ MapSearchInfo SearchInfo;
+
+ // The first item in pSearch is the one that is to be
+ // entered. It should be the only one filled in. Any other
+ // will be ignored unless it causes an error.
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ if(pSearch->uDataType == QCBOR_TYPE_NONE) {
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+ return;
+ }
+
+
+ /* The map or array was found. Now enter it.
+ *
+ * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
+ * next item for the pre-order traversal cursor to be the map/array
+ * found by MapSearch(). The next few lines of code force the
+ * cursor to that.
+ *
+ * There is no need to retain the old cursor because
+ * QCBORDecode_EnterBoundedMapOrArray() will set it to the
+ * beginning of the map/array being entered.
+ *
+ * The cursor is forced by: 1) setting the input buffer position to
+ * the item offset found by MapSearch(), 2) setting the map/array
+ * counter to the total in the map/array, 3) setting the nesting
+ * level. Setting the map/array counter to the total is not
+ * strictly correct, but this is OK because this cursor only needs
+ * to be used to get one item and MapSearch() has already found it
+ * confirming it exists.
+ */
+ UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ /* The map to enter was found, now finish off entering it. */
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+#else
+ (void)szLabel;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+#else
+ (void)szLabel;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+/**
+ * @brief Semi-private to do the the work for EnterMap() and EnterArray().
+ *
+ * @param[in] pMe The decode context
+ * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
+ * @param[out] pItem The data item for the map or array entered.
+ *
+ * The next item in the traversal must be a map or array. This
+ * consumes that item and does the book keeping to enter the map or
+ * array.
+ */
+void
+QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
+ const uint8_t uType,
+ QCBORItem *pItem)
+{
+ QCBORError uErr;
+
+ /* Must only be called on maps and arrays. */
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ // Already in error state; do nothing.
+ return;
+ }
+
+ /* Get the data item that is the map or array being entered. */
+ QCBORItem Item;
+ uErr = QCBORDecode_GetNext(pMe, &Item);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ uint8_t uItemDataType = Item.uDataType;
+
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
+ if(uItemDataType != uType) {
+ uErr = QCBOR_ERR_UNEXPECTED_TYPE;
+ goto Done;
+ }
+
+ QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
+
+
+ const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
+ if(bIsEmpty) {
+ if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
+ // Undo decrement done by QCBORDecode_GetNext() so the the
+ // the decrement when exiting the map/array works correctly
+ pMe->nesting.pCurrent->u.ma.uCountCursor++;
+ }
+ // Special case to increment nesting level for zero-length maps
+ // and arrays entered in bounded mode.
+ DecodeNesting_Descend(&(pMe->nesting), uType);
+ }
+
+ pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
+
+ uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
+ UsefulInputBuf_Tell(&(pMe->InBuf)));
+
+ if(pItem != NULL) {
+ *pItem = Item;
+ }
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/**
+ * @brief Exit a bounded map, array or bstr (semi-private).
+ *
+ * @param[in] pMe Decode context.
+ * @param[in] uEndOffset The input buffer offset of the end of item exited.
+ *
+ * @returns QCBOR_SUCCESS or an error code.
+ *
+ * This is the common work for exiting a level that is a bounded map,
+ * array or bstr wrapped CBOR.
+ *
+ * One chunk of work is to set up the pre-order traversal so it is at
+ * the item just after the bounded map, array or bstr that is being
+ * exited. This is somewhat complex.
+ *
+ * The other work is to level-up the bounded mode to next higest
+ * bounded mode or the top level if there isn't one.
+ */
+QCBORError
+QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
+ const uint32_t uEndOffset)
+{
+ QCBORError uErr;
+
+ /*
+ * First the pre-order-traversal byte offset is positioned to the
+ * item just after the bounded mode item that was just consumed.
+ */
+ UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
+
+ /*
+ * Next, set the current nesting level to one above the bounded
+ * level that was just exited.
+ *
+ * DecodeNesting_CheckBoundedType() is always called before this
+ * and makes sure pCurrentBounded is valid.
+ */
+ DecodeNesting_LevelUpCurrent(&(pMe->nesting));
+
+ /*
+ * This does the complex work of leveling up the pre-order
+ * traversal when the end of a map or array or another bounded
+ * level is reached. It may do nothing, or ascend all the way to
+ * the top level.
+ */
+ uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ /*
+ * This makes the next highest bounded level the current bounded
+ * level. If there is no next highest level, then no bounded mode
+ * is in effect.
+ */
+ DecodeNesting_LevelUpBounded(&(pMe->nesting));
+
+ pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
+
+Done:
+ return uErr;
+}
+
+
+/**
+ * @brief Get started exiting a map or array (semi-private)
+ *
+ * @param[in] pMe The decode context
+ * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
+ *
+ * This does some work for map and array exiting (but not
+ * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
+ * is called to do the rest.
+ */
+void
+QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
+ const uint8_t uType)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ /* Already in error state; do nothing. */
+ return;
+ }
+
+ QCBORError uErr;
+
+ if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
+ uErr = QCBOR_ERR_EXIT_MISMATCH;
+ goto Done;
+ }
+
+ /*
+ Have to set the offset to the end of the map/array
+ that is being exited. If there is no cached value,
+ from previous map search, then do a dummy search.
+ */
+ if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
+ QCBORItem Dummy;
+ Dummy.uLabelType = QCBOR_TYPE_NONE;
+ uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+ uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+
+
+
+/**
+ * @brief Process simple type true and false, a boolean
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pItem The item with either true or false.
+ * @param[out] pBool The boolean value output.
+ *
+ * Sets the internal error if the item isn't a true or a false. Also
+ * records any tag numbers as the tag numbers of the last item.
+ */
+static void
+QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ bool *pBool)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ /* Already in error state, do nothing */
+ return;
+ }
+
+ switch(pItem->uDataType) {
+ case QCBOR_TYPE_TRUE:
+ *pBool = true;
+ break;
+
+ case QCBOR_TYPE_FALSE:
+ *pBool = false;
+ break;
+
+ default:
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ break;
+ }
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
+{
+ QCBORItem Item;
+ QCBORDecode_VGetNext(pMe, &Item);
+ QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ bool *pValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ bool *pValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
+}
+
+
+/**
+ * @brief Process simple values.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pItem The item with the simple value.
+ * @param[out] puSimple The simple value output.
+ *
+ * Sets the internal error if the item isn't a true or a false. Also
+ * records any tag numbers as the tag numbers of the last item.
+ */
+static void
+QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ uint8_t *puSimple)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ /* It's kind of lame to remap true...undef back to simple values, but
+ * this function isn't used much and to not do it would require
+ * changing GetNext() behavior in an incompatible way.
+ */
+ switch(pItem->uDataType) {
+ case QCBOR_TYPE_UKNOWN_SIMPLE:
+ *puSimple = pItem->val.uSimple;
+ break;
+
+ case QCBOR_TYPE_TRUE:
+ *puSimple = CBOR_SIMPLEV_TRUE;
+ break;
+
+ case QCBOR_TYPE_FALSE:
+ *puSimple = CBOR_SIMPLEV_FALSE;
+ break;
+
+ case QCBOR_TYPE_NULL:
+ *puSimple = CBOR_SIMPLEV_NULL;
+ break;
+
+ case QCBOR_TYPE_UNDEF:
+ *puSimple = CBOR_SIMPLEV_UNDEF;
+ break;
+
+ default:
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ return;
+ }
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
+{
+ QCBORItem Item;
+ QCBORDecode_VGetNext(pMe, &Item);
+ QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t *puSimpleValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t *puSimpleValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
+}
+
+
+
+
+
+
+// Improvement: add methods for wrapped CBOR, a simple alternate
+// to EnterBstrWrapped
+
diff --git a/src/qcbor_tag_decode.c b/src/qcbor_tag_decode.c
index 31f9c03..2627962 100644
--- a/src/qcbor_tag_decode.c
+++ b/src/qcbor_tag_decode.c
@@ -10,13 +10,1029 @@
* Created on 9/5/24 from qcbode_decode.c
* ========================================================================== */
-// TODO: qcbor_tag_decode.c or tag_decode.c
-
#include "qcbor/qcbor_tag_decode.h"
+#include "decode_private.h"
+#include "decode_nesting.h"
#include <math.h> /* For isnan() */
+
+#ifndef QCBOR_DISABLE_TAGS
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+{
+ QCBORItem Item;
+ size_t uOffset;
+ QCBORError uErr;
+
+ const QCBORDecodeNesting SaveNesting = pMe->nesting;
+ const UsefulInputBuf Save = pMe->InBuf;
+
+ uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+ if(uOffset == pMe->uTagNumberCheckOffset) {
+ pMe->uTagNumberIndex++;
+ } else {
+ pMe->uTagNumberIndex = 0;
+ }
+
+ *puTagNumber = CBOR_TAG_INVALID64;
+ uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
+ if(uErr) {
+ return uErr;
+ }
+
+ *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
+ if(*puTagNumber == CBOR_TAG_INVALID64 ||
+ QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+ pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
+ }
+ pMe->uTagNumberCheckOffset = uOffset;
+
+ pMe->nesting = SaveNesting;
+ pMe->InBuf = Save;
+
+ return QCBOR_SUCCESS;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+{
+ pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_tag_decode.h file
+ */
+QCBORError
+QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
+{
+ size_t uOffset;
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+ QCBORError uReturn;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return pMe->uLastError;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+
+ uOffset = Info.uStartOffset;
+ if(uOffset == pMe->uTagNumberCheckOffset) {
+ pMe->uTagNumberIndex++;
+ } else {
+ pMe->uTagNumberIndex = 0;
+ }
+
+ *puTagNumber = CBOR_TAG_INVALID64;
+
+ *puTagNumber = QCBORDecode_GetNthTagNumber(pMe,
+ &OneItemSeach[0],
+ pMe->uTagNumberIndex);
+ if(*puTagNumber == CBOR_TAG_INVALID64 ||
+ QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+ pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
+ }
+ pMe->uTagNumberCheckOffset = uOffset;
+
+ return uReturn;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ size_t uOffset;
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return pMe->uLastError;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+
+
+ uOffset = Info.uStartOffset;
+ if(uOffset == pMe->uTagNumberCheckOffset) {
+ pMe->uTagNumberIndex++;
+ } else {
+ pMe->uTagNumberIndex = 0;
+ }
+
+ *puTagNumber = CBOR_TAG_INVALID64;
+
+ *puTagNumber = QCBORDecode_GetNthTagNumber(pMe,
+ &OneItemSeach[0],
+ pMe->uTagNumberIndex);
+ if(*puTagNumber == CBOR_TAG_INVALID64 ||
+ QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+ pMe->uTagNumberIndex = 255; /* All tags clear for this item */
+ }
+ pMe->uTagNumberCheckOffset = uOffset;
+
+ return uReturn;
+#else /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+ (void)pMe;
+ (void)szLabel;
+ (void)puTagNumber;
+ return QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ uint8_t uIndex)
+{
+ if(pItem->uDataType == QCBOR_TYPE_NONE) {
+ return CBOR_TAG_INVALID64;
+ }
+ if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe, uint8_t uIndex)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return CBOR_TAG_INVALID64;
+ }
+ if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
+}
+
+
+static uint64_t
+QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
+ const uint16_t puTagNumbers[],
+ const uint32_t uIndex)
+{
+ uint32_t uArrayIndex;
+
+ /* Find number of tag numbers */
+ for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
+ if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
+ break;
+ }
+ }
+ if(uIndex > uArrayIndex) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const uint32_t uIndex)
+{
+ if(pItem->uDataType == QCBOR_TYPE_NONE) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_GetNthTagNumberReverse(pMe,
+ pItem->auTagNumbers,
+ uIndex);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, uint32_t uIndex)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return CBOR_TAG_INVALID64;
+ }
+ if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_GetNthTagNumberReverse(pMe,
+ pMe->auLastTags,
+ uIndex);
+}
+
+
+
+// TODO: uTagNumber might be better a list than calling this multiple times
+static QCBORError
+QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const uint64_t uTagNumber,
+ const size_t uOffset)
+{
+ if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
+ /* There are no tag numbers at all, so no unprocessed */
+ return QCBOR_SUCCESS;
+ }
+
+ /* There are some tag numbers, so keep checking. This check passes
+ * if there is one and only one tag number that matches uTagNumber
+ */
+
+ // TODO: behave different in v1 and v2?
+
+ const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
+
+ if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16) {
+ /* The only tag number is the one we are processing so no unprocessed */
+ return QCBOR_SUCCESS;
+ }
+
+ if(uOffset != pMe->uTagNumberCheckOffset) {
+ /* processed tag numbers are for some other item, not us */
+ return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+ }
+
+ if(pMe->uTagNumberIndex != 1) {
+ return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+ }
+
+ return QCBOR_SUCCESS;
+}
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+static QCBORError
+QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const size_t uOffset,
+ const uint8_t *uQCBORTypes,
+ const uint64_t *uTagNumbers,
+ const uint8_t uTagRequirement,
+ bool *bTypeMatched)
+{
+ const uint64_t *pQType;
+ const uint64_t *pTNum;
+ const uint8_t *pTypeNum;
+
+ const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
+
+ *bTypeMatched = false;
+ for(pTypeNum = uQCBORTypes; *pTypeNum != QCBOR_TYPE_NONE; pTypeNum++) {
+ if(pItem->uDataType == *pTypeNum) {
+ *bTypeMatched = true;
+ break;
+ }
+ }
+
+#ifndef QCBOR_DISABLE_TAGS
+ bool bTagNumberMatched;
+ QCBORError uErr;
+ const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
+
+ bTagNumberMatched = false;
+ for(pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
+ if(uInnerTag == *pQType) {
+ bTagNumberMatched = true;
+ break;
+ }
+ }
+
+
+ if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
+ /* There must be a tag number */
+ if(!bTagNumberMatched && !*bTypeMatched) {
+ return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
+ }
+
+ } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
+ if(bTagNumberMatched || *bTypeMatched) {
+ return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
+ }
+
+ } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
+ /* No check necessary */
+ }
+
+ /* Now check if there are extra tags and if there's an error in them */
+ if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
+ /* The flag to ignore extra is not set, so keep checking */
+ for(pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
+ uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
+ if(uErr != QCBOR_SUCCESS) {
+ return uErr;
+ }
+ }
+ }
+
+ return QCBOR_SUCCESS;
+#else /* ! QCBOR_DISABLE_TAGS */
+ (void)pMe;
+ (void)uOffset;
+ (void)uTagNumbers;
+
+ if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
+ return QCBOR_SUCCESS;
+ } else {
+ return QCBOR_ERR_UNEXPECTED_TYPE;
+ }
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+}
+
+
+void
+QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumbers[],
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset)
+{
+ QCBORError uErr;
+ bool bTypeMatched;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ uErr = QCBORDecode_Private_CheckTagNType(pMe,
+ pItem,
+ uOffset,
+ uQCBORTypes,
+ uTagNumbers,
+ uTagRequirement,
+ &bTypeMatched);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ if(!bTypeMatched) {
+ /* Tag content wasn't previously processed, do it now */
+ uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/*
+ **/
+void
+QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumber,
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset)
+{
+ uint64_t auTagNumbers[2];
+
+ auTagNumbers[0] = uTagNumber;
+ auTagNumbers[1] = CBOR_TAG_INVALID64;
+
+ QCBORDecode_Private_ProcessTagItemMulti(pMe,
+ pItem,
+ uTagRequirement,
+ uQCBORTypes,
+ auTagNumbers,
+ pfCB,
+ uOffset);
+}
+
+
+static void
+QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORType,
+ const uint64_t uTagNumber,
+ QCBORTagContentCallBack *pfCB,
+ const size_t uOffset)
+{
+ uint8_t auQCBORType[2];
+
+ auQCBORType[0] = uQCBORType;
+ auQCBORType[1] = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_ProcessTagItem(pMe,
+ pItem,
+ uTagRequirement,
+ auQCBORType,
+ uTagNumber,
+ pfCB,
+ uOffset);
+}
+
+
+void
+QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBOR_Type,
+ const uint64_t uTagNumber,
+ UsefulBufC *pStr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ uQCBOR_Type,
+ uTagNumber,
+ QCBORDecode_StringsTagCB,
+ uOffset);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ *pStr = Item.val.string;
+ } else {
+ *pStr = NULLUsefulBufC;
+ }
+}
+
+
+/**
+ * @brief Semi-private to get an string by label to match a tag specification.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] nLabel Label to search map for.
+ * @param[in] uTagRequirement Whether or not tag number is required.
+ * See @ref QCBOR_TAG_REQUIREMENT_TAG.
+ * @param[in] uQCBOR_Type QCBOR type to search for.
+ * @param[in] uTagNumber Tag number to match.
+ * @param[out] pString The string found.
+ *
+ * This finds the string with the given label in currently open
+ * map. Then checks that its tag number and types matches the tag
+ * specification. If not, an error is set in the decode context.
+ */
+void
+QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBOR_Type,
+ const uint64_t uTagNumber,
+ UsefulBufC *pString)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ uQCBOR_Type,
+ uTagNumber,
+ QCBORDecode_StringsTagCB,
+ uOffset);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ *pString = Item.val.string;
+ }
+}
+
+
+/**
+ * @brief Semi-private to get an string by label to match a tag specification.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] szLabel Label to search map for.
+ * @param[in] uTagRequirement Whether or not tag number is required.
+ * See @ref QCBOR_TAG_REQUIREMENT_TAG.
+ * @param[in] uQCBOR_Type QCBOR type to search for.
+ * @param[in] uTagNumber Tag number to match.
+ * @param[out] pString The string found.
+ *
+ * This finds the string with the given label in currently open
+ * map. Then checks that its tag number and types matches the tag
+ * specification. If not, an error is set in the decode context.
+ */
+void
+QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ uint8_t uQCBOR_Type,
+ uint64_t uTagNumber,
+ UsefulBufC *pString)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ uQCBOR_Type,
+ uTagNumber,
+ QCBORDecode_StringsTagCB,
+ uOffset);
+
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ *pString = Item.val.string;
+ }
+}
+
+
+
+
+/**
+ * @brief The main work of entering some byte-string wrapped CBOR.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pItem The byte string item.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
+ * @param[out] pBstr Pointer and length of byte string entered.
+ *
+ * This is called once the byte string item has been decoded to do all
+ * the book keeping work for descending a nesting level into the
+ * nested CBOR.
+ *
+ * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
+ */
+static QCBORError
+QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const size_t uOffset,
+ UsefulBufC *pBstr)
+{
+ bool bTypeMatched;
+ QCBORError uError;
+
+ const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR,
+ QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE,
+ QCBOR_TYPE_NONE};
+ const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR,
+ CBOR_TAG_CBOR_SEQUENCE,
+ CBOR_TAG_INVALID64};
+
+
+ if(pBstr) {
+ *pBstr = NULLUsefulBufC;
+ }
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return pMe->uLastError;
+ }
+
+ if(pItem->uDataAlloc) {
+ return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
+ }
+
+ uError = QCBORDecode_Private_CheckTagNType(pMe,
+ pItem,
+ uOffset,
+ uTypes,//TODO: maybe empty?
+ uTagNumbers,
+ uTagRequirement,
+ &bTypeMatched);
+
+ if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
+ uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
+ }
+
+
+ if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
+ /* Reverse the decrement done by GetNext() for the bstr so the
+ * increment in QCBORDecode_NestLevelAscender() called by
+ * ExitBoundedLevel() will work right.
+ */
+ DecodeNesting_ReverseDecrement(&(pMe->nesting));
+ }
+
+ if(pBstr) {
+ *pBstr = pItem->val.string;
+ }
+
+ /* This saves the current length of the UsefulInputBuf and then
+ * narrows the UsefulInputBuf to start and length of the wrapped
+ * CBOR that is being entered.
+ *
+ * Most of these calls are simple inline accessors so this doesn't
+ * amount to much code.
+ */
+
+ const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
+ /* This check makes the cast of uPreviousLength to uint32_t below safe. */
+ if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ uError = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+
+ const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
+ pItem->val.string.ptr);
+ /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
+ if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
+ /* This should never happen because pItem->val.string.ptr should
+ * always be valid since it was just returned.
+ */
+ uError = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+
+ const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
+
+ UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
+ UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
+
+ uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
+ (uint32_t)uPreviousLength,
+ (uint32_t)uStartOfBstr);
+Done:
+ return uError;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pBstr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
+ &Item,
+ uTagRequirement,
+ uOffset,
+ pBstr);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pBstr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_BYTE_STRING,
+ &Item,
+ &uOffset);
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
+ &Item,
+ uTagRequirement,
+ uOffset,
+ pBstr);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pBstr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_BYTE_STRING,
+ &Item,
+ &uOffset);
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
+ &Item,
+ uTagRequirement,
+ uOffset,
+ pBstr);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ // Already in error state; do nothing.
+ return;
+ }
+
+ if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
+ pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
+ return;
+ }
+
+ const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
+
+ /*
+ Reset the length of the UsefulInputBuf to what it was before
+ the bstr wrapped CBOR was entered.
+ */
+ UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
+ DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
+
+
+ QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_EPOCH,
+ CBOR_TAG_DATE_EPOCH,
+ QCBORDecode_DateEpochTagCB,
+ uOffset);
+ *pnTime = Item.val.epochDate.nSeconds;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_EPOCH,
+ CBOR_TAG_DATE_EPOCH,
+ QCBORDecode_DateEpochTagCB,
+ uOffset);
+ *pnTime = Item.val.epochDate.nSeconds;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_EPOCH,
+ CBOR_TAG_DATE_EPOCH,
+ QCBORDecode_DateEpochTagCB,
+ uOffset);
+ *pnTime = Item.val.epochDate.nSeconds;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ int64_t *pnDays)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_EPOCH,
+ CBOR_TAG_DAYS_EPOCH,
+ QCBORDecode_DaysEpochTagCB,
+ uOffset);
+ *pnDays = Item.val.epochDays;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnDays)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_EPOCH,
+ CBOR_TAG_DAYS_EPOCH,
+ QCBORDecode_DaysEpochTagCB,
+ uOffset);
+ *pnDays = Item.val.epochDays;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnDays)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_EPOCH,
+ CBOR_TAG_DAYS_EPOCH,
+ QCBORDecode_DaysEpochTagCB,
+ uOffset);
+ *pnDays = Item.val.epochDays;
+}
+
+
+
+
+static void
+QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ UsefulBufC *pValue,
+ bool *pbIsTag257,
+ size_t uOffset)
+{
+ QCBORError uErr;
+
+ const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
+
+ const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
+
+ QCBORDecode_Private_ProcessTagItemMulti(pMe,
+ pItem,
+ uTagRequirement,
+ puTypes,
+ puTNs,
+ QCBORDecode_MIMETagCB,
+ uOffset);
+ if(pMe->uLastError) {
+ return;
+ }
+
+ if(pItem->uDataType == QCBOR_TYPE_MIME) {
+ *pbIsTag257 = false;
+ } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
+ *pbIsTag257 = true;
+ }
+ *pValue = pItem->val.string;
+
+
+ uErr = QCBOR_SUCCESS;
+
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_GetMIME(pMe,
+ uTagRequirement,
+ &Item,
+ pMessage,
+ pbIsTag257,
+ uOffset);
+}
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_GetMIME(pMe,
+ uTagRequirement,
+ &Item,
+ pMessage,
+ pbIsTag257,
+ uOffset);
+}
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_GetMIME(pMe,
+ uTagRequirement,
+ &Item,
+ pMessage,
+ pbIsTag257,
+ uOffset);
+}
+
+
+
+
/* Public function; see qcbor_tag_decode.h */
QCBORError
QCBORDecode_DateEpochTagCB(QCBORDecodeContext *pDecodeCtx,
@@ -166,7 +1182,8 @@
* @ref CBOR_TAG_BIG_FLOAT.
* @param[in] pDecodedItem Item being decoded.
*
- * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION and @ref QCBOR_TYPE_BIGFLOAT
+ * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION
+ * and @ref QCBOR_TYPE_BIGFLOAT
*
* Does mapping between a CBOR tag number and a QCBOR type with a
* little logic and arithmetic.