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 */