Bug fixes for spiffy decode corner cases (#57)
* Bug fix for decoding empty maps and arrays with spiffy decode
* Bug fix for entering and exiting the same map multiple times
* Add a lot of tests for spiffy decoding of nested maps and arrays
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index afc3651..7b41ff3 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -227,7 +227,8 @@
return false;
}
// Works for both definite and indefinite length maps/arrays
- if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0) {
+ 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;
}
@@ -432,6 +433,13 @@
static inline void
+DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+}
+
+
+static inline void
DecodeNesting_Init(QCBORDecodeNesting *pNesting)
{
/* Assumes that *pNesting has been zero'd before this call. */
@@ -445,7 +453,7 @@
{
*pSave = *pNesting;
pNesting->pCurrent = pNesting->pCurrentBounded;
- pNesting->pCurrent->u.ma.uCountCursor = pNesting->pCurrent->u.ma.uCountTotal;
+ DecodeNesting_ResetMapOrArrayCount(pNesting);
}
@@ -2964,13 +2972,25 @@
}
+/**
+ * @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 SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
{
// 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) {
- // Already in error state; do nothing.
return;
}
@@ -2985,23 +3005,28 @@
return;
}
- /* Need to get the current pre-order nesting level and cursor to be
- at the map/array about to be entered.
-
- Also need the current map nesting level and start cursor to
- be at the right place.
-
- The UsefulInBuf offset could be anywhere, so no assumption is
- made about it.
-
- No assumption is made about the pre-order nesting level either.
-
- However the bounded mode nesting level is assumed to be one above
- the map level that is being entered.
+ /*
+ * 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.
*/
- /* Seek to the data item that is the map or array */
UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
QCBORDecode_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);