Unbundle decode configuration (#275)

Rework the decode configuration so it is flags, not modes. The decode checks that make decode modes like CDE and Preferred and dCBOR are available individually.


* Unbundle decode configuration

* straggler

* fix test fan out

* Documentation updates

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index df365fe..1305b51 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -92,6 +92,30 @@
  * but the @ref SpiffyDecode APIs that allow searching maps by label
  * are often more convenient.
  *
+ * @anchor v2-Tag-Decoding
+ *
+ * RFC 7049 called tags "optional". This was a mistake. They specify
+ * critical type information that can't be ignored by decoders.
+ *
+ * QCBOR v1 always returns the tag numbers on an item
+ * in QCBORItem and leaves it up to the caller to check.
+ * Probably most callers don't know this and never added
+ * the check. There decode implementations are tolerant
+ * of random tag numbers and they shouldn't be.
+ *
+ * QCBOR v2 requires tags numbers to be processed by
+ * QCBORDecode_GetNextTagNumber(). If they are not
+ * an error will be returned.
+ *
+ * This new behavior saves the caller from having to do this check
+ * (that they probably didn't know they neeeded).  It is much more
+ * correct behavior.
+ *
+ * This behavior is not backwards compatible with v1. The v1 behavior
+ * can be restored with @ref QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS.
+ * However, the v2 behavior is more correct, so this configuration
+ * should not be used.
+ *
  * @anchor Decode-Errors-Overview
  * # Decode Errors Overview
  *
@@ -169,6 +193,7 @@
  * @anchor Disabilng-Tag-Decoding
  * # Disabilng Tag Decoding
  *
+ * TODO: update this
  * If QCBOR_DISABLE_TAGS is defined, all code for decoding tags will
  * be omitted reducing the core decoder, QCBORDecode_VGetNext(), by
  * about 400 bytes. If a tag number is encountered in the decoder
@@ -184,16 +209,64 @@
  * will be set.
  */
 
+
 /**
- * The decode mode options.
+ *  These are the decode configuration flags that can be or'd together
+ *  and passed to QCBORDecode_Init().
  */
 typedef enum {
-   /** See QCBORDecode_Init() */
+   /** Normal decoding with no flags set. */
    QCBOR_DECODE_MODE_NORMAL = 0,
-   /** See QCBORDecode_Init() */
-   QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
-   /** See QCBORDecode_Init() */
-   QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2,
+
+   /** Required map labels to be strings. If not @ref  QCBOR_ERR_MAP_LABEL_TYPE
+    * occurs. */
+   QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 0x01,
+
+   /** Causes maps to be treated as special arrays so all types of map
+    * labels can be decoded..  They will be returned with special
+    * @c uDataType @ref QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the
+    * number of items, will be double what it would be for a normal
+    * map because the labels are also counted. This mode is useful for
+    * decoding CBOR that has labels that are not integers or
+    * strings. Each map entry is decoded with two Get() calls, one for
+    * the label and one for the value. QCBORItem.label is never filled
+    * in. */
+   QCBOR_DECODE_MODE_MAP_AS_ARRAY = 0x02,
+
+   /** Makes QCBOR v2 tag decoding compatible with QCBOR v1. The error
+    *  @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER is not returned.  See
+    *  @ref v2-Tag-Decoding and QCBORDecode_CompatibilityV1().
+    */
+   QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS = 0x04,
+
+   /** Error out on indefinite length strings, arrays and maps. */
+   QCBOR_DECODE_NO_INDEF_LENGTH = 0x08,
+
+   /** Error out if integers or floats are encoded as
+    *  non-preferred. */
+   QCBOR_DECODE_ONLY_PREFERRED_NUMBERS = 0x10,
+
+   /** If big numbers that will fit into normal integers are
+    *  encountered error XXX will occur. This is to comply with big
+    *  number preferred serialization. */
+   QCBOR_DECODE_ONLY_PREFERRED_BIG_NUMBERS = 0x20,
+
+   /** If maps are not sorted, error @ref QCBOR_ERR_UNSORTED
+    *  occurs. This is makes map decoding take more CPU time, but that
+    *  is probably only of consequence with big maps on small CPUs. */
+   QCBOR_DECODE_ONLY_SORTED_MAPS = 0x40,
+
+   /** If whole number floats are present (they are not encoded as
+    * integers), error @ref QCBOR_ERR_DCBOR_CONFORMANCE occurs. This
+    * is as required for dCBOR.
+    */
+   QCBOR_DECODE_ONLY_REDUCED_FLOATS = 0x80,
+
+   /** dCBOR allows only the simple types true, false and NULL
+    * This enforces that.
+    */
+   QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES = 0x100,
+
    /**
     * This checks that the input is encoded with preferred
     * serialization. The checking is performed as each item is
@@ -205,7 +278,9 @@
     * lengths and tags, must be in shortest form, and floating-point
     * numbers must be reduced to shortest form all the way to
     * half-precision. */
-   QCBOR_DECODE_MODE_PREFERRED = 3,
+   QCBOR_DECODE_MODE_PREFERRED = QCBOR_DECODE_NO_INDEF_LENGTH |
+                                 QCBOR_DECODE_ONLY_PREFERRED_NUMBERS |
+                                 QCBOR_DECODE_ONLY_PREFERRED_BIG_NUMBERS,
 
    /** This checks that maps in the input are sorted by label as
     * described in RFC 8949 section 4.2.1.  This also performs
@@ -214,21 +289,18 @@
     * for large inputs on slow CPUs.
     *
     * This also performs all the checks that
-    * QCBOR_DECODE_MODE_PREFERRED does. */
-   QCBOR_DECODE_MODE_CDE = 4,
-   
+    * @ref QCBOR_DECODE_MODE_PREFERRED does. */
+   QCBOR_DECODE_MODE_CDE = QCBOR_DECODE_MODE_PREFERRED |
+                           QCBOR_DECODE_ONLY_SORTED_MAPS,
+
    /** This requires integer-float unification. It performs all the checks that
-    * QCBOR_DECODE_MODE_CDE does. */
-   QCBOR_DECODE_MODE_DCBOR = 5,
+    * @ref QCBOR_DECODE_MODE_CDE does. */
+   QCBOR_DECODE_MODE_DCBOR = QCBOR_DECODE_MODE_CDE |
+                             QCBOR_DECODE_ONLY_REDUCED_FLOATS |
+                             QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES,
 
-   /** Makes QCBOR v2 compatible with v1. The error @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER is not returned.
-    * This can be or'd with the above modes. */
-   QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS = 8,
-
-   /* This is stored in uint8_t in places; never add values > 255 */
 } QCBORDecodeMode;
 
-#define QCBOR_DECODE_MODE_MASK 0x07
 
 
 /**
@@ -730,43 +802,21 @@
 /**
  * Initialize the CBOR decoder context.
  *
- * @param[in] pCtx         The context to initialize.
- * @param[in] EncodedCBOR  The buffer with CBOR encoded bytes to be decoded.
- * @param[in] nMode        See below and @ref QCBORDecodeMode.
+ * @param[in] pCtx          The context to initialize.
+ * @param[in] EncodedCBOR   The buffer with CBOR encoded bytes to be decoded.
+ * @param[in] uConfigFlags  See @ref QCBORDecodeMode.
  *
- * Initialize context for a pre-order traversal of the encoded CBOR
- * tree.
+ * Initialize the decoder context with the encoded CBOR to be decoded.
  *
- * Most CBOR decoding can be completed by calling this function to
- * start and QCBORDecode_GetNext() in a loop.
+ * For typical use, @c uConfigFlags is zero (@ref QCBOR_DECODE_MODE_NORMAL).
+ * See configuration flags that can be or'd defined in @ref QCBORDecodeMode.
  *
  * If indefinite-length strings are to be decoded, then
  * QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
- * called to set up a string allocator.
- *
- * Three decoding modes are supported.  In normal mode, @ref
- * QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers
- * are accepted as map labels. If a label is other than these, the
- * error @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by
- * QCBORDecode_GetNext().
- *
- * TODO: get rid of QCBOR_DECODE_MODE_MAP_STRINGS_ONLY in v2?
- * In strings-only mode, @ref QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only
- * text strings are accepted for map labels.  This lines up with CBOR
- * that converts to JSON. The error @ref QCBOR_ERR_MAP_LABEL_TYPE is
- * returned by QCBORDecode_GetNext() if anything but a text string
- * label is encountered.
- *
- * In @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special
- * arrays.  They will be returned with special @c uDataType @ref
- * QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the number of items, will be
- * double what it would be for a normal map because the labels are
- * also counted. This mode is useful for decoding CBOR that has labels
- * that are not integers or text strings, but the caller must manage
- * much of the map decoding.
+ * additionally called to set up a string allocator.
  */
 void
-QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
+QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode uConfigFlags);
 
 
 /**
@@ -1695,25 +1745,28 @@
  * ========================================================================= */
 
 /**
- * TODO: Initialize the CBOR decoder context with QCBOR v1 compatibility (deprecated).
+ * @brief Configure CBOR decoder context for QCBOR v1 compatibility (deprecated).
  *
- * @param[in] pCtx         The context to initialize.
+ * @param[in] pCtx  The context to configure.
  *
- * This is listed as deprecated even though it is new in QCBOR v2 because
- * it recommended that v1 mode not be used because the tag number processing
- * is too loose.
+ * This performs two actions to make QCBOR v2 decoding compatible with v1.
  *
- * This links in a fair bit of object code for all the tag handlers that were
- * always present in v1. If you don't care about them, use pass XXX to init().
+ * First, it sets @ref QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS
+ * which causes no error to be returned when un processed tag numbers
+ * are encountered.
  *
- * This is the same as QCBORDecode_Init() except it changes the
- * tag number decoding behavior in two ways:
- *
- * First, it sets @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS which
- * causes no error to be returned when un processed tag numbers are encountered.
- *
- * Second, it installs all the same tag handlers that v1 had hardwwired.
+ * Second, it installs all the same tag content handlers that v1 had hardwwired.
  *    QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
+ *
+ * This is listed as deprecated even though it is new in QCBOR v2
+ * because it recommended that v1 mode not be used because the tag
+ * number processing is too loose.
+ *
+ * This links in a fair bit of object code for all the tag content
+ * handlers that were always present in v1. To get the v1 behavior
+ * without the object code for the tag content handlers, pass
+ * @ref QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS to
+ * QCBORDecode_Init().
  */
 void
 QCBORDecode_CompatibilityV1(QCBORDecodeContext *pCtx);
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index e69f97f..f860c49 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -256,7 +256,7 @@
  * 32-bit machine size is 200 bytes
  */
 typedef struct __QCBORDecodeNesting  {
-  /* PRIVATE DATA STRUCTURE */
+   /* PRIVATE DATA STRUCTURE */
    struct nesting_decode_level {
       /*
        * This keeps tracking info for each nesting level. There are two
@@ -346,6 +346,7 @@
 typedef uint16_t QCBORMappedTagNumbers[QCBOR_MAX_TAGS_PER_ITEM1];
 
 
+
 /*
  * PRIVATE DATA STRUCTURE
  *
@@ -380,7 +381,7 @@
 #define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX
    uint32_t uMapEndOffsetCache;
 
-   uint8_t  uDecodeMode;
+   uint32_t uDecodeMode;
    uint8_t  bStringAllocateAll;
    uint8_t  uLastError;  /* QCBORError stuffed into a uint8_t */
    uint8_t  bAllowAllLabels; /* Used internally only, not an external feature yet */
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index fd16322..1e272b7 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -647,14 +647,14 @@
 void
 QCBORDecode_Init(QCBORDecodeContext *pMe,
                  UsefulBufC          EncodedCBOR,
-                 QCBORDecodeMode     nDecodeMode)
+                 QCBORDecodeMode     uConfigFlags)
 {
    memset(pMe, 0, sizeof(QCBORDecodeContext));
    UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
    /* Don't bother with error check on decode mode. If a bad value is
     * passed it will just act as if the default normal mode of 0 was set.
     */
-   pMe->uDecodeMode = (uint8_t)nDecodeMode;
+   pMe->uDecodeMode = (uint32_t)uConfigFlags;
    DecodeNesting_Init(&(pMe->nesting));
 
    /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
@@ -671,7 +671,7 @@
 void
 QCBORDecode_CompatibilityV1(QCBORDecodeContext *pMe)
 {
-   pMe->uDecodeMode |= QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS;
+   pMe->uDecodeMode |= QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS;
 #ifndef QCBOR_DISABLE_TAGS
    QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
 #endif /* ! QCBOR_DISABLE_TAGS */
@@ -766,7 +766,7 @@
  * @brief Decode the CBOR head, the type and argument.
  *
  * @param[in] pUInBuf            The input buffer to read from.
- * @param[in] bRequirePreferred  Require preferred serialization for argument.
+ * @param[in] uConfigFlags   Decode mode flags.
  * @param[out] pnMajorType       The decoded major type.
  * @param[out] puArgument        The decoded argument.
  * @param[out] pnAdditionalInfo  The decoded Lower 5 bits of initial byte.
@@ -786,9 +786,9 @@
  * analyzers happier.
  */
 static QCBORError
-QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
+QCBOR_Private_DecodeHead(UsefulInputBuf  *pUInBuf,
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
-                         bool            bRequirePreferred,
+                         QCBORDecodeMode  uConfigFlags,
 #endif
                          int            *pnMajorType,
                          uint64_t       *puArgument,
@@ -817,7 +817,7 @@
 
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
       /* If requested, check that argument is in preferred form */
-      if(bRequirePreferred) {
+      if(uConfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
          uint64_t uMinArgument;
 
          if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
@@ -845,7 +845,7 @@
       goto Done;
    } else {
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
-      if(bRequirePreferred && nAdditionalInfo == LEN_IS_INDEFINITE) {
+      if(uConfigFlags & QCBOR_DECODE_NO_INDEF_LENGTH && nAdditionalInfo == LEN_IS_INDEFINITE) {
          uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
          goto Done;
       }
@@ -1047,7 +1047,7 @@
 /**
  * @brief Decode array or map.
  *
- * @param[in] uDecodeMode3Bit            Decoder mode.
+ * @param[in] uConfigFlags            Decoder mode.
  * @param[in] nMajorType       Whether it is a byte or text string.
  * @param[in] uItemCount       The length of the string.
  * @param[in] nAdditionalInfo  Whether it is an indefinite-length.
@@ -1066,11 +1066,11 @@
  * QCBOR_DISABLE_NON_INTEGER_LABELS.
  */
 static QCBORError
-QCBOR_Private_DecodeArrayOrMap(const uint8_t  uDecodeMode3Bit,
-                               const int      nMajorType,
-                               uint64_t       uItemCount,
-                               const int      nAdditionalInfo,
-                               QCBORItem     *pDecodedItem)
+QCBOR_Private_DecodeArrayOrMap(const QCBORDecodeMode  uConfigFlags,
+                               const int              nMajorType,
+                               uint64_t               uItemCount,
+                               const int              nAdditionalInfo,
+                               QCBORItem             *pDecodedItem)
 {
    QCBORError uReturn;
 
@@ -1084,11 +1084,11 @@
    #endif
    pDecodedItem->uDataType = (uint8_t)nMajorType;
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-   if(uDecodeMode3Bit == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
+   if((uConfigFlags & QCBOR_DECODE_MODE_MAP_AS_ARRAY) && nMajorType == QCBOR_TYPE_MAP) {
       pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
    }
 #else
-   (void)uDecodeMode3Bit;
+   (void)uConfigFlags;
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
 
    uReturn = QCBOR_SUCCESS;
@@ -1107,7 +1107,7 @@
 
       } else {
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-         if(uDecodeMode3Bit == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
+         if((uConfigFlags & QCBOR_DECODE_MODE_MAP_AS_ARRAY) && nMajorType == QCBOR_TYPE_MAP) {
             /* ------ Map as array ------ */
             uItemCount *= 2;
          }
@@ -1162,7 +1162,7 @@
 #if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
 
 static QCBORError
-QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode3Bit)
+QCBORDecode_Private_HalfConformance(const double d, const QCBORDecodeMode uConfigFlags)
 {
    struct IEEE754_ToInt ToInt;
 
@@ -1176,7 +1176,7 @@
     * The only thing allowed here is a double/half-precision that
     * can't be converted to anything but a double.
     */
-   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
+   if(uConfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
       ToInt = IEEE754_DoubleToInt(d);
       if(ToInt.type != QCBOR_TYPE_DOUBLE) {
          return QCBOR_ERR_DCBOR_CONFORMANCE;
@@ -1188,12 +1188,12 @@
 
 
 static QCBORError
-QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode3Bit)
+QCBORDecode_Private_SingleConformance(const float f, const QCBORDecodeMode uconfigFlags)
 {
    struct IEEE754_ToInt ToInt;
    IEEE754_union        ToSmaller;
 
-   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
+   if(uconfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
       /* See if it could have been encoded as an integer */
       ToInt = IEEE754_SingleToInt(f);
       if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
@@ -1207,7 +1207,7 @@
    }
 
    /* See if it could have been encoded shorter */
-   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
+   if(uconfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
       ToSmaller = IEEE754_SingleToHalf(f, true);
       if(ToSmaller.uSize != sizeof(float)) {
          return QCBOR_ERR_PREFERRED_CONFORMANCE;
@@ -1219,12 +1219,12 @@
 
 
 static QCBORError
-QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
+QCBORDecode_Private_DoubleConformance(const double d, QCBORDecodeMode uConfigFlags)
 {
    struct IEEE754_ToInt ToInt;
    IEEE754_union        ToSmaller;
 
-   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
+   if(uConfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
       /* See if it could have been encoded as an integer */
       ToInt = IEEE754_DoubleToInt(d);
       if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
@@ -1237,7 +1237,7 @@
    }
 
    /* See if it could have been encoded shorter */
-   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
+   if(uConfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
       ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
       if(ToSmaller.uSize != sizeof(double)) {
          return QCBOR_ERR_PREFERRED_CONFORMANCE;
@@ -1249,10 +1249,10 @@
 #else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
 
 static QCBORError
-QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode3Bit)
+QCBORDecode_Private_SingleConformance(const float f, const QCBORDecodeMode uConfigFlags)
 {
    (void)f;
-   if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
+   if(uConfigFlags & (QCBOR_DECODE_ONLY_REDUCED_FLOATS | QCBOR_DECODE_ONLY_PREFERRED_NUMBERS)) {
       return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
    } else {
       return QCBOR_SUCCESS;
@@ -1260,10 +1260,10 @@
 }
 
 static QCBORError
-QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
+QCBORDecode_Private_DoubleConformance(const double d, const QCBORDecodeMode uConfigFlags)
 {
    (void)d;
-   if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
+   if(uConfigFlags & (QCBOR_DECODE_ONLY_REDUCED_FLOATS | QCBOR_DECODE_ONLY_PREFERRED_NUMBERS)) {
       return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
    } else {
       return QCBOR_SUCCESS;
@@ -1276,10 +1276,10 @@
  * Decode a float
  */
 static QCBORError
-QCBOR_Private_DecodeFloat(const uint8_t  uDecodeMode3Bit,
-                          const int      nAdditionalInfo,
-                          const uint64_t uArgument,
-                          QCBORItem     *pDecodedItem)
+QCBOR_Private_DecodeFloat(const QCBORDecodeMode uConfigFlags,
+                          const int             nAdditionalInfo,
+                          const uint64_t        uArgument,
+                          QCBORItem            *pDecodedItem)
 {
    QCBORError uReturn = QCBOR_SUCCESS;
    float      single;
@@ -1296,7 +1296,7 @@
          pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
          pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
 
-         uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
+         uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uConfigFlags);
          if(uReturn != QCBOR_SUCCESS) {
             break;
          }
@@ -1314,7 +1314,7 @@
           * 32 bits. It was widened to 64 bits to be passed in here.
           */
          single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
-         uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode3Bit);
+         uReturn = QCBORDecode_Private_SingleConformance(single, uConfigFlags);
          if(uReturn != QCBOR_SUCCESS) {
             break;
          }
@@ -1342,7 +1342,7 @@
          pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
          pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
 
-         uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
+         uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uConfigFlags);
          if(uReturn != QCBOR_SUCCESS) {
             break;
          }
@@ -1400,10 +1400,10 @@
  *                                           type in input.
  */
 static QCBORError
-QCBOR_Private_DecodeType7(const uint8_t  uDecodeMode3Bit,
-                          const int      nAdditionalInfo,
-                          const uint64_t uArgument,
-                          QCBORItem     *pDecodedItem)
+QCBOR_Private_DecodeType7(const QCBORDecodeMode  uConfigFlags,
+                          const int              nAdditionalInfo,
+                          const uint64_t         uArgument,
+                          QCBORItem             *pDecodedItem)
 {
    QCBORError uReturn = QCBOR_SUCCESS;
 
@@ -1423,7 +1423,7 @@
       case SINGLE_PREC_FLOAT: /* 26 */
       case DOUBLE_PREC_FLOAT: /* 27 */
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-         uReturn = QCBOR_Private_DecodeFloat(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
+         uReturn = QCBOR_Private_DecodeFloat(uConfigFlags, nAdditionalInfo, uArgument, pDecodedItem);
 #else
          uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
 #endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
@@ -1435,7 +1435,7 @@
       case CBOR_SIMPLEV_UNDEF: /* 23 */
       case CBOR_SIMPLE_BREAK:  /* 31 */
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
-         if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR &&
+         if((uConfigFlags & QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES) &&
             nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
             uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
             goto Done;
@@ -1455,7 +1455,7 @@
 
       default: /* 0-19 */
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
-         if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR &&
+         if((uConfigFlags & QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES) &&
             (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
             uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
             goto Done;
@@ -1513,10 +1513,11 @@
                                    QCBORItem           *pDecodedItem)
 {
    QCBORError uReturn;
-   int       nMajorType = 0;
-   uint64_t  uArgument = 0;
-   int       nAdditionalInfo = 0;
-   uint8_t   uDecodeMode3Bit = pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK;
+   int        nMajorType = 0;
+   uint64_t   uArgument = 0;
+   int        nAdditionalInfo = 0;
+
+   const QCBORDecodeMode uDecodeMode = pMe->uDecodeMode;
 
    memset(pDecodedItem, 0, sizeof(QCBORItem));
 
@@ -1526,7 +1527,7 @@
    uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
                                       // TODO: make this prettier; will optimizer take out stuff without ifdef?
-                                      uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED,
+                                      uDecodeMode,
 #endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
                                       &nMajorType,
                                       &uArgument,
@@ -1553,7 +1554,7 @@
 
       case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
       case CBOR_MAJOR_TYPE_MAP:   /* Major type 5 */
-         return QCBOR_Private_DecodeArrayOrMap(uDecodeMode3Bit, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
+         return QCBOR_Private_DecodeArrayOrMap(uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
          break;
 
       case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
@@ -1562,7 +1563,7 @@
 
       case CBOR_MAJOR_TYPE_SIMPLE:
          /* Major type 7: float, double, true, false, null... */
-         return QCBOR_Private_DecodeType7(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
+         return QCBOR_Private_DecodeType7(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
          break;
 
       default:
@@ -2034,7 +2035,7 @@
    /* TODO: QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
     * get rid of it in QCBOR 2.0
     */
-   if((pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
+   if(pMe->uDecodeMode & QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
       LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
       uErr = QCBOR_ERR_MAP_LABEL_TYPE;
       goto Done;
@@ -2663,7 +2664,7 @@
 
 #ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
    if(uErr == QCBOR_SUCCESS &&
-      (pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) >= QCBOR_DECODE_MODE_CDE &&
+      pMe->uDecodeMode & QCBOR_DECODE_ONLY_SORTED_MAPS &&
       pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
       /* Traverse map checking sort order and for duplicates */
       uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
@@ -2672,7 +2673,7 @@
 
 #ifndef QCBOR_DISABLE_TAGS
    if(uErr == QCBOR_SUCCESS &&
-      !(pMe->uDecodeMode & QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS) &&
+      !(pMe->uDecodeMode & QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS) &&
       pDecodedItem->auTagNumbers[0] != CBOR_TAG_INVALID16) {
       /*  Not QCBOR v1; there are tag numbers -- check they were consumed */
       if(uOffset != pMe->uTagNumberCheckOffset || pMe->uTagNumberIndex != 255) {