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: