Option to disable all tag processing;  Minor bug fix to QCBORDecode_GetDecimalFraction() 

This allows disabling of all tag decoding saving about 400 bytes of object code (a lot!).

This also fixes a bug where QCBORDecode_GetDecimalFraction() and
QCBORDecode_GetDecimalFractionBig() would fail on input CBOR that is not a tag when it should succeed.



* Check point work on disabling tags

* Check point tag disable

* Checkpoint work on disabling tags

* check point

* More tests are passing

* Check point ; down to only 3 tests not passing

* all tests passing

* documentation fixes

* minor tidying

* more tidiness

* More documentation

* Check point -- more tidiness

* Check point new mant/exp tests

* main source is probably done; more testing to do

* Documentation fix

* Improve testing of mantissa and exponent a lot

* Final clean up

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 46c4f12..841f49a 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -1163,12 +1163,16 @@
          break;
 
       case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
+#ifndef QCBOR_DISABLE_TAGS
          if(nAdditionalInfo == LEN_IS_INDEFINITE) {
             uReturn = QCBOR_ERR_BAD_INT;
          } else {
             pDecodedItem->val.uTagV = uArgument;
             pDecodedItem->uDataType = QCBOR_TYPE_TAG;
          }
+#else /* QCBOR_DISABLE_TAGS */
+         uReturn = QCBOR_ERR_TAGS_DISABLED;
+#endif /* QCBOR_DISABLE_TAGS */
          break;
 
       case CBOR_MAJOR_TYPE_SIMPLE:
@@ -1347,6 +1351,7 @@
 }
 
 
+#ifndef QCBOR_DISABLE_TAGS
 /**
  * @brief This converts a tag number to a shorter mapped value for storage.
  *
@@ -1421,6 +1426,7 @@
       return pMe->auMappedTags[uIndex];
    }
 }
+#endif /* QCBOR_DISABLE_TAGS */
 
 
 /**
@@ -1450,6 +1456,7 @@
 static QCBORError
 QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
 {
+#ifndef QCBOR_DISABLE_TAGS
    /* Accummulate the tags from multiple items here and then copy them
     * into the last item, the non-tag item.
     */
@@ -1508,8 +1515,13 @@
 
 Done:
    return uReturn;
-}
 
+#else /* QCBOR_DISABLE_TAGS */
+
+   return QCBORDecode_GetNextFullString(pMe, pDecodedItem);
+
+#endif /* QCBOR_DISABLE_TAGS */
+}
 
 /**
  * @brief Combine a map entry label and value into one item (decode layer 3).
@@ -1900,6 +1912,7 @@
 }
 
 
+#ifndef QCBOR_DISABLE_TAGS
 /**
  * @brief Shift 0th tag out of the tag list.
  *
@@ -1916,6 +1929,7 @@
    pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
 }
 
+#endif /* QCBOR_DISABLE_TAGS */
 
 /**
  * @brief Convert different epoch date formats in to the QCBOR epoch date format
@@ -2074,6 +2088,18 @@
 
 
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
+
+/* Forward declaration is necessary for
+ * QCBORDecode_MantissaAndExponent().  to be able to decode bignum
+ * tags in the mantissa. If the mantissa is a decimal fraction or big
+ * float in error, this will result in a recurive call to
+ * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
+ * correctly and the correct error is returned.
+ */
+static QCBORError
+QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem);
+
+
 /**
  * @brief Decode decimal fractions and big floats.
  *
@@ -2086,14 +2112,19 @@
  * @returns  Decoding errors from getting primitive data items or
  *           \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
  *
- * When called pDecodedItem must be the array that is tagged as a big
- * float or decimal fraction, the array that has the two members, the
+ * When called pDecodedItem must be the array with two members, the
  * exponent and mantissa.
  *
  * This will fetch and decode the exponent and mantissa and put the
  * result back into pDecodedItem.
+ *
+ * This does no checking or processing of tag numbers. That is to be
+ * done by the code that calls this.
+ *
+ * This stuffs the type of the mantissa into pDecodedItem with the expectation
+ * the caller will process it.
  */
-static inline QCBORError
+static QCBORError
 QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
 {
    QCBORError uReturn;
@@ -2105,16 +2136,12 @@
    }
 
    /* A check for pDecodedItem->val.uCount == 2 would work for
-    * definite-length arrays, but not for indefnite.  Instead remember
+    * definite-length arrays, but not for indefinite.  Instead remember
     * the nesting level the two integers must be at, which is one
     * deeper than that of the array.
     */
    const int nNestLevel = pDecodedItem->uNestingLevel + 1;
 
-   /* --- Which is it, decimal fraction or a bigfloat? --- */
-   const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(pMe, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
-   pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
-
    /* --- Get the exponent --- */
    QCBORItem exponentItem;
    uReturn = QCBORDecode_GetNextMapOrArray(pMe, &exponentItem);
@@ -2142,7 +2169,7 @@
 
    /* --- Get the mantissa --- */
    QCBORItem mantissaItem;
-   uReturn = QCBORDecode_GetNextWithTags(pMe, &mantissaItem, NULL);
+   uReturn = QCBORDecode_GetNextTagContent(pMe, &mantissaItem);
    if(uReturn != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -2151,6 +2178,9 @@
       uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
       goto Done;
    }
+   /* Stuff the mantissa data type into the item to send it up to the
+    * the next level. */
+   pDecodedItem->uDataType = mantissaItem.uDataType;
    if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
       /* Data arriving as an unsigned int < INT64_MAX has been
        * converted to QCBOR_TYPE_INT64 and thus handled here. This is
@@ -2159,14 +2189,16 @@
        * and thus an error that will get handled in an else below.
        */
       pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
+#ifndef QCBOR_DISABLE_TAGS
+      /* With tags fully disabled a big number mantissa will error out
+       * in the call to QCBORDecode_GetNextWithTags() because it has
+       * a tag number.
+       */
    }  else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
               mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
       /* Got a good big num mantissa */
       pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
-      /* Depends on numbering of QCBOR_TYPE_XXX */
-      pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
-                                          mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
-                                          1);
+#endif /* QCBOR_DISABLE_TAGS */
    } else {
       /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
       uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
@@ -2176,6 +2208,7 @@
    /* --- Check that array only has the two numbers --- */
    if(mantissaItem.uNextNestLevel == nNestLevel) {
       /* Extra items in the decimal fraction / big float */
+      /* Improvement: this should probably be an unrecoverable error. */
       uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
       goto Done;
    }
@@ -2187,6 +2220,8 @@
 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
 
 
+#ifndef QCBOR_DISABLE_TAGS
+
 #ifndef QCBOR_DISABLE_UNCOMMON_TAGS
 /**
  * @brief Decode the MIME type tag
@@ -2215,7 +2250,6 @@
 }
 #endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
 
-
 /**
  * Table of CBOR tags whose content is either a text string or a byte
  * string. The table maps the CBOR tag to the QCBOR type. The high-bit
@@ -2303,6 +2337,31 @@
    pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
    return QCBOR_SUCCESS;
 }
+#endif /* QCBOR_DISABLE_TAGS */
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ * This returns the QCBOR_TYPE for a mantissa and exponent.
+
+Called in one context where there is always a tag
+
+ Called in another context where there might be a tag or the caller might say what they are expecting.
+
+ 6 possible outputs
+ */
+static inline uint8_t
+MantissaExponentDataType(const uint16_t uTagToProcess, const QCBORItem *pDecodedItem)
+{
+   uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
+                                       QCBOR_TYPE_DECIMAL_FRACTION :
+                                       QCBOR_TYPE_BIGFLOAT;
+   if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
+      uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
+   }
+   return uBase;
+}
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
 
 
 /**
@@ -2328,6 +2387,7 @@
       goto Done;
    }
 
+#ifndef QCBOR_DISABLE_TAGS
    /* When there are no tag numbers for the item, this exits first
     * thing and effectively does nothing.
     *
@@ -2357,6 +2417,9 @@
       } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
                 uTagToProcess == CBOR_TAG_BIGFLOAT) {
          uReturn = QCBORDecode_MantissaAndExponent(pMe, pDecodedItem);
+         /* --- Which is it, decimal fraction or a bigfloat? --- */
+         pDecodedItem->uDataType = MantissaExponentDataType(uTagToProcess, pDecodedItem);
+
 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
 #ifndef QCBOR_DISABLE_UNCOMMON_TAGS
       } else if(uTagToProcess == CBOR_TAG_MIME ||
@@ -2388,6 +2451,7 @@
        */
       ShiftTags(pDecodedItem);
    }
+#endif /* QCBOR_DISABLE_TAGS */
 
 Done:
    return uReturn;
@@ -2463,6 +2527,8 @@
                             QCBORItem          *pDecodedItem,
                             QCBORTagListOut    *pTags)
 {
+#ifndef QCBOR_DISABLE_TAGS
+
    QCBORError uReturn;
 
    uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
@@ -2486,6 +2552,13 @@
    }
 
    return QCBOR_SUCCESS;
+
+#else /* QCBOR_DISABLE_TAGS */
+   (void)pMe;
+   (void)pDecodedItem;
+   (void)pTags;
+   return QCBOR_ERR_TAGS_DISABLED;
+#endif /* QCBOR_DISABLE_TAGS */
 }
 
 
@@ -2496,6 +2569,7 @@
                           const QCBORItem   *pItem,
                           uint64_t           uTag)
 {
+#ifndef QCBOR_DISABLE_TAGS
    for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
       if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
          break;
@@ -2504,6 +2578,11 @@
          return true;
       }
    }
+#else /* QCBOR_TAGS_DISABLED */
+   (void)pMe;
+   (void)pItem;
+   (void)uTag;
+#endif /* QCBOR_TAGS_DISABLED */
 
    return false;
 }
@@ -2564,6 +2643,7 @@
                                const QCBORItem    *pItem,
                                uint32_t            uIndex)
 {
+#ifndef QCBOR_DISABLE_TAGS
    if(pItem->uDataType == QCBOR_TYPE_NONE) {
       return CBOR_TAG_INVALID64;
    }
@@ -2572,6 +2652,13 @@
    } else {
       return UnMapTagNumber(pMe, pItem->uTags[uIndex]);
    }
+#else /* QCBOR_DISABLE_TAGS */
+   (void)pMe;
+   (void)pItem;
+   (void)uIndex;
+
+   return CBOR_TAG_INVALID64;
+#endif /* QCBOR_DISABLE_TAGS */
 }
 
 
@@ -2581,6 +2668,8 @@
 uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
                                      uint32_t                  uIndex)
 {
+#ifndef QCBOR_DISABLE_TAGS
+
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return CBOR_TAG_INVALID64;
    }
@@ -2589,6 +2678,12 @@
    } else {
       return UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
    }
+#else /* QCBOR_DISABLE_TAGS */
+   (void)pMe;
+   (void)uIndex;
+
+   return CBOR_TAG_INVALID64;
+#endif /* QCBOR_DISABLE_TAGS */
 }
 
 
@@ -2784,9 +2879,15 @@
 
 
 
-static inline void CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
+static inline void
+CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
 {
+#ifndef QCBOR_DISABLE_TAGS
    memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
+#else
+   (void)pMe;
+   (void)pItem;
+#endif
 }
 
 
@@ -3224,7 +3325,6 @@
 }
 
 
-
 static QCBORError
 CheckTypeList(int uDataType, const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
 {
@@ -3238,30 +3338,47 @@
 
 
 /**
- @param[in] TagSpec  Specification for matching tags.
- @param[in] pItem    The item to check.
-
- @retval QCBOR_SUCCESS   \c uDataType is allowed by @c TagSpec
- @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
-
- The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered
- tag value.
+ * Match a tag/type specification against the type of the item.
+ *
+ * @param[in] TagSpec  Specification for matching tags.
+ * @param[in] pItem    The item to check.
+ *
+ * @retval QCBOR_SUCCESS   \c uDataType is allowed by @c TagSpec
+ * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
+ *
+ * This checks the item data type of untagged items as well as of
+ * tagged items against a specification to see if decoding should
+ * proceed.
+ *
+ * This relies on the automatic tag decoding done by QCBOR that turns
+ * tag numbers into particular QCBOR_TYPEs so there is no actual
+ * comparsion of tag numbers, just of QCBOR_TYPEs.
+ *
+ * This checks the data item type as possibly representing the tag
+ * number or as the tag content type.
+ *
+ * If QCBOR_DISABLE_TAGS is #defined,  this primarily checks the item
+ * data type against the allowed tag content types. It will also error out
+ * if the caller tries to require a tag because there is no way that can
+ * ever be fulfilled.
  */
 static QCBORError
 CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem)
 {
+   const int nItemType = pItem->uDataType;
+   const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
+
+#ifndef QCBOR_DISABLE_TAGS
    if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
       pItem->uTags[0] != CBOR_TAG_INVALID16) {
       /* There are tags that QCBOR couldn't process on this item and
-       the caller has told us there should not be. */
+       * the caller has told us there should not be.
+       */
       return QCBOR_ERR_UNEXPECTED_TYPE;
    }
 
-   const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
-   const int nItemType = pItem->uDataType;
-
    if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
-      // Must match the tag and only the tag
+      /* Must match the tag number and only the tag */
       return CheckTypeList(nItemType, TagSpec.uTaggedTypes);
    }
 
@@ -3272,26 +3389,35 @@
 
    if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
       /* Must match the content type and only the content type.
-       There was no match just above so it is a fail. */
+       * There was no match just above so it is a fail. */
       return QCBOR_ERR_UNEXPECTED_TYPE;
    }
 
-   /* If here it can match either the tag or the content
-    and it hasn't matched the content, so the end
-    result is whether it matches the tag. This is
-    also the case that the CBOR standard discourages. */
+   /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
+    * and it hasn't matched the content, so the end
+    * result is whether it matches the tag. This is
+    * the tag optional case that the CBOR standard discourages.
+    */
 
    return CheckTypeList(nItemType, TagSpec.uTaggedTypes);
-}
 
+#else /* QCBOR_DISABLE_TAGS */
+   if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
+      return QCBOR_ERR_UNEXPECTED_TYPE;
+   }
+
+   return CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
+
+#endif /* QCBOR_DISABLE_TAGS */
+}
 
 
 // This could be semi-private if need be
 static inline
-void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
-                                     int64_t             nLabel,
-                                     TagSpecification    TagSpec,
-                                     QCBORItem          *pItem)
+void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext    *pMe,
+                                     const int64_t          nLabel,
+                                     const TagSpecification TagSpec,
+                                     QCBORItem             *pItem)
 {
    QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
    if(pMe->uLastError != QCBOR_SUCCESS) {
@@ -3304,10 +3430,10 @@
 
 // This could be semi-private if need be
 static inline
-void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
-                                     const char          *szLabel,
-                                     TagSpecification    TagSpec,
-                                     QCBORItem          *pItem)
+void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext    *pMe,
+                                     const char             *szLabel,
+                                     const TagSpecification  TagSpec,
+                                     QCBORItem              *pItem)
 {
    QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
    if(pMe->uLastError != QCBOR_SUCCESS) {
@@ -3321,7 +3447,7 @@
 void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
                                        int64_t             nLabel,
                                        TagSpecification    TagSpec,
-                                       UsefulBufC          *pString)
+                                       UsefulBufC         *pString)
 {
    QCBORItem Item;
    QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
@@ -3631,10 +3757,11 @@
 
 
 
-static QCBORError InternalEnterBstrWrapped(QCBORDecodeContext *pMe,
-                                           const QCBORItem    *pItem,
-                                           uint8_t             uTagRequirement,
-                                           UsefulBufC         *pBstr)
+static QCBORError
+InternalEnterBstrWrapped(QCBORDecodeContext *pMe,
+                         const QCBORItem    *pItem,
+                         const uint8_t       uTagRequirement,
+                         UsefulBufC         *pBstr)
 {
    if(pBstr) {
       *pBstr = NULLUsefulBufC;
@@ -3875,7 +4002,7 @@
 
 static void ProcessEpochDate(QCBORDecodeContext *pMe,
                              QCBORItem           *pItem,
-                             uint8_t              uTagRequirement,
+                             const uint8_t        uTagRequirement,
                              int64_t             *pnTime)
 {
    if(pMe->uLastError != QCBOR_SUCCESS) {
@@ -4054,13 +4181,16 @@
 
 
 
-
-void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe,
-                                         TagSpecification    TagSpec,
-                                         UsefulBufC         *pBstr)
+/*
+ * @brief Get a string that matches the type/tag specification.
+ */
+void
+QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext     *pMe,
+                                    const TagSpecification  TagSpec,
+                                    UsefulBufC             *pBstr)
 {
    if(pMe->uLastError != QCBOR_SUCCESS) {
-      // Already in error state, do nothing
+      /* Already in error state, do nothing */
       return;
    }
 
@@ -4085,10 +4215,11 @@
 
 
 
-static QCBORError ProcessBigNum(uint8_t          uTagRequirement,
-                                const QCBORItem *pItem,
-                                UsefulBufC      *pValue,
-                                bool            *pbIsNegative)
+static QCBORError
+ProcessBigNum(const uint8_t   uTagRequirement,
+             const QCBORItem *pItem,
+             UsefulBufC      *pValue,
+             bool            *pbIsNegative)
 {
    const TagSpecification TagSpec =
    {
@@ -4179,10 +4310,11 @@
 
 
 // Semi private
-QCBORError QCBORDecode_GetMIMEInternal(uint8_t     uTagRequirement,
-                                       const       QCBORItem *pItem,
-                                       UsefulBufC *pMessage,
-                                       bool       *pbIsTag257)
+QCBORError
+QCBORDecode_GetMIMEInternal(const uint8_t     uTagRequirement,
+                            const QCBORItem  *pItem,
+                            UsefulBufC       *pMessage,
+                            bool             *pbIsTag257)
 {
    const TagSpecification TagSpecText =
       {
@@ -5469,38 +5601,105 @@
 }
 
 
-static QCBORError MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe,
-                                                 TagSpecification    TagSpec,
-                                                 QCBORItem          *pItem)
+/**
+ * @brief Check and/or complete mantissa and exponent item.
+ *
+ * @param[in] pMe        The decoder context
+ * @param[in] TagSpec    Expected type(s)
+ * @param[in,out] pItem  See below
+ *
+ * This is for decimal fractions and big floats, both of which are a
+ * mantissa and exponent.
+ *
+ * The input item is either a fully decoded decimal faction or big
+ * float, or a just the decoded first item of a decimal fraction or
+ * big float.
+ *
+ * On output, the item is always a fully decoded decimal fraction or
+ * big float.
+ *
+ * This errors out if the input type does not meet the TagSpec.
+ */
+// TODO: document and see tests for the bug that was fixed by this rewrite
+static QCBORError
+MantissaAndExponentTypeHandler(QCBORDecodeContext     *pMe,
+                               const TagSpecification  TagSpec,
+                               QCBORItem              *pItem)
 {
    QCBORError uErr;
-   // Loops runs at most 1.5 times. Making it a loop saves object code.
-   while(1) {
-      uErr = CheckTagRequirement(TagSpec, pItem);
-      if(uErr != QCBOR_SUCCESS) {
-         goto Done;
-      }
 
-      if(pItem->uDataType != QCBOR_TYPE_ARRAY) {
-         break; // Successful exit. Moving on to finish decoding.
-      }
+   /* pItem could either be an auto-decoded mantissa and exponent or
+    * the opening array of an undecoded mantissa and exponent. This
+    * check will succeed on either, but doesn't say which it was.
+    */
+   uErr = CheckTagRequirement(TagSpec, pItem);
+   if(uErr != QCBOR_SUCCESS) {
+      goto Done;
+   }
 
-      // The item is an array, which means an undecoded
-      // mantissa and exponent, so decode it. It will then
-      // have a different type and exit the loop if.
+   if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
+      /* The item is an array, which means is is an undecoded mantissa
+       * and exponent. This call consumes the items in the array and
+       * results in a decoded mantissa and exponent in pItem. This is
+       * the case where there was no tag.
+       */
       uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
       if(uErr != QCBOR_SUCCESS) {
          goto Done;
       }
 
-      // Second time around, the type must match.
-      TagSpec.uTagRequirement = QCBOR_TAG_REQUIREMENT_TAG;
+      /* The above decode didn't determine whether it is a decimal
+       * fraction or big num. Which of these two depends on what the
+       * caller wants it decoded as since there is no tag, so fish the
+       * type out of the TagSpec. */
+      pItem->uDataType = MantissaExponentDataType(TagSpec.uTaggedTypes[0], pItem);
+
+      /* No need to check the type again. All that we need to know was
+       * that it decoded correctly as a mantissa and exponent. The
+       * QCBOR type is set out by what was requested.
+       */
    }
+
+   /* If the item was not an array and the check passed, then
+    * it is a fully decoded big float or decimal fraction and
+    * matches what is requested.
+    */
+
 Done:
    return uErr;
 }
 
 
+/* Some notes from the work to disable tags.
+ *
+ * The API for big floats and decimal fractions seems good.
+ * If there's any issue with it it's that the code size to
+ * implement is a bit large because of the conversion
+ * to/from int and bignum that is required. There is no API
+ * that doesn't do the conversion so dead stripping will never
+ * leave that code out.
+ *
+ * The implementation itself seems correct, but not as clean
+ * and neat as it could be. It could probably be smaller too.
+ *
+ * The implementation has three main parts / functions
+ *  - The decoding of the array of two
+ *  - All the tag and type checking for the various API functions
+ *  - Conversion to/from bignum and int
+ *
+ * The type checking seems like it wastes the most code for
+ * what it needs to do.
+ *
+ * The inlining for the conversion is probably making the
+ * overall code base larger.
+ *
+ * The tests cases could be organized a lot better and be
+ * more thorough.
+ *
+ * Seems also like there could be more common code in the
+ * first tier part of the public API. Some functions only
+ * vary by a TagSpec.
+ */
 static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe,
                                        TagSpecification    TagSpec,
                                        QCBORItem          *pItem,
@@ -5518,10 +5717,12 @@
 
       case QCBOR_TYPE_DECIMAL_FRACTION:
       case QCBOR_TYPE_BIGFLOAT:
-         *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
          *pnExponent = pItem->val.expAndMantissa.nExponent;
+         *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
          break;
 
+#ifndef QCBOR_DISABLE_TAGS
+      /* If tags are disabled, mantissas can never be big nums */
       case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
       case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
          *pnExponent = pItem->val.expAndMantissa.nExponent;
@@ -5533,6 +5734,7 @@
          *pnExponent = pItem->val.expAndMantissa.nExponent;
          uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
          break;
+#endif /* QCBOR_DISABLE_TAGS */
 
       default:
          uErr = QCBOR_ERR_UNEXPECTED_TYPE;
@@ -5575,6 +5777,8 @@
          *pnExponent = pItem->val.expAndMantissa.nExponent;
          break;
 
+#ifndef QCBOR_DISABLE_TAGS
+      /* If tags are disabled, mantissas can never be big nums */
       case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
       case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
          *pnExponent = pItem->val.expAndMantissa.nExponent;
@@ -5588,6 +5792,7 @@
          *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
          *pbIsNegative = true;
          break;
+#endif /* QCBOR_DISABLE_TAGS */
 
       default:
          uErr = QCBOR_ERR_UNEXPECTED_TYPE;
@@ -5690,7 +5895,7 @@
 */
 void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
                                        uint8_t             uTagRequirement,
-                                       UsefulBuf          MantissaBuffer,
+                                       UsefulBuf           MantissaBuffer,
                                        UsefulBufC         *pMantissa,
                                        bool               *pbMantissaIsNegative,
                                        int64_t            *pnExponent)