Allow disabling of indefinite length array/map decoding to save object code
Allows defining of QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS to save 200 bytes of object code for the smallest decode configuration.
Added a few more tests related to bstr-wrapped CBOR.
Some code tidiness fixes (that don't change semantics)
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 9650e6a..ac59326 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -39,7 +39,7 @@
#include <math.h> // For isnan(), llround(), llroudf(), round(), roundf(),
// pow(), exp2()
#include <fenv.h> // feclearexcept(), fetestexcept()
-#endif
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
/*
@@ -76,6 +76,7 @@
static inline bool
QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem *pMe)
{
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
if(!QCBORItem_IsMapOrArray(pMe)){
return false;
}
@@ -84,6 +85,10 @@
return false;
}
return true;
+#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+ (void)pMe;
+ return false;
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
}
@@ -157,15 +162,18 @@
// 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_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
{
@@ -768,9 +776,9 @@
// was 16 bits. It was widened to 64 bits to be passed in here.
pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
-#else
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
nReturn = QCBOR_ERR_HALF_PRECISION_DISABLED;
-#endif
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
break;
case SINGLE_PREC_FLOAT: // 26
// Single precision is normally returned as a double
@@ -787,7 +795,7 @@
// In the normal case, use HW to convert float to double.
pDecodedItem->val.dfnum = (double)f;
pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
-#else
+#else /* QCBOR_DISABLE_FLOAT_HW_USE */
// Use of float HW is disabled, return as a float.
pDecodedItem->val.fnum = f;
pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
@@ -796,7 +804,7 @@
// as a double, but it adds object code and most likely
// anyone disabling FLOAT HW use doesn't care about
// floats and wants to save object code.
-#endif
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
}
break;
@@ -1000,7 +1008,12 @@
goto Done;
}
if(nAdditionalInfo == LEN_IS_INDEFINITE) {
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
+#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+ nReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
+ break;
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
} else {
// type conversion OK because of check above
pDecodedItem->val.uCount = (uint16_t)uNumber;
@@ -1401,6 +1414,7 @@
}
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
/*
See if next item is a CBOR break. If it is, it is consumed,
if not it is not consumed.
@@ -1426,32 +1440,47 @@
return QCBOR_SUCCESS;
}
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
/*
- An item was just consumed, now figure out if it was the
- end of an array or map that can be closed out. That
- may in turn close out another map or array.
+ * An item was just consumed, now figure out if it was the
+ * end of an array/map map that can be closed out. That
+ * may in turn close out the above array/map...
*/
static QCBORError NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd)
{
QCBORError uReturn;
- /* This loops ascending nesting levels as long as there is ascending to do */
+ /* Loop ascending nesting levels as long as there is ascending to do */
while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
- if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
- /* Decrement count for definite length maps / arrays */
+ if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
+ /* Nesting level is bstr-wrapped CBOR */
+
+ /* Ascent for bstr-wrapped CBOR is always by explicit call
+ * so no further ascending can happen.
+ */
+ break;
+
+ } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
+ /* Level is a definite-length array/map */
+
+ /* Decrement the item count the definite-length array/map */
DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
- /* Didn't close out map or array, so all work here is done */
+ /* Didn't close out array/map, so all work here is done */
break;
}
- /* All of a definite length array was consumed; fall through to
- ascend */
+ /* All items in a definite length array were consumed so it
+ * is time to ascend one level. This happens below.
+ */
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
} else {
- /* If not definite length, have to check for a CBOR break */
+ /* Level is an indefinite-length array/map. */
+
+ /* Check for a break which is what ends indefinite-length arrays/maps */
bool bIsBreak = false;
uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
if(uReturn != QCBOR_SUCCESS) {
@@ -1459,33 +1488,28 @@
}
if(!bIsBreak) {
- /* It's not a break so nothing closes out and all work is done */
+ /* Not a break so array/map does not close out. All work is done */
break;
}
- if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
- /*
- Break occurred inside a bstr-wrapped CBOR or
- in the top level sequence. This is always an
- error because neither are an indefinte length
- map/array.
- */
- uReturn = QCBOR_ERR_BAD_BREAK;
- goto Done;
- }
+ /* It was a break in an indefinite length map / array so
+ * it is time to ascend one level.
+ */
- /* It was a break in an indefinite length map / array */
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
}
- /* All items in the map/array level have been consumed. */
+
+ /* All items in the array/map have been consumed. */
/* But ascent in bounded mode is only by explicit call to
- QCBORDecode_ExitBoundedMode() */
+ * QCBORDecode_ExitBoundedMode().
+ */
if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
/* Set the count to zero for definite length arrays to indicate
- cursor is at end of bounded map / array */
+ * cursor is at end of bounded array/map */
if(bMarkEnd) {
- // Used for definite and indefinite to signal end
+ /* Used for definite and indefinite to signal end */
DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
}
@@ -1498,7 +1522,10 @@
uReturn = QCBOR_SUCCESS;
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Done:
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
return uReturn;
}
@@ -1561,15 +1588,15 @@
/*
Check to see if at the end of a bounded definite length map or
- array. The check for the end of an indefinite length array is
- later.
+ array. The check for a break ending indefinite length array is
+ later in NestLevelAscender().
*/
if(DecodeNesting_IsAtEndOfBoundedLevel(&(me->nesting))) {
uReturn = QCBOR_ERR_NO_MORE_ITEMS;
goto Done;
}
- /* ==== Next: not at the end so get another item ==== */
+ /* ==== Next: not at the end, so get another item ==== */
uReturn = GetNext_MapEntry(me, pDecodedItem);
if(QCBORDecode_IsUnrecoverableError(uReturn)) {
/* Error is so bad that traversal is not possible. */
@@ -1577,8 +1604,8 @@
}
/*
- Breaks ending arrays/maps are always processed at the end of this
- function. They should never show up here.
+ Breaks ending arrays/maps are processed later in the call to
+ NestLevelAscender(). They should never show up here.
*/
if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
uReturn = QCBOR_ERR_BAD_BREAK;
@@ -1623,7 +1650,7 @@
QCBORItem_IsIndefiniteLengthMapOrArray(pDecodedItem)) {
/*
The following cases are handled here:
- - A non-aggregate like an integer or string
+ - A non-aggregate item like an integer or string
- An empty definite length map or array
- An indefinite length map or array that might be empty or might not.
@@ -4528,7 +4555,7 @@
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
-#endif
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
@@ -4634,9 +4661,9 @@
return QCBOR_ERR_UNEXPECTED_TYPE;
}
}
-#else
+#else /* QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
-#endif
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
break;
case QCBOR_TYPE_DOUBLE: