Merge some feature adds from QCBOR 1.x into dev
diff --git a/README.md b/README.md
index e6655cb..08ab1f5 100644
--- a/README.md
+++ b/README.md
@@ -15,10 +15,10 @@
 
 ![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true)
 
-**QCBOR** is a powerful, commercial-quality CBOR encoder/decoder that
+**QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that
 implements these RFCs:
 
-* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Everything
+* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything
 except sorting of encoded maps)
 * [RFC7049](https://tools.ietf.org/html/rfc7049) The previous CBOR standard.
 Replaced by RFC 8949.
@@ -183,11 +183,14 @@
 
 ## Code Status
 
-The current version is v1.1, a small feature addition and bug fix
-release over QCBOR 1.0.
+The official current release is version 1.3. Changes over the last few
+years have been only minor bug fixes, minor feature additions and
+documentation improvements. QCBOR 1.x is highly stable.
 
-Code has been stable for over a year. The last major change was in
-fall of 2020.
+Work on some larger feature additions is ongoing in "dev" branch.
+This includes more explicit support for preferred serialization and
+CDE (CBOR Deterministic Encoding).  It will eventually be release as
+QCBOR 2.x.
 
 QCBOR was originally developed by Qualcomm. It was [open sourced
 through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 59ceb3a..4df6e98 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -1,5 +1,5 @@
 /*==============================================================================
-  cmd_line_mainc.c -- Runs tests for QCBOR encoder / decoder
+  cmd_line_mainc.c -- Runs tests for QCBOR encoder-decoder
 
  Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
 
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,
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 64818df..d37aa24 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -1801,18 +1801,30 @@
  *
  * @param[in] pMe       The decode context.
  * @param[in] bMarkEnd  If true mark end of maps/arrays with count of zero.
+ * @param[out] pbBreak  Set to true if extra break was consumed.
  *
  * 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...
-*/
+ *
+ * When ascending indefinite-length arrays and maps, this will correctly
+ * consume the break for the level above. This is a problem for the
+ * implementation of QCBORDecode_GetArray() that must not return
+ * that break. @c pbBreak is set to true to indicate that one
+ * byte should be removed.
+ *
+ * Improvement: this could reduced further if indef is disabled
+ */
 static QCBORError
-QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd)
+QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
 {
    QCBORError uReturn;
 
    /* Loop ascending nesting levels as long as there is ascending to do */
    while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
+      if(pbBreak) {
+         *pbBreak = false;
+      }
 
       if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
          /* Nesting level is bstr-wrapped CBOR */
@@ -1854,6 +1866,9 @@
          /* It was a break in an indefinitelength map / array so
           * it is time to ascend one level.
           */
+         if(pbBreak) {
+            *pbBreak = true;
+         }
 
 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
       }
@@ -1893,6 +1908,7 @@
  * @brief Ascending & Descending out of nesting levels (decode layer 2).
  *
  * @param[in] pMe            Decoder context
+ * @param[out] pbBreak       Set to true if extra break was consumed.
  * @param[out] pDecodedItem  The decoded item that work is done on.
 
  * @retval QCBOR_ERR_UNSUPPORTED             Encountered unsupported/reserved
@@ -1933,6 +1949,7 @@
  */
 static QCBORError
 QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
+                                      bool               *pbBreak,
                                       QCBORItem          *pDecodedItem)
 {
    QCBORError uReturn;
@@ -2022,7 +2039,7 @@
        * to the top level.
        */
       QCBORError uAscendErr;
-      uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true);
+      uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
       if(uAscendErr != QCBOR_SUCCESS) {
          /* This error is probably a traversal error and it overrides
           * the non-traversal error.
@@ -2293,7 +2310,7 @@
 
    /* --- Get the exponent --- */
    QCBORItem exponentItem;
-   uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, &exponentItem);
+   uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
    if(uReturn != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -2541,7 +2558,7 @@
 {
    QCBORError uReturn;
 
-   uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pDecodedItem);
+   uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
    if(uReturn != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -3076,6 +3093,7 @@
 static QCBORError
 QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
                                 const QCBORItem    *pItemToConsume,
+                                bool               *pbBreak,
                                 uint8_t            *puNextNestLevel)
 {
    QCBORError uReturn;
@@ -3091,7 +3109,7 @@
        * arrays by using the nesting level
        */
       do {
-         uReturn = QCBORDecode_GetNext(pMe, &Item);
+         uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
          if(QCBORDecode_IsUnrecoverableError(uReturn) ||
             uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
             goto Done;
@@ -3103,7 +3121,7 @@
       uReturn = QCBOR_SUCCESS;
 
    } else {
-      /* pItemToConsume is not a map or array.  Just pass the nesting
+      /* pItemToConsume is not a map or array. Just pass the nesting
        * level through. */
       *puNextNestLevel = pItemToConsume->uNextNestLevel;
 
@@ -3124,12 +3142,35 @@
    QCBORDecode_VGetNext(pMe, pDecodedItem);
 
    if(pMe->uLastError == QCBOR_SUCCESS) {
-      pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem,
+      pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
          &pDecodedItem->uNextNestLevel);
    }
 }
 
 
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+uint32_t
+QCBORDecode_Tell(QCBORDecodeContext *pMe)
+{
+   size_t uCursorOffset;
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return UINT32_MAX;
+   }
+
+   uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+   if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
+      return UINT32_MAX;
+   } else {
+      /* Cast is safe because decoder input size is restricted. */
+      return (uint32_t)uCursorOffset;
+   }
+}
+
+
 /**
  * @brief Rewind cursor to start as if map or array were just entered.
  *
@@ -3190,14 +3231,25 @@
 
 
 
+typedef struct {
+   void               *pCBContext;
+   QCBORItemCallback   pfCallback;
+} MapSearchCallBack;
+
+typedef struct {
+   size_t   uStartOffset;
+   uint16_t uItemCount;
+} MapSearchInfo;
+
+
 /**
  * @brief Search a map for a set of items.
  *
  * @param[in]  pMe           The decode context to search.
  * @param[in,out] pItemArray The items to search for and the items found.
- * @param[out] puOffset      Byte offset of last item matched.
- * @param[in] pCBContext     Context for the not-found item call back.
- * @param[in] pfCallback     Function to call on items not matched in pItemArray.
+ * @param[out] pInfo         Several bits of meta-info returned by search.
+ * @param[in] pCallBack      Callback object or @c NULL.
+ *   TODO: fix params
  *
  * @retval QCBOR_ERR_NOT_ENTERED     Trying to search without entering a map.
  *
@@ -3225,9 +3277,8 @@
 static QCBORError
 QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
                               QCBORItem          *pItemArray,
-                              size_t             *puOffset,
-                              void               *pCBContext,
-                              QCBORItemCallback   pfCallback)
+                              MapSearchInfo      *pInfo,
+                              MapSearchCallBack  *pCallBack)
 {
    QCBORError uReturn;
    uint64_t   uFoundItemBitMap = 0;
@@ -3260,6 +3311,7 @@
    }
 
    QCBORDecodeNesting SaveNesting;
+   size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
    DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
 
    /* Reposition to search from the start of the map / array */
@@ -3283,6 +3335,9 @@
     that error code is returned.
     */
    const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
+   if(pInfo) {
+      pInfo->uItemCount = 0;
+   }
    uint8_t       uNextNestLevel;
    do {
       /* Remember offset of the item because sometimes it has to be returned */
@@ -3292,12 +3347,12 @@
       QCBORItem Item;
       QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
       if(QCBORDecode_IsUnrecoverableError(uResult)) {
-         /* Unrecoverable error so map can't even be decoded. */
+         /* The map/array can't be decoded when unrecoverable errors occur */
          uReturn = uResult;
          goto Done;
       }
       if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
-         // Unexpected end of map or array.
+         /* Unexpected end of map or array. */
          uReturn = uResult;
          goto Done;
       }
@@ -3312,7 +3367,9 @@
                goto Done;
             }
             if(uResult != QCBOR_SUCCESS) {
-               /* The label matches, but the data item is in error */
+               /* The label matches, but the data item is in error.
+                * It is OK to have recoverable errors on items that are not
+                * matched. */
                uReturn = uResult;
                goto Done;
             }
@@ -3325,22 +3382,22 @@
             /* Successful match. Return the item. */
             pItemArray[nIndex] = Item;
             uFoundItemBitMap |= 0x01ULL << nIndex;
-            if(puOffset) {
-               *puOffset = uOffset;
+            if(pInfo) {
+               pInfo->uStartOffset = uOffset;
             }
             bMatched = true;
          }
       }
 
 
-      if(!bMatched && pfCallback != NULL) {
+      if(!bMatched && pCallBack != NULL) {
          /*
           Call the callback on unmatched labels.
           (It is tempting to do duplicate detection here, but that would
           require dynamic memory allocation because the number of labels
           that might be encountered is unbounded.)
          */
-         uReturn = (*pfCallback)(pCBContext, &Item);
+         uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
          if(uReturn != QCBOR_SUCCESS) {
             goto Done;
          }
@@ -3353,10 +3410,15 @@
        items at the current nesting level are examined
        to match the labels.
        */
-      uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, &uNextNestLevel);
+      uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
       if(uReturn != QCBOR_SUCCESS) {
          goto Done;
       }
+
+      if(pInfo) {
+         pInfo->uItemCount++;
+      }
+
    } while (uNextNestLevel >= uMapNestLevel);
 
    uReturn = QCBOR_SUCCESS;
@@ -3376,6 +3438,7 @@
 
  Done:
    DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
+   UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
 
  Done2:
    /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
@@ -3409,7 +3472,7 @@
    OneItemSeach[0].uDataType   = uQcborType;
    OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE; // Indicates end of array
 
-   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
+   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
 
    *pItem = OneItemSeach[0];
 
@@ -3444,7 +3507,8 @@
    OneItemSeach[0].uDataType    = uQcborType;
    OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE; // Indicates end of array
 
-   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
+   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
+
    if(uReturn != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -3460,6 +3524,146 @@
 }
 
 
+
+/**
+ * @brief Semi-private. Get pointer, length and item for an array or map.
+ *
+ * @param[in] pMe            The decode context.
+ * @param[in] uType          CBOR major type, either array/map.
+ * @param[out] pItem         The item for the array/map.
+ * @param[out] pEncodedCBOR  Pointer and length of the encoded map or array.
+ *
+ * The next item to be decoded must be a map or array as specified by \c uType.
+ *
+ * \c pItem will be filled in with the label and tags of the array or map
+ * in addition to \c pEncodedCBOR giving the pointer and length of the
+ * encoded CBOR.
+ *
+ * When this is complete, the traversal cursor is at the end of the array or
+ * map that was retrieved.
+ */
+void
+QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
+                                  const uint8_t       uType,
+                                  QCBORItem          *pItem,
+                                  UsefulBufC         *pEncodedCBOR)
+{
+   QCBORError uErr;
+   uint8_t    uNestLevel;
+   size_t     uStartingCursor;
+   size_t     uStartOfReturned;
+   size_t     uEndOfReturned;
+   size_t     uTempSaveCursor;
+   bool       bInMap;
+   QCBORItem  LabelItem;
+   bool       EndedByBreak;
+
+   uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+   bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
+
+   /* Could call GetNext here, but don't need to because this
+    * is only interested in arrays and maps. */
+   uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
+   if(uErr != QCBOR_SUCCESS) {
+      pMe->uLastError = (uint8_t)uErr;
+      return;
+   }
+
+   if(pItem->uDataType != uType) {
+      pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+      return;
+   }
+
+   if(bInMap) {
+      /* If the item is in a map, the start of the array/map
+       * itself, not the label, must be found. Do this by
+       * rewinding to the starting position and fetching
+       * just the label data item. QCBORDecode_Private_GetNextTagNumber()
+       * doesn't do any of the array/map item counting or nesting
+       * level tracking. Used here it will just fetech the label
+       * data item.
+       *
+       * Have to save the cursor and put it back to the position
+       * after the full item once the label as been fetched by
+       * itself.
+       */
+      uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+      UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
+
+      /* Item has been fetched once so safe to ignore error */
+      (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
+
+      uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
+      UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
+   } else {
+      uStartOfReturned = uStartingCursor;
+   }
+
+   /* Consume the entire array/map to find the end */
+   uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
+   if(uErr != QCBOR_SUCCESS) {
+      pMe->uLastError = (uint8_t)uErr;
+      goto Done;
+   }
+
+   /* Fill in returned values */
+   uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
+   if(EndedByBreak) {
+      /* When ascending nesting levels, a break for the level above
+       * was consumed. That break is not a part of what is consumed here. */
+      uEndOfReturned--;
+   }
+   pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
+   pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
+
+Done:
+   return;
+}
+
+
+/**
+ * @brief Semi-private. Get pointer, length and item count of an array or map.
+ *
+ * @param[in] pMe            The decode context.
+ * @param[in] pTarget        The label and type of the array or map to retrieve.
+ * @param[out] pItem         The item for the array/map.
+ * @param[out] pEncodedCBOR  Pointer and length of the encoded map or array.
+ *
+ * The next item to be decoded must be a map or array as specified by \c uType.
+ *
+ * When this is complete, the traversal cursor is unchanged.
+ */void
+QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
+                                           QCBORItem          *pTarget,
+                                           QCBORItem          *pItem,
+                                           UsefulBufC         *pEncodedCBOR)
+{
+   MapSearchInfo      Info;
+   QCBORDecodeNesting SaveNesting;
+   size_t             uSaveCursor;
+
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   /* Save the whole position of things so they can be restored.
+    * so the cursor position is unchanged by this operation, like
+    * all the other GetXxxxInMap() operations. */
+   DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
+   uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+   DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+   UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+   QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
+
+   UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
+   DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
+}
+
+
+
+
 /**
  * @brief Is a QCBOR_TYPE in the type list?
  *
@@ -3670,7 +3874,7 @@
 void
 QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
 {
-   QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL, NULL);
+   QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
    pMe->uLastError = (uint8_t)uErr;
 }
 
@@ -3683,7 +3887,12 @@
                                       void               *pCallbackCtx,
                                       QCBORItemCallback   pfCB)
 {
-   QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, pCallbackCtx, pfCB);
+   MapSearchCallBack CallBack;
+   CallBack.pCBContext = pCallbackCtx;
+   CallBack.pfCallback = pfCB;
+
+   QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
+
    pMe->uLastError = (uint8_t)uErr;
 }
 
@@ -3711,8 +3920,8 @@
       return;
    }
 
-   size_t uOffset;
-   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &uOffset, NULL, NULL);
+   MapSearchInfo Info;
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return;
    }
@@ -3742,7 +3951,7 @@
     * to be used to get one item and MapSearch() has already found it
     * confirming it exists.
     */
-   UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
+   UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
 
    DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
 
@@ -3924,7 +4133,7 @@
     * level is reached.  It may do nothing, or ascend all the way to
     * the top level.
     */
-   uErr = QCBORDecode_Private_NestLevelAscender(pMe, false);
+   uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
    if(uErr != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -3977,7 +4186,7 @@
    if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
       QCBORItem Dummy;
       Dummy.uLabelType = QCBOR_TYPE_NONE;
-      uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL, NULL);
+      uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
       if(uErr != QCBOR_SUCCESS) {
          goto Done;
       }
@@ -4104,6 +4313,11 @@
       return;
    }
 
+   if(Item.uDataAlloc) {
+      pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
+      return;
+   }
+
    pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
                                                                   &Item,
                                                                    uTagRequirement,
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index e4a7bf6..a614eb1 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -484,7 +484,7 @@
    /* This expression integer-promotes to type int. The code above in
     * function guarantees that nAdditionalInfo will never be larger
     * than 0x1f. The caller may pass in a too-large uMajor type. The
-    * conversion to unint8_t will cause an integer wrap around and
+    * conversion to uint8_t will cause an integer wrap around and
     * incorrect CBOR will be generated, but no security issue will
     * occur.
     */
@@ -1594,15 +1594,13 @@
 QCBORError
 QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR)
 {
-   QCBORError uReturn = QCBOREncode_GetErrorState(pMe);
-
-   if(uReturn != QCBOR_SUCCESS) {
+   if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) {
       goto Done;
    }
 
 #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
    if(Nesting_IsInNest(&(pMe->nesting))) {
-      uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
+      pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
       goto Done;
    }
 #endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
@@ -1610,7 +1608,7 @@
    *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
 
 Done:
-   return uReturn;
+   return pMe->uError;
 }
 
 
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index 13e87e3..0524b4d 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -673,6 +673,22 @@
       return "Incorrect pointer offset for start";
    }
 
+   if(UsefulBuf_OffsetToPointer(Boo, 0) != &pB[0]) {
+      return "Wrong OffsetToPointer";
+   }
+
+   if(UsefulBuf_OffsetToPointer(Boo, 3) != NULL) {
+      return "Didn't validate offset correctly";
+   }
+
+   if(UsefulBuf_OffsetToPointer(Boo, 2) != &pB[2]) {
+      return "Wrong OffsetToPointer 2";
+   }
+
+   if(UsefulBuf_OffsetToPointer(NULLUsefulBufC, 2) != NULL) {
+      return "Failed OffsetToPtr on NULLUsefulBufC";
+   }
+
    return NULL;
 }
 
@@ -800,6 +816,20 @@
       return "PointerToOffset not working";
    }
 
+
+   const uint8_t pB[] = {0x01, 0x02, 0x03};
+   UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
+
+   UsefulInputBuf_Init(&UIB, Boo);
+
+   if(UsefulInputBuf_OffsetToPointer(&UIB, 0) != &pB[0]) {
+      return "OffsetToPointer fail";
+   }
+
+   if(UsefulInputBuf_OffsetToPointer(&UIB, SIZE_MAX) != NULL) {
+      return "OffsetToPointer SIZE_MAX fail";
+   }
+
    return NULL;
 }
 
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 833b5b8..5e43823 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -5940,9 +5940,6 @@
                00
 };
 
-const unsigned char spBadConsumeInput3[] = {
-   0x81, 0xc0, 0x81, 0x00
-};
 
 const unsigned char spBadConsumeInput4[] = {
    0x81, 0x9f, 0x00, 0xff
@@ -5991,6 +5988,20 @@
 {
    QCBORDecodeContext DCtx;
    QCBORItem          Item1;
+   int64_t            nInt;
+   QCBORError         uErr;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0);
+   QCBORDecode_EnterMap(&DCtx, NULL);
+   QCBORDecode_GetInt64InMapN (&DCtx, 3, &nInt);
+   uErr = QCBORDecode_GetNext(&DCtx, &Item1);
+   if(uErr != QCBOR_SUCCESS) {
+      return 701;
+   }
+   if(Item1.uDataType != QCBOR_TYPE_INT64) {
+      return 700;
+   }
+
 
    int i;
    for(i = 0; i < 13; i++) {
@@ -6402,12 +6413,6 @@
    if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
       return 2700;
    }
-
-   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput3), 0);
-   QCBORDecode_VGetNextConsume(&DCtx, &Item1);
-   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
-      return 2800;
-   }
 #endif
 
 
@@ -8632,16 +8637,14 @@
 
    QCBORDecode_EnterArray(&DCtx, NULL);
    QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL);
-   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INPUT_TOO_LARGE) {
-      /* TODO: This is what happens when trying to enter
-       * indefinite-length byte string wrapped CBOR.  Tolerate for
-       * now. Eventually it needs to be fixed so this works, but that
-       * is not simple.
-       */
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) {
       return 7300;
    }
 
    /*
+    Improvement: Fix QCBORDecode_EnterBstrWrapped() so it can work on
+    allocated strings. This is a fairly big job because of all the
+    UsefulBuf internal book keeping that needs tweaking.
    QCBORDecode_GetUInt64(&DCtx, &i);
    if(i != 42) {
       return 7110;
@@ -8650,7 +8653,8 @@
    QCBORDecode_GetUInt64(&DCtx, &i);
    if(i != 42) {
       return 7220;
-   }*/
+   }
+    */
 
 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
 
@@ -9039,6 +9043,333 @@
 #endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
 
 
+
+static const uint8_t spExpectedArray2s[] = {
+   0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+   0x31, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+   0x32};
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+static const uint8_t spExpectedArray2sIndef[] = {
+   0x9f, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+   0x31, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+   0x32, 0xff};
+#endif
+
+static const uint8_t spExpectedMap4[] = {
+   0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20,
+   0x31, 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62,
+   0x79, 0x74, 0x65, 0x73, 0x20, 0x32, 0x44, 0x79,
+   0x79, 0x79, 0x79, 0x6b, 0x61, 0x6e, 0x6f, 0x74,
+   0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x18,
+   0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32,
+   0x78, 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20,
+   0x64, 0x61, 0x6d, 0x6e, 0x20, 0x6c, 0x69, 0x65,
+   0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74,
+   0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73};
+
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+
+static const uint8_t spExpectedMap4Indef[] = {
+   0xbf, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20,
+   0x31, 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62,
+   0x79, 0x74, 0x65, 0x73, 0x20, 0x32, 0x44, 0x79,
+   0x79, 0x79, 0x79, 0x6b, 0x61, 0x6e, 0x6f, 0x74,
+   0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x18,
+   0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32,
+   0x78, 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20,
+   0x64, 0x61, 0x6d, 0x6e, 0x20, 0x6c, 0x69, 0x65,
+   0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74,
+   0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73,
+   0xff};
+
+/*
+ * [[[[[0, []]]]], 0]
+ */
+static const uint8_t spDefAndIndef[] = {
+   0x82,
+      0x9f, 0x9f, 0x9f, 0x82, 0x00, 0x9f, 0xff, 0xff, 0xff, 0xff, 0x00
+};
+#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+
+#ifndef QCBOR_DISABLE_TAGS
+/* An exp / mant tag in two nested arrays */
+static const uint8_t spExpMant[] = {0x81, 0x81, 0xC4, 0x82, 0x20, 0x03};
+#endif /* !QCBOR_DISABLE_TAGS */
+
+
+int32_t GetMapAndArrayTest(void)
+{
+   QCBORDecodeContext DCtx;
+   size_t             uPosition ;
+   QCBORItem          Item;
+   UsefulBufC         ReturnedEncodedCBOR;
+
+
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+                    0);
+
+   QCBORDecode_EnterMap(&DCtx, NULL);
+   QCBORDecode_VGetNextConsume(&DCtx, &Item);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 1;
+   }
+   if(Item.val.uCount != 2) {
+      return 2;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2s))) {
+      return 3;
+   }
+
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) {
+      return 4;
+   }
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+
+
+   QCBORDecode_GetMap(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 10;
+   }
+   if(Item.val.uCount != 4) {
+      return 11;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4))) {
+      return 12;
+   }
+   uPosition = QCBORDecode_Tell(&DCtx);
+   QCBORDecode_GetArrayFromMapSZ(&DCtx,
+                                 "an array of two strings",
+                                 &Item,
+                                 &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 20;
+   }
+   if(Item.val.uCount != 2) {
+      return 21;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2s))) {
+      return 22;
+   }
+   if(uPosition != QCBORDecode_Tell(&DCtx)) {
+      return 23;
+   }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+   QCBORDecode_GetMapFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 30;
+   }
+   if(Item.val.uCount != 4) {
+      return 31;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4))) {
+      return 32;
+   }
+   if(uPosition != QCBORDecode_Tell(&DCtx)) {
+      return 33;
+   }
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+   QCBORDecode_GetArrayFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+      return 40;
+   }
+   if(UINT32_MAX != QCBORDecode_Tell(&DCtx)) {
+      return 41;
+   }
+   QCBORDecode_GetAndResetError(&DCtx);
+   if(uPosition != QCBORDecode_Tell(&DCtx)) {
+      return 42;
+   }
+
+
+#ifndef QCBOR_DISABLE_TAGS
+   UsefulBufC ExpMant = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpMant);
+   QCBORDecode_Init(&DCtx, ExpMant, 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 200;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return 201;
+   }
+   if(!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION)) {
+      return 202;
+   }
+   if(Item.val.uCount != 2) {
+      return 201;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(ExpMant, 2))) {
+      return 205;
+   }
+#endif /* !QCBOR_DISABLE_TAGS */
+
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+
+   UsefulBufC DefAndIndef = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDefAndIndef);
+   QCBORDecode_Init(&DCtx, DefAndIndef, 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 50;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 11), 1))) {
+      return 51;
+   }
+
+   QCBORDecode_Init(&DCtx, DefAndIndef, 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 52;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 10), 2))) {
+      return 53;
+   }
+
+   QCBORDecode_Init(&DCtx, DefAndIndef, 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 54;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 9), 3))) {
+      return 55;
+   }
+   QCBORDecode_Init(&DCtx, DefAndIndef, 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 56;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 8), 4))) {
+      return 57;
+   }
+
+   QCBORDecode_Init(&DCtx, DefAndIndef, 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_VGetNextConsume(&DCtx, &Item);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 58;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 8), 6))) {
+      return 59;
+   }
+
+
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded),
+                    0);
+
+   QCBORDecode_EnterMap(&DCtx, NULL);
+   QCBORDecode_VGetNextConsume(&DCtx, &Item);
+   QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 60;
+   }
+   if(Item.val.uCount != UINT16_MAX) {
+      return 61;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2sIndef))) {
+      return 62;
+   }
+
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) {
+      return 63;
+   }
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+
+
+   QCBORDecode_GetMap(&DCtx, &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 70;
+   }
+   if(Item.val.uCount != UINT16_MAX) {
+      return 71;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4Indef))) {
+      return 72;
+   }
+
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+   QCBORDecode_GetArrayFromMapSZ(&DCtx,
+                                 "an array of two strings",
+                                 &Item,
+                                 &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 80;
+   }
+   if(Item.val.uCount != UINT16_MAX) {
+      return 81;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2sIndef))) {
+      return 82;
+   }
+   if(uPosition != QCBORDecode_Tell(&DCtx)) {
+      return 83;
+   }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+   QCBORDecode_GetMapFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 90;
+   }
+   if(Item.val.uCount != UINT16_MAX) {
+      return 91;
+   }
+   if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4Indef))) {
+      return 92;
+   }
+   if(uPosition != QCBORDecode_Tell(&DCtx)) {
+      return 93;
+   }
+
+   uPosition = QCBORDecode_Tell(&DCtx);
+   QCBORDecode_GetArrayFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+      return 100;
+   }
+   if(UINT32_MAX != QCBORDecode_Tell(&DCtx)) {
+      return 101;
+   }
+   QCBORDecode_GetAndResetError(&DCtx);
+   if(uPosition != QCBORDecode_Tell(&DCtx)) {
+      return 102;
+   }
+#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   return 0;
+}
+
+   
 int32_t
 ErrorHandlingTests(void)
 {
@@ -9119,3 +9450,312 @@
 
    return 0;
 }
+
+
+int32_t TellTests(void)
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem          Item;
+   uint32_t           uPosition;
+   int                nIndex;
+   int64_t            nDecodedInt;
+
+   static const uint32_t aPos[] =
+       {0, 1, 17, 42, 50, 58, 72, 85, 98, 112, UINT32_MAX};
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+                    0);
+   for(nIndex = 0; ; nIndex++) {
+      uPosition = QCBORDecode_Tell(&DCtx);
+      if(uPosition != aPos[nIndex]) {
+         return nIndex;
+      }
+
+      if(uPosition == UINT32_MAX) {
+         break;
+      }
+
+      QCBORDecode_VGetNext(&DCtx, &Item);
+   }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   static const uint32_t aPosIndef[] =
+       {0, 1, 17, 42, 50, 59, 73, 86, 99, 113, UINT32_MAX};
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded),
+                    0);
+
+   for(nIndex = 0; ; nIndex++) {
+      uPosition = QCBORDecode_Tell(&DCtx);
+      if(uPosition != aPosIndef[nIndex]) {
+         return nIndex + 100;
+      }
+
+      if(uPosition == UINT32_MAX) {
+         break;
+      }
+
+      QCBORDecode_VGetNext(&DCtx, &Item);
+   }
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   /* Next, some tests with entered maps and arrays */
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+                    0);
+   QCBORDecode_EnterMap(&DCtx, &Item);
+   if(QCBORDecode_Tell(&DCtx) != 1) {
+      return 1001;
+   }
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt);
+   if(QCBORDecode_Tell(&DCtx) != 1) {
+      return 1002;
+   }
+   QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map");
+   if(QCBORDecode_Tell(&DCtx) != 72) {
+      return 1003;
+   }
+
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt);
+   if(nDecodedInt != 98) {
+      return 1004;
+   }
+   /* Getting non-aggregate types doesn't affect cursor position. */
+   if(QCBORDecode_Tell(&DCtx) != 72) {
+      return 1005;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_Tell(&DCtx) != 85) {
+      return 1006;
+   }
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt);
+   if(nDecodedInt != 98) {
+      return 1007;
+   }
+   /* Getting non-aggregate types doesn't affect cursor position. */
+   if(QCBORDecode_Tell(&DCtx) != 85) {
+      return 1008;
+   }
+
+   QCBORDecode_ExitMap(&DCtx);
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 1009;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
+      return 1010;
+   }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   /* Next, some tests with entered maps and arrays */
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded),
+                    0);
+   QCBORDecode_EnterMap(&DCtx, &Item);
+   if(QCBORDecode_Tell(&DCtx) != 1) {
+      return 2000;
+   }
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt);
+   if(QCBORDecode_Tell(&DCtx) != 1) {
+      return 2001;
+   }
+   QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map");
+   if(QCBORDecode_Tell(&DCtx) != 73) {
+      return 2002;
+   }
+
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt);
+   if(nDecodedInt != 98) {
+      return 2003;
+   }
+   /* Getting non-aggregate types doesn't affect cursor position. */
+   if(QCBORDecode_Tell(&DCtx) != 73) {
+      return 2004;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_Tell(&DCtx) != 86) {
+      return 2005;
+   }
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt);
+   if(nDecodedInt != 98) {
+      return 2006;
+   }
+   /* Getting non-aggregate types doesn't affect cursor position. */
+   if(QCBORDecode_Tell(&DCtx) != 86) {
+      return 2007;
+   }
+
+   QCBORDecode_ExitMap(&DCtx);
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 2008;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
+      return 2010;
+   }
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+
+
+   /* Error state test */
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+                    0);
+   /* Cause an error */
+   QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt);
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 3000;
+   }
+
+   /* Empties tests */
+   const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0);
+   if(QCBORDecode_Tell(&DCtx) != 0) {
+      return 4000;
+   }
+   QCBORDecode_EnterMap(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 4001;
+   }
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 4002;
+   }
+   QCBORDecode_ExitMap(&DCtx);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 4001;
+   }
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 4002;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
+      return 4010;
+   }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   const uint8_t pMinimalIndefCBOR[] = {0xbf, 0xff}; // One empty map
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalIndefCBOR),0);
+   if(QCBORDecode_Tell(&DCtx) != 0) {
+      return 4100;
+   }
+   QCBORDecode_EnterMap(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 4101;
+   }
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 4102;
+   }
+   QCBORDecode_ExitMap(&DCtx);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 4101;
+   }
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 4102;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
+      return 4110;
+   }
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   /* Test on a CBOR sequence */
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput),0);
+   if(QCBORDecode_Tell(&DCtx) != 0) {
+      return 5000;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 5001;
+   }
+   if(QCBORDecode_Tell(&DCtx) != 11) {
+      return 5002;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 5003;
+   }
+   if(QCBORDecode_Tell(&DCtx) != 12) {
+      return 5004;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 5005;
+   }
+   if(QCBORDecode_Tell(&DCtx) != 17) {
+      return 5006;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
+      return 5007;
+   }
+   if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) {
+      return 5008;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) {
+      return 5010;
+   }
+
+
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+                    0);
+   QCBORDecode_EnterMap(&DCtx, &Item);
+   QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings");
+   if(QCBORDecode_Tell(&DCtx) != 42) {
+      return 6001;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_Tell(&DCtx) != 50) {
+      return 6002;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   if(QCBORDecode_Tell(&DCtx) != 58) {
+      return 6008;
+   }
+   QCBORDecode_VGetNext(&DCtx, &Item);
+   (void)QCBORDecode_GetAndResetError(&DCtx);
+   if(QCBORDecode_Tell(&DCtx) != 58) {
+      return 6003;
+   }
+   QCBORDecode_ExitArray(&DCtx);
+   if(QCBORDecode_Tell(&DCtx) != 58) {
+      return 6004;
+   }
+
+   static const uint32_t aEmptiesPos[] =
+       {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, UINT32_MAX};
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties),
+                    0);
+   for(nIndex = 0; ; nIndex++) {
+      uPosition = QCBORDecode_Tell(&DCtx);
+      if(uPosition != aEmptiesPos[nIndex]) {
+         return nIndex + 200;
+      }
+
+      if(uPosition == UINT32_MAX) {
+         break;
+      }
+
+      QCBORDecode_VGetNext(&DCtx, &Item);
+   }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   static const uint32_t aIndefEmptiesPos[] =
+       {0, 1, 2, 4, 5, 7, 8, 10, 12, 13, 16, 19, UINT32_MAX};
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmptiesIndef),
+                    0);
+   for(nIndex = 0; ; nIndex++) {
+      uPosition = QCBORDecode_Tell(&DCtx);
+      if(uPosition != aIndefEmptiesPos[nIndex]) {
+         return nIndex + 300;
+      }
+
+      if(uPosition == UINT32_MAX) {
+         break;
+      }
+
+      QCBORDecode_VGetNext(&DCtx, &Item);
+   }
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+
+   return 0;
+}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index bd0996b..e3fe1b6 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -324,4 +324,12 @@
 int32_t ErrorHandlingTests(void);
 
 
+/*
+ * Test QCBORDecode_GetArray and QCBORDecode_GetMap
+ */
+int32_t GetMapAndArrayTest(void);
+
+int32_t TellTests(void);
+
+
 #endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 118b232..6cc9d08 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -2528,6 +2528,8 @@
 {
    QCBOREncodeContext EC;
    QCBORError         uErr;
+   UsefulBufC         EncodedResult;
+   MakeUsefulBufOnStack(SmallBuffer, 4);
 
 
    // ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------
@@ -2723,6 +2725,31 @@
    }
 #endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
 
+   /* Test that still-open error sticks */
+   QCBOREncode_Init(&EC, Large);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_Finish(&EC, &EncodedResult);
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+      return -120;
+   }
+#else /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+   if(QCBOREncode_GetErrorState(&EC) != QCBOR_SUCCESS) {
+      return -122;
+   }
+#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+   /* Test that too-small error is sticky */
+   QCBOREncode_Init(&EC, SmallBuffer);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddInt64(&EC, INT64_MAX);
+   QCBOREncode_AddInt64(&EC, INT64_MAX);
+   QCBOREncode_AddInt64(&EC, INT64_MAX);
+   QCBOREncode_CloseArray(&EC);
+   QCBOREncode_Finish(&EC, &EncodedResult);
+   if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_BUFFER_TOO_SMALL) {
+      return -130;
+   }
 
    return 0;
 }
diff --git a/test/run_tests.c b/test/run_tests.c
index d5948f2..a94aa47 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -69,6 +69,8 @@
 static test_entry s_tests[] = {
    TEST_ENTRY(ErrorHandlingTests),
    TEST_ENTRY(OpenCloseBytesTest),
+   TEST_ENTRY(GetMapAndArrayTest),
+   TEST_ENTRY(TellTests),
    TEST_ENTRY(EnterBstrTest),
    TEST_ENTRY(IntegerConvertTest),
    TEST_ENTRY(EnterMapTest),
diff --git a/test/run_tests.h b/test/run_tests.h
index ce44673..6790710 100644
--- a/test/run_tests.h
+++ b/test/run_tests.h
@@ -60,7 +60,7 @@
 
 
 /**
- @brief Print sizes of encoder / decoder contexts.
+ @brief Print sizes of encoder-decoder contexts.
 
  @param[in] pfOutput     Function that is called to output text strings.
  @param[in] pOutCtx      Context pointer passed to output function.