Merge some feature adds from QCBOR 1.x into dev
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index 1a4a3bf..95f0571 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -43,7 +43,8 @@
 
  when         who             what, where, why
  --------     ----            --------------------------------------------------
- 28/02/2022   llundblade      Rearrange UsefulOutBuf_Compare().
+ 10/05/2024   llundblade      Add Xxx_OffsetToPointer.
+ 28/02/2024   llundblade      Rearrange UsefulOutBuf_Compare().
  19/11/2023   llundblade      Add UsefulOutBuf_GetOutput().
  19/11/2023   llundblade      Add UsefulOutBuf_Swap().
  19/11/2023   llundblade      Add UsefulOutBuf_Compare().
@@ -651,16 +652,27 @@
 
 
 /**
- @brief Convert a pointer to an offset with bounds checking.
-
- @param[in] UB  Pointer to the UsefulInputBuf.
- @param[in] p   Pointer to convert to offset.
-
- @return SIZE_MAX if @c p is out of range, the byte offset if not.
+ * @brief Convert a pointer to an offset with bounds checking.
+ *
+ * @param[in] UB  A UsefulBuf.
+ * @param[in] p   Pointer to convert to offset.
+ *
+ * @return SIZE_MAX if @c p is out of range, the byte offset if not.
 */
 static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p);
 
 
+/**
+ * @brief Convert an offset to a pointer with bounds checking.
+ *
+ * @param[in] UB       A UsefulBuf.
+ * @param[in] uOffset  Offset in @c pUInBuf.
+ *
+ * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not.
+ */
+static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset);
+
+
 #ifndef USEFULBUF_DISABLE_DEPRECATED
 /** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
 #define SZLiteralToUsefulBufC(szString)  UsefulBuf_FROM_SZ_LITERAL(szString)
@@ -1589,7 +1601,18 @@
  *
  * @return SIZE_MAX if @c p is out of range, the byte offset if not.
  */
-static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p);
+static size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p);
+
+
+/**
+ * @brief Convert an offset to a pointer with bounds checking.
+ *
+ * @param[in] pUInBuf  Pointer to the @ref UsefulInputBuf.
+ * @param[in] uOffset  Offset in @c pUInBuf.
+ *
+ * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not.
+ */
+static const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset);
 
 
 /**
@@ -1955,6 +1978,18 @@
 }
 
 
+static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset)
+{
+   if(UsefulBuf_IsNULLC(UB) || uOffset >= UB.len) {
+      return NULL;
+   }
+
+   return (const uint8_t *)UB.ptr + uOffset;
+}
+
+
+
+
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
 static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
 {
@@ -2361,6 +2396,12 @@
 }
 
 
+static inline const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset)
+ {
+    return UsefulBuf_OffsetToPointer(pUInBuf->UB, uOffset);
+ }
+
+
 static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
 {
    const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 8c6c125..652cf01 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -238,7 +238,7 @@
 
 
 /**
- * Error codes returned by QCBOR Encoder and Decoder.
+ * Error codes returned by QCBOR Encoder-Decoder.
  *
  * They are grouped to keep the code size of
  * QCBORDecode_IsNotWellFormedError() and
@@ -535,6 +535,10 @@
     * negative integer) without allowing it by calling
     * QCBOREncode_Allow() */
    QCBOR_ERR_NOT_ALLOWED = 80,
+   /** QCBORDecode_EnterBstrWrapped() cannot be used on
+    * indefinite-length strings because they exist in memory pool for
+    * a @ref QCBORStringAllocate. */
+   QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 81,
 
    /** A range of error codes that can be made use of by the
     * caller. QCBOR internally does nothing with these except notice
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 69dbbc1..d7010d9 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -56,7 +56,7 @@
  * # QCBOR Basic Decode
  *
  * This section discusses decoding assuming familiarity with the
- * general description of this encoder / decoder in section @ref
+ * general description of this encoder-decoder in section @ref
  * Overview.
  *
  * Encoded CBOR has a tree structure where the leaf nodes are
@@ -64,9 +64,9 @@
  * nodes are either arrays or maps. Fundamentally, CBOR decoding is a
  * pre-order traversal of this tree with CBOR sequences a minor
  * exception. Calling QCBORDecode_GetNext() repeatedly will perform
- * this. It is possible to decode any CBOR by only calling
- * QCBORDecode_GetNext(), though this doesn't take advantage of many
- * QCBOR features.
+ * this. QCBOR maintains an internal traversal cursor. It is possible
+ * to decode any CBOR by only calling QCBORDecode_GetNext(), though
+ * this doesn't take advantage of many QCBOR features.
  *
  * QCBORDecode_GetNext() returns a 56 byte structure called
  * @ref QCBORItem that describes the decoded item including:
@@ -198,8 +198,8 @@
 } QCBORDecodeMode;
 
 /**
- * The maximum size of input to the decoder. Slightly less than UINT32_MAX
- * to make room for some special indicator values.
+ * The maximum size of input to the decoder. Slightly less than
+ * @c UINT32_MAX to make room for some special indicator values.
  */
 #define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2)
 
@@ -989,10 +989,19 @@
  * @param[in]  pCtx          The decoder context.
  * @param[out] pDecodedItem  The decoded CBOR item.
  *
- * This is the same as QCBORDecode_VGetNext() but the contents of the
- * entire map or array will be consumed if the item is a map or array.
+ * @c pItem returned is the same as QCBORDecode_VGetNext(). If the
+ * item is an array or map, the entire contents of the array or map
+ * will be consumed leaving the cursor after the array or map.
  *
- * In order to go back to decode the contents of a map or array
+ * If an array or map is being consumed by this, an error will occur
+ * if any of the items in the array or map are in error.
+ *
+ * If the item is a tag the contents of which is an array or map, like
+ * a big float, @c pItem will identify it as such and the contents
+ * will be consumed, but the validity of the tag won't be checked
+ * other than for being well-formed.
+ *
+ * In order to go back to decode the contents of an array or map
  * consumed by this, the decoder must be rewound using
  * QCBORDecode_Rewind().
  */
@@ -1043,6 +1052,48 @@
 
 
 /**
+ * @brief Get the current traversal cursort offset in the input CBOR.
+ *
+ * @param[in]  pCtx   The decoder context.
+ *
+ * @returns The traversal cursor offset or @c UINT32_MAX.
+
+ * The position returned is always the start of the next item that
+ * would be next decoded with QCBORDecode_VGetNext().  If the cursor
+ * is at the end of the input or in the error state, @c UINT32_MAX is
+ * returned.
+ *
+ * When decoding map items, the position returned is always of the
+ * label, never the value.
+ *
+ * For indefinite-length arrays and maps, the break byte is consumed
+ * when the last item in the array or map is consumed so the cursor is
+ * at the next item to be decoded as expected.
+ *
+ * There are some special rules for the traversal cursor when fetching
+ * map items by label. See the description of @SpiffyDecode.
+ *
+ * When traversal is bounded because an array or map has been entered
+ * (e.g., QCBORDecode_EnterMap()) and all items in the array or map
+ * have been consumed, the position returned will be of the item
+ * outside of the array or map. The array or map must be exited before
+ * QCBORDecode_VGetNext() will decode it.
+ *
+ * In many cases the position returned will be in the middle of
+ * an array or map. It will not be possible to start decoding at
+ * that location with another instance of the decoder and go to
+ * the end. It is not valid CBOR. If the input is a CBOR sequence
+ * and the position is not in the moddle of an array or map
+ * then it is possible to decode to the end.
+ *
+ * There is no corresponding seek method because it is too complicated
+ * to restore the internal decoder state that tracks nesting.
+ */
+uint32_t
+QCBORDecode_Tell(QCBORDecodeContext *pCtx);
+
+
+/**
  * @brief Returns the tag numbers for an item.
  *
  * @param[in] pCtx    The decoder context.
@@ -1068,7 +1119,7 @@
  * See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview.
  *
  * To reduce memory used by a QCBORItem, tag numbers larger than
- * UINT16_MAX are mapped so the tag numbers in @c uTags should be
+ * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be
  * accessed with this function rather than directly.
  *
  * This returns @ref CBOR_TAG_INVALID64 if any error occurred when
@@ -1281,8 +1332,8 @@
  * @return 0 on success -1 if not
  *
  * When decoding an integer, the CBOR decoder will return the value as
- * an int64_t unless the integer is in the range of @c INT64_MAX and @c
- * UINT64_MAX. That is, unless the value is so large that it can only be
+ * an int64_t unless the integer is in the range of @c INT64_MAX and
+ * @c UINT64_MAX. That is, unless the value is so large that it can only be
  * represented as a @c uint64_t, it will be an @c int64_t.
  *
  * CBOR itself doesn't size the individual integers it carries at
@@ -1494,7 +1545,7 @@
  * been decoded.
  *
  * This is not backwards compatibile in two ways. First, it is limited
- * to \ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was
+ * to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was
  * unlimited. Second, it will not inlucde the tags that QCBOR decodes
  * internally.
  *
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 694c2a3..008ee91 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -341,7 +341,7 @@
  * float type as 32-bits and a C double type as 64-bits. Floating-point
  * epoch dates will be unsupported.
  *
- * If USEFULBUF_DISABLE_ALL_FLOATis defined, then floating point
+ * If USEFULBUF_DISABLE_ALL_FLOAT is defined, then floating point
  * support is completely disabled. Decoding functions return
  * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is
  * encountered during decoding. Functions that are encoding floating
@@ -349,31 +349,33 @@
  *
  * ## Limitations
  *
- * Summary Limits of this implementation:
+ * Summary limitations:
  * - The entire encoded CBOR must fit into contiguous memory.
- * - Max size of encoded / decoded CBOR data is a few bytes less than @c UINT32_MAX (4GB).
- * - Max array / map nesting level when encoding / decoding is
+ * - Max size of encoded CBOR data is a few bytes less than
+ *   @c UINT32_MAX (4GB).
+ * - Max array / map nesting level when encoding or decoding is
  *   @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
- * - Max items in an array or map when encoding / decoding is
+ * - Max items in an array or map when encoding or decoding is
  *   @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
  * - Does not directly support labels in maps other than text strings & integers.
- * - Does not directly support integer labels greater than @c INT64_MAX.
+ * - Does not directly support integer labels beyond whats fits in @c int64_t
+ *   or @c uint64_t.
  * - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
- * - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX.
+ * - Exponents for bigfloats and decimal integers are limited to whats fits in
+ *   @c int64_t.
  * - Tags on labels are ignored during decoding.
  * - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4).
- * - Works only on 32- and 64-bit CPUs (modifications could make it work
- *   on 16-bit CPUs).
+ * - Works only on 32- and 64-bit CPUs.
+ * - QCBORDecode_EnterBstrWrapped() doesn't work on indefinite-length strings.
  *
  * The public interface uses @c size_t for all lengths. Internally the
  * implementation uses 32-bit lengths by design to use less memory and
  * fit structures on the stack. This limits the encoded CBOR it can
- * work with to size @c UINT32_MAX (4GB) which should be enough.
+ * work with to size @c UINT32_MAX (4GB).
  *
- * This implementation assumes two's compliment integer machines.
- * @c <stdint.h> also requires this. It is possible to modify this
- * implementation for another integer representation, but all modern
- * machines seem to be two's compliment.
+ * This implementation requires two's compliment integers. While
+ * C doesn't require two's compliment,  <stdint.h> does. Other
+ * parts of this implementation may also require two's compliment.
  */
 
 
@@ -4116,15 +4118,17 @@
 QCBOREncode_GetErrorState(QCBOREncodeContext *pMe)
 {
    if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
-      // Items didn't fit in the buffer.
-      // This check catches this condition for all the appends and inserts
-      // so checks aren't needed when the appends and inserts are performed.
-      // And of course UsefulBuf will never overrun the input buffer given
-      // to it. No complex analysis of the error handling in this file is
-      // needed to know that is true. Just read the UsefulBuf code.
+      /* Items didn't fit in the buffer. This check catches this
+       * condition for all the appends and inserts so checks aren't
+       * needed when the appends and inserts are performed.  And of
+       * course UsefulBuf will never overrun the input buffer given to
+       * it. No complex analysis of the error handling in this file is
+       * needed to know that is true. Just read the UsefulBuf code.
+       */
       pMe->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
-      // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
-      // OK. Once the caller fixes this, they'll be unmasked.
+      /* QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
+       * OK. Once the caller fixes this, they'll be unmasked.
+       */
    }
 
    return (QCBORError)pMe->uError;
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index ea543b0..20e99ba 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -269,13 +269,13 @@
        *   1) Byte count tracking. This is for the top level input CBOR
        *   which might be a single item or a CBOR sequence and byte
        *   string wrapped encoded CBOR.
-       *   2) Item tracking. This is for maps and arrays.
+       *   2) Item count tracking. This is for maps and arrays.
        *
        * uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and
        * QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY
        * for 2).
        *
-       * Item tracking is either for definite or indefinite-length
+       * Item count tracking is either for definite or indefinite-length
        * maps/arrays. For definite lengths, the total count and items
        * unconsumed are tracked. For indefinite-length, uTotalCount is
        * QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and
@@ -286,16 +286,16 @@
        * uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate
        * it is empty.
        *
-       * This also records whether a level is bounded or not.  All
+       * This also records whether a level is bounded or not. All
        * byte-count tracked levels (the top-level sequence and
-       * bstr-wrapped CBOR) are bounded. Maps and arrays may or may
-       * not be bounded. They are bounded if they were Entered() and
-       * not if they were traversed with GetNext(). They are marked as
-       * bounded by uStartOffset not being UINT32_MAX.
+       * bstr-wrapped CBOR) are bounded implicitly. Maps and arrays
+       * may or may not be bounded. They are bounded if they were
+       * Entered() and not if they were traversed with GetNext(). They
+       * are marked as bounded by uStartOffset not being @c UINT32_MAX.
        */
       /*
        * If uLevelType can put in a separately indexed array, the
-       * union/ struct will be 8 bytes rather than 9 and a lot of
+       * union/struct will be 8 bytes rather than 9 and a lot of
        * wasted padding for alignment will be saved.
        */
       uint8_t  uLevelType;
@@ -306,6 +306,8 @@
             uint16_t uCountTotal;
             uint16_t uCountCursor;
 #define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX
+            /* The start of the array or map in bounded mode so
+             * the input can be rewound for GetInMapXx() by label. */
             uint32_t uStartOffset;
          } ma; /* for maps and arrays */
          struct {
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index 1370ada..6169a90 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -91,9 +91,6 @@
  * QCBORDecode_EnterArray() can be used to narrow the traversal to the
  * extent of the array.
  *
- * QCBORDecode_EnterArray() can be used to narrow the traversal to the
- * extent of the array.
- *
  * All the QCBORDecode_GetXxxxInMapX() methods support duplicate label
  * detection and will result in an error if the map has duplicate
  * labels.
@@ -726,8 +723,8 @@
  * Nested arrays and maps may be entered to a depth of
  * @ref QCBOR_MAX_ARRAY_NESTING.
  *
- * See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap() and
- * QCBORDecode_EnterBstrWrapped().
+ * See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap(),
+ * QCBORDecode_EnterBstrWrapped() and QCBORDecode_GetArray().
  */
 static void
 QCBORDecode_EnterArray(QCBORDecodeContext *pCtx, QCBORItem *pItem);
@@ -749,7 +746,7 @@
  * The items in the array that was entered do not have to have been
  * consumed for this to succeed.
  *
- * This sets the pre-order traversal cursor to the item after the
+ * This sets the traversal cursor to the item after the
  * array that was exited.
  *
  * This will result in an error if any item in the array is not well
@@ -761,6 +758,65 @@
 
 
 
+/**
+ * @brief Get the encoded bytes that make up an array.
+ *
+ * @param[in] pCtx           The decode context.
+ * @param[out] pItem         Place to return the item.
+ * @param[out] pEncodedCBOR  Place to return pointer and length of the array.
+ *
+ * The next item to decode must be an array.
+ *
+ * The encoded bytes of the array will be returned. They can be
+ * decoded by another decoder instance.
+ *
+ * @c pItem will have the label and tags for the array. It is filled
+ * in the same as if QCBORDecode_GetNext() were called on the array item. In
+ * particular, the array count will be filled in for definite-length
+ * arrays and set to @c UINT16_MAX for indefinite-length arrays.
+ *
+ * This works on both definite and indefinite length arrays (unless
+ * indefinite length array decoding has been disabled).
+ *
+ * The pointer returned is to the data item that opens the array. The
+ * length in bytes includes it and all the member data items. If the array
+ * occurs in another map and thus has a label, the label is not included
+ * in what is returned.
+ *
+ * If the array is preceeded by tags, those encoded tags are included
+ * in the encoded CBOR that is returned.
+ *
+ * QCBORDecode_GetArray() consumes the entire array and leaves the
+ * traversal cursor at the item after the array.
+ * QCBORDecode_GetArrayFromMapN() and QCBORDecode_GetArrayFromMapSZ()
+ * don't affect the traversal cursor.
+ *
+ * This traverses the whole array and every subordinate array or map in
+ * it. This is necessary to determine the length of the array.
+ *
+ * This will fail if any item in the array is not well-formed.
+ *
+ * This uses a few hundred bytes of stack, more than most methods.
+ *
+ * See also QCBORDecode_EnterArray().
+ */
+static void
+QCBORDecode_GetArray(QCBORDecodeContext *pCtx,
+                     QCBORItem          *pItem,
+                     UsefulBufC         *pEncodedCBOR);
+
+static void
+QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pCtx,
+                             int64_t             nLabel,
+                             QCBORItem          *pItem,
+                             UsefulBufC         *pEncodedCBOR);
+
+static void
+QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pCtx,
+                              const char         *szLabel,
+                              QCBORItem          *pItem,
+                              UsefulBufC         *pEncodedCBOR);
+
 
 /**
  * @brief Enter a map for decoding and searching.
@@ -788,7 +844,7 @@
  * fully exited.
  *
  * While in bounded mode, QCBORDecode_GetNext() works as usual on the
- * map and the pre-order traversal cursor is maintained. It starts out
+ * map and the traversal cursor is maintained. It starts out
  * at the first item in the map just entered. Attempts to get items
  * off the end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS
  * rather going to the next item after the map as it would when not in
@@ -799,12 +855,12 @@
  * non-aggregate items by label behaves differently from entering subordinate
  * aggregate items by label.  See dicussion in @ref SpiffyDecode.
  *
- * Exiting leaves the pre-order cursor at the data item following the
+ * Exiting leaves the traversal cursor at the data item following the
  * last entry in the map or at the end of the input CBOR if there
  * nothing after the map.
  *
  * Entering and Exiting a map is a way to skip over an entire map and
- * its contents. After QCBORDecode_ExitMap(), the pre-order traversal
+ * its contents. After QCBORDecode_ExitMap(), the traversal
  * cursor will be at the first item after the map.
  *
  * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
@@ -813,6 +869,8 @@
  * QCBORDecode_EnterBstrWrapped().  Entering and exiting any nested
  * combination of maps, arrays and bstr-wrapped CBOR is supported up
  * to the maximum of @ref QCBOR_MAX_ARRAY_NESTING.
+ *
+ * See also QCBORDecode_GetMap().
  */
 static void
 QCBORDecode_EnterMap(QCBORDecodeContext *pCtx, QCBORItem *pItem);
@@ -834,7 +892,7 @@
  * The items in the map that was entered do not have to have been
  * consumed for this to succeed.
  *
- * This sets the pre-order traversal cursor to the item after the map
+ * This sets the traversal cursor to the item after the map
  * that was exited.
  *
  * This will result in an error if any item in the map is not well
@@ -846,6 +904,67 @@
 
 
 /**
+ * @brief Get the bytes that make up a map.
+ *
+ * @param[in] pCtx           The decode context.
+ * @param[out] pItem         Place to return the item.
+ * @param[out] pEncodedCBOR  Place to return pointer and length of the map.
+ *
+ * The next item to decode must be a map.
+ *
+ * The encoded bytes of the map will be returned. They can be
+ * decoded by another decoder instance.
+ *
+ *  @c pItem will have the label and tags for the array. It is filled
+ * in the same as if QCBORDecode_GetNext() were called on the map item. In
+ * particular, the map count will be filled in for definite-length
+ * maps and set to @c UINT16_MAX for indefinite-length maps.
+ *
+ * This works on both definite and indefinite length maps (unless
+ * indefinite length map decoding has been disabled).
+ *
+ * The pointer returned is to the data item that opens the map. The
+ * length in bytes includes it and all the member data items. If the map
+ * occurs in another map and thus has a label, the label is not included
+ * in what is returned.
+ *
+ * If the map is preceeded by tags, those encoded tags are included in
+ * the encoded CBOR that is returned.
+ *
+ * QCBORDecode_GetMap() consumes the entire array and leaves the
+ * traversal cursor at the item after the map.
+ * QCBORDecode_GetMapFromMapN() and QCBORDecode_GetMapFromMapSZ()
+ * don't affect the traversal cursor.
+ *
+ * This traverses the whole map and every subordinate array or map in
+ * it. This is necessary to determine the length of the map. The
+ * traversal cursor is left at the first item after the map.
+ *
+ * This will fail if any item in the map is not well-formed.
+ *
+ * This uses a few hundred bytes of stack, more than most methods.
+ *
+ * See also QCBORDecode_EnterMap().
+ */
+static void
+QCBORDecode_GetMap(QCBORDecodeContext *pCtx,
+                   QCBORItem          *pItem,
+                   UsefulBufC         *pEncodedCBOR);
+
+static void
+QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pCtx,
+                           int64_t             nLabel,
+                           QCBORItem          *pItem,
+                           UsefulBufC         *pEncodedCBOR);
+
+static void
+QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pCtx,
+                            const char         *szLabel,
+                            QCBORItem          *pItem,
+                            UsefulBufC         *pEncodedCBOR);
+
+
+/**
  * @brief Reset traversal cursor to start of map, array, byte-string
  *        wrapped CBOR or start of input.
  *
@@ -893,7 +1012,7 @@
  * with little nesting, this is of little consequence, but may be of
  * consequence for large deeply nested CBOR structures on slow CPUs.
  *
- * The position of the pre-order traversal cursor is not changed.
+ * The position of the traversal cursor is not changed.
  *
  * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
  *
@@ -940,7 +1059,7 @@
  * QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and
  * such to descend into and process maps and arrays.
  *
- * The position of the pre-order traversal cursor is not changed.
+ * The position of the traversal cursor is not changed.
  *
  * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
  *
@@ -1831,8 +1950,8 @@
  * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume
  * processing CBOR outside the wrapped CBOR.
  *
- * This does not (currently) work on indefinite-length strings. The
- * (confusing) error @ref QCBOR_ERR_INPUT_TOO_LARGE will be set.
+ * This does not work on indefinite-length strings. The
+ * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set.
  *
  * If @c pBstr is not @c NULL the pointer and length of the wrapped
  * CBOR will be returned. This is usually not needed, but sometimes
@@ -1873,7 +1992,7 @@
  * The items in the wrapped CBOR that was entered do not have to have
  * been consumed for this to succeed.
  *
- * The this sets the pre-order traversal cursor to the item after the
+ * The this sets the traversal cursor to the item after the
  * byte string that was exited.
  */
 void
@@ -2118,6 +2237,103 @@
 }
 
 
+/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+void
+QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx,
+                                  uint8_t             uType,
+                                  QCBORItem          *pItem,
+                                  UsefulBufC         *pEncodedCBOR);
+
+
+/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+void
+QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx,
+                                           QCBORItem          *pTarget,
+                                           QCBORItem          *pItem,
+                                           UsefulBufC         *pEncodedCBOR);
+
+
+static inline void
+QCBORDecode_GetArray(QCBORDecodeContext *pMe,
+                     QCBORItem          *pItem,
+                     UsefulBufC         *pEncodedCBOR)
+{
+   QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_ARRAY, pItem, pEncodedCBOR);
+}
+
+
+static inline void
+QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pMe,
+                             int64_t             nLabel,
+                             QCBORItem          *pItem,
+                             UsefulBufC         *pEncodedCBOR)
+{
+   QCBORItem OneItemSeach[2];
+   OneItemSeach[0].uLabelType  = QCBOR_TYPE_INT64;
+   OneItemSeach[0].label.int64 = nLabel;
+   OneItemSeach[0].uDataType   = QCBOR_TYPE_ARRAY;
+   OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE;
+
+   QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR);
+}
+
+
+static inline void
+QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pMe,
+                              const char         *szLabel,
+                              QCBORItem          *pItem,
+                              UsefulBufC         *pEncodedCBOR)
+{
+   QCBORItem OneItemSeach[2];
+   OneItemSeach[0].uLabelType   = QCBOR_TYPE_TEXT_STRING;
+   OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+   OneItemSeach[0].uDataType    = QCBOR_TYPE_ARRAY;
+   OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE;
+
+   QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR);
+}
+
+static inline void
+QCBORDecode_GetMap(QCBORDecodeContext *pMe,
+                   QCBORItem          *pItem,
+                   UsefulBufC         *pEncodedCBOR)
+{
+   QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_MAP, pItem, pEncodedCBOR);
+}
+
+
+static inline void
+QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pMe,
+                           int64_t             nLabel,
+                           QCBORItem          *pItem,
+                           UsefulBufC         *pEncodedCBOR)
+{
+   QCBORItem OneItemSeach[2];
+   OneItemSeach[0].uLabelType  = QCBOR_TYPE_INT64;
+   OneItemSeach[0].label.int64 = nLabel;
+   OneItemSeach[0].uDataType   = QCBOR_TYPE_MAP;
+   OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE;
+
+   QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR);
+}
+
+
+static inline void
+QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pMe,
+                            const char         *szLabel,
+                            QCBORItem          *pItem,
+                            UsefulBufC         *pEncodedCBOR)
+{
+   QCBORItem OneItemSeach[2];
+   OneItemSeach[0].uLabelType   = QCBOR_TYPE_TEXT_STRING;
+   OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+   OneItemSeach[0].uDataType    = QCBOR_TYPE_MAP;
+   OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE;
+
+   QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR);
+}
+
+
 
 static inline void
 QCBORDecode_GetInt64Convert(QCBORDecodeContext *pMe,