New Rewind method for entered maps...; bug fix for entering tagged wrapping byte strings

The new QCBORDecode_Rewind method allows the pre-order traversal cursor to be reset to the beginning of an entered array, map or byte string. If nothing was entered, then the reset is to the initial state, the beginning of the input encoded CBOR.

This also fixes a bug that prevented tagged wrapping byte strings from being entered.

This also adds a method to UsefulBuf and UsefulInBuf to convert a pointer to an offset.



* first version of rewind

* Make rewind work when not bounded and reset error state

* Rewind working for maps and arrays, but not byte strings

* rewind almost working for byte strings

* src/qcbor_decode.c

* minor tidying

* rewinding wrapped byte strings works, but needs more tests

* Full testing of UsefulBuf pointer to offset functions

* tidy up rewind; tests all passing

* fix bug entering tagged byte-string wrapped CBOR; entering indefinite-length byte-string wrapped is still broken

* one more test; give up on entering indef length wrapping strings

* spelling fix

* ifdefs for disabling tests

* refactor rewind

* more nits

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index 783af79..5b3ef68 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -164,7 +164,7 @@
 		E743D13124DE05CC0017899F /* QCBOR_Disable_Preferred_Float */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Preferred_Float; sourceTree = BUILT_PRODUCTS_DIR; };
 		E743D132251014E60017899F /* Tagging.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = Tagging.md; path = doc/Tagging.md; sourceTree = "<group>"; };
 		E743D13325115A270017899F /* TRY SPIFFY DECODE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "TRY SPIFFY DECODE.md"; sourceTree = "<group>"; };
-		E74BF411245D6713002CE8E8 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/qcbor/UsefulBuf.h; sourceTree = "<group>"; };
+		E74BF411245D6713002CE8E8 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/qcbor/UsefulBuf.h; sourceTree = "<group>"; tabWidth = 3; };
 		E772022723B52C02006E966E /* QCBOR_Disable_Exp_Mantissa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Exp_Mantissa; sourceTree = BUILT_PRODUCTS_DIR; };
 		E776E07C214ADF7F00E67947 /* QCBOR */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR; sourceTree = BUILT_PRODUCTS_DIR; };
 		E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; tabWidth = 3; };
diff --git a/README.md b/README.md
index 1f689c8..5df01a7 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # QCBOR
 
-QCBOR is an implementation of nearly everything in
+QCBOR is a powerful, commercial quality implementation of nearly everything in
 [RFC8949](https://tools.ietf.org/html/rfc8949). This RFC defines the
 Concise Binary Object Representation (CBOR). Since RFC 8949 is fully
 compatible with RFC 7049, this is also a near-complete implementation
@@ -235,7 +235,7 @@
     |               | smallest | largest |  
     |---------------|----------|---------|
     | encode only   |      850 |    2100 |
-    | decode only   |     2000 |   13400 |
+    | decode only   |     2000 |   13300 |
     | combined      |     2850 |   15500 |
     
  From the table above, one can see that the amount of code pulled in
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index 6fe33a1..6c057fe 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -1,6 +1,6 @@
 /*============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -41,6 +41,7 @@
 
  when         who             what, where, why
  --------     ----            --------------------------------------------------
+ 2/17/2021    llundblade      Add method to go from a pointer to an offset.
  1/25/2020    llundblade      Add some casts so static anlyzers don't complain.
  5/21/2019    llundblade      #define configs for efficient endianness handling.
  5/16/2019    llundblade      Add UsefulOutBuf_IsBufferNULL().
@@ -589,6 +590,17 @@
 size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
 
 
+/**
+ @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.
+*/
+static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p);
+
+
 #if 1 // NOT_DEPRECATED
 /** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
 #define SZLiteralToUsefulBufC(szString) \
@@ -1332,6 +1344,17 @@
 
 
 /**
+ @brief Convert a pointer to an offset with bounds checking.
+
+ @param[in] pUInBuf  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.
+*/
+static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p);
+
+
+/**
  @brief Get pointer to bytes out of the input buffer.
 
  @param[in] pUInBuf  Pointer to the UsefulInputBuf.
@@ -1626,6 +1649,28 @@
 }
 
 
+static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p)
+{
+   if(UB.ptr == NULL) {
+      return SIZE_MAX;
+   }
+
+   if(p < UB.ptr) {
+      /* given pointer is before start of buffer */
+      return SIZE_MAX;
+   }
+
+   // Cast to size_t (from ptrdiff_t) is OK because of check above
+   const size_t uOffset = (size_t)((uint8_t *)p - (uint8_t *)UB.ptr);
+
+    if(uOffset >= UB.len) {
+      /* given pointer is off the end of the buffer */
+      return SIZE_MAX;
+   }
+
+   return uOffset;
+}
+
 
 static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
 {
@@ -1993,6 +2038,12 @@
 }
 
 
+static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p)
+{
+   return UsefulBuf_PointerToOffset(pUInBuf->UB, p);
+}
+
+
 static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
 {
    const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 960e810..95f41a0 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -881,7 +881,7 @@
 
  This is useful for looking ahead to determine the type
  of a data item to know which type-specific spiffy decode
- function to call. 
+ function to call.
  */
 QCBORError
 QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index 5ddc16f..abd6ba2 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -152,11 +152,11 @@
        QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY
        for 2).
 
-       Item tracking is either be for definite or indefinite length
+       Item 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
+       unconsumed are tracked. For indefinite-length, uTotalCount is
        QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and there
-       is no per-item count of members. For indefinite length maps and
+       is no per-item count of members. For indefinite-length maps and
        arrays, uCountCursor is UINT16_MAX if not consumed and zero if
        it is consumed in the pre-order traversal. Additionally, if
        entered in bounded mode, uCountCursor is
@@ -185,9 +185,12 @@
             uint32_t uStartOffset;
          } ma; /* for maps and arrays */
          struct {
-            uint32_t uEndOfBstr;
-            uint32_t uPreviousEndOffset;
-         } bs; /* for top-level sequence and bstr wrapped CBOR */
+            /* The end of the input before the bstr was entered so that
+             * it can be restored when the bstr is exited. */
+            uint32_t uSavedEndOffset;
+            /* The beginning of the bstr so that it can be rewound. */
+            uint32_t uBstrStartOffset;
+         } bs; /* for top-level sequence and bstr-wrapped CBOR */
       } u;
    } pLevels[QCBOR_MAX_ARRAY_NESTING1+1],
     *pCurrent,
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index 0ea6a71..d1a391d 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -151,7 +151,7 @@
  example, to decode an epoch date tag the content must be an integer
  or floating-point value.
 
- If the parameter indicates it should not be a tag 
+ If the parameter indicates it should not be a tag
  (@ref  QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then
   @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the
  encoded CBOR is not what is expected.  In the example of an epoch
@@ -736,6 +736,25 @@
 
 
 /**
+ @brief Reset traversal cursor to start of map, array, byte-string
+ wrapped CBOR or start of input.
+
+ @param[in] pCtx  The decode context.
+
+ If an array, map or wrapping byte string has been entered this sets
+ the traversal cursor to its beginning. If several arrays, maps or
+ byte strings have been entered, this sets the traversal cursor to the
+ beginning of the one most recently entered.
+
+ If no map or array has been entered, this resets the traversal cursor
+ to the beginning of the input CBOR.
+
+ This also resets the error state.
+ */
+void QCBORDecode_Rewind(QCBORDecodeContext *pCtx);
+
+
+/**
  @brief Get an item in map by label and type.
 
  @param[in] pCtx   The decode context.
@@ -743,8 +762,8 @@
  @param[in] uQcborType  The QCBOR type. One of @c QCBOR_TYPE_XXX.
  @param[out] pItem  The returned item.
 
- A map must have been entered to use this. If not @ref QCBOR_ERR_MAP_NOT_ENTERED is
- set.
+ A map must have been entered to use this. If not @ref
+ QCBOR_ERR_MAP_NOT_ENTERED is set.
 
  The map is searched for an item of the requested label and type.
  @ref QCBOR_TYPE_ANY can be given to search for the label without
@@ -1512,6 +1531,9 @@
  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.
+
  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
  useful, particularly in the case of verifying signed data like the
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index ebcbc97..5fdbcfa 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -422,10 +422,10 @@
 
 static inline QCBORError
 DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
-                                     uint32_t uEndOffset,
-                                     uint32_t uEndOfBstr)
+                                     uint32_t            uEndOffset,
+                                     uint32_t            uStartOffset)
 {
-   QCBORError uError = QCBOR_SUCCESS;
+   QCBORError uError;
 
    uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
    if(uError != QCBOR_SUCCESS) {
@@ -433,8 +433,8 @@
    }
 
    /* Fill in the new byte string level */
-   pNesting->pCurrent->u.bs.uPreviousEndOffset = uEndOffset;
-   pNesting->pCurrent->u.bs.uEndOfBstr         = uEndOfBstr;
+   pNesting->pCurrent->u.bs.uSavedEndOffset  = uEndOffset;
+   pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
 
    /* Bstr wrapped levels are always bounded */
    pNesting->pCurrentBounded = pNesting->pCurrent;
@@ -454,7 +454,9 @@
 static inline void
 DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
 {
-   pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+   if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+      pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+   }
 }
 
 
@@ -472,8 +474,6 @@
                                   QCBORDecodeNesting *pSave)
 {
    *pSave = *pNesting;
-   pNesting->pCurrent = pNesting->pCurrentBounded;
-   DecodeNesting_ResetMapOrArrayCount(pNesting);
 }
 
 
@@ -486,16 +486,9 @@
 
 
 static inline uint32_t
-DecodeNesting_GetEndOfBstr(const QCBORDecodeNesting *pMe)
-{
-   return pMe->pCurrentBounded->u.bs.uEndOfBstr;
-}
-
-
-static inline uint32_t
 DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
 {
-   return pMe->pCurrentBounded->u.bs.uPreviousEndOffset;
+   return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
 }
 
 
@@ -2702,6 +2695,56 @@
     return uReturn;
 }
 
+/* Call only on maps and arrays. Rewinds the cursor
+ * to the start as if it was just entered.
+ */
+static void RewindMapOrArray(QCBORDecodeContext *pMe)
+{
+   /* Reset nesting tracking to the deepest bounded level */
+   DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+   DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
+   /* Reposition traversal cursor to the start of the map/array */
+   UsefulInputBuf_Seek(&(pMe->InBuf),
+                       DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
+}
+
+
+/*
+ Public function, see header qcbor/qcbor_decode.h file
+ */
+void QCBORDecode_Rewind(QCBORDecodeContext *pMe)
+{
+   if(pMe->nesting.pCurrentBounded != NULL) {
+      /* In a bounded map, array or bstr-wrapped CBOR */
+
+      if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
+         /* In bstr-wrapped CBOR. */
+
+         /* Reposition traversal cursor to start of wrapping byte string */
+         UsefulInputBuf_Seek(&(pMe->InBuf),
+                             pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
+         DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+      } else {
+         /* In a map or array */
+         RewindMapOrArray(pMe);
+      }
+
+   } else {
+      /* Not in anything bounded */
+
+      /* Reposition traversal cursor to the start of input CBOR */
+      UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
+
+      /* Reset nesting tracking to beginning of input. */
+      DecodeNesting_Init(&(pMe->nesting));
+   }
+
+   pMe->uLastError = QCBOR_SUCCESS;
+}
+
 
 /* Return true if the labels in Item1 and Item2 are the same.
    Works only for integer and string labels. Returns false
@@ -2823,8 +2866,7 @@
    DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
 
    /* Reposition to search from the start of the map / array */
-   UsefulInputBuf_Seek(&(pMe->InBuf),
-                       DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
+   RewindMapOrArray(pMe);
 
    /*
     Loop over all the items in the map or array. Each item
@@ -3194,7 +3236,9 @@
       return;
    }
 
-   /*
+
+   /* The map or array was found. Now enter it.
+    *
     * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
     * next item for the pre-order traversal cursor to be the map/array
     * found by MapSearch(). The next few lines of code force the
@@ -3435,16 +3479,11 @@
    }
 
    if(pMe->uLastError != QCBOR_SUCCESS) {
-      // Already in error state; do nothing.
+      /* Already in error state; do nothing. */
       return pMe->uLastError;
    }
 
-   QCBORError uError = QCBOR_SUCCESS;
-
-   if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
-      uError = QCBOR_ERR_UNEXPECTED_TYPE;
-      goto Done;;
-   }
+   QCBORError uError;
 
    const TagSpecification TagSpec =
       {
@@ -3459,9 +3498,10 @@
    }
 
    if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
-      // Reverse the decrement done by GetNext() for the bstr so the
-      // increment in QCBORDecode_NestLevelAscender() called by ExitBoundedLevel()
-      // will work right.
+      /* Reverse the decrement done by GetNext() for the bstr so the
+       * increment in QCBORDecode_NestLevelAscender() called by
+       * ExitBoundedLevel() will work right.
+       */
       DecodeNesting_ReverseDecrement(&(pMe->nesting));
    }
 
@@ -3469,34 +3509,40 @@
       *pBstr = pItem->val.string;
    }
 
-   // This saves the current length of the UsefulInputBuf and then
-   // narrows the UsefulInputBuf to start and length of the wrapped
-   // CBOR that is being entered.
-   //
-   // This makes sure the length is less than
-   // QCBOR_MAX_DECODE_INPUT_SIZE which is slighly less than
-   // UINT32_MAX. The value UINT32_MAX is used as a special indicator
-   // value. The checks against QCBOR_MAX_DECODE_INPUT_SIZE also make
-   // the casts safe.  uEndOfBstr will always be less than
-   // uPreviousLength because of the way UsefulInputBuf works so there
-   // is no need to check it.  There is also a range check in the
-   // seek.
-   //
-   // Most of these calls are simple inline accessors so this doesn't
-   // amount to much code.
-   // Cast of uPreviousLength to uint32_t for cases where SIZE_MAX < UINT32_MAX.
+   /* This saves the current length of the UsefulInputBuf and then
+    * narrows the UsefulInputBuf to start and length of the wrapped
+    * CBOR that is being entered.
+    *
+    * Most of these calls are simple inline accessors so this doesn't
+    * amount to much code.
+    */
+
    const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
-   if((uint32_t)uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+   /* This check makes the cast of uPreviousLength to uint32_t below safe. */
+   if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
       uError = QCBOR_ERR_INPUT_TOO_LARGE;
       goto Done;
    }
-   const size_t uEndOfBstr = UsefulInputBuf_Tell(&(pMe->InBuf));
-   UsefulInputBuf_Seek(&(pMe->InBuf), uEndOfBstr - pItem->val.string.len);
+
+   const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
+                                                              pItem->val.string.ptr);
+   /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
+   if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
+      /* This should never happen because pItem->val.string.ptr should
+       * always be valid since it was just returned.
+       */
+      uError = QCBOR_ERR_INPUT_TOO_LARGE;
+      goto Done;
+   }
+
+   const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
+
+   UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
    UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
 
    uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
                                                  (uint32_t)uPreviousLength,
-                                                 (uint32_t)uEndOfBstr);
+                                                 (uint32_t)uStartOfBstr);
 Done:
    return uError;
 }
@@ -3514,7 +3560,7 @@
       return;
    }
 
-   /* Get the data item that is the map that is being searched */
+   /* Get the data item that is the byte string being entered */
    QCBORItem Item;
    pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
    if(pMe->uLastError != QCBOR_SUCCESS) {
@@ -3579,6 +3625,8 @@
       return;
    }
 
+   const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
+
    /*
     Reset the length of the UsefulInputBuf to what it was before
     the bstr wrapped CBOR was entered.
@@ -3587,7 +3635,7 @@
                                DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
 
 
-   QCBORError uErr = ExitBoundedLevel(pMe, DecodeNesting_GetEndOfBstr(&(pMe->nesting)));
+   QCBORError uErr = ExitBoundedLevel(pMe, uEndOfBstr);
    pMe->uLastError = (uint8_t)uErr;
 }
 
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index 1c2634e..880be02 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -1,6 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -591,13 +591,46 @@
       return "Failed to find 3";
    }
 
+
+   const uint8_t pB[] = {0x01, 0x02, 0x03};
+   UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
+   // Try to map a pointer before
+   if(UsefulBuf_PointerToOffset(Boo, pB-1) != SIZE_MAX) {
+      return "Didn't error on pointer before";
+   }
+
+   // Try to map a pointer after
+   if(UsefulBuf_PointerToOffset(Boo, pB+sizeof(pB)) != SIZE_MAX) {
+      return "Didn't error on pointer after";
+   }
+
+   // Try to map a pointer inside
+   if(UsefulBuf_PointerToOffset(Boo, pB+1) != 1) {
+      return "Incorrect pointer offset";
+   }
+
+   // Try to map a pointer at the start
+   if(UsefulBuf_PointerToOffset(Boo, pB) != 0) {
+      return "Incorrect pointer offset for start";
+   }
+
+   // Try to map a pointer at the end
+   if(UsefulBuf_PointerToOffset(Boo, pB + sizeof(pB)-1) != 2) {
+      return "Incorrect pointer offset for end";
+   }
+
+   // Try to map a pointer on a NULL UB
+   if(UsefulBuf_PointerToOffset(NULLUsefulBufC, pB ) != SIZE_MAX) {
+      return "Incorrect pointer offset for start";
+   }
+
    return NULL;
 }
 
 
 const char *  UIBTest_IntegerFormat()
 {
-   UsefulOutBuf_MakeOnStack(UOB,100);
+   UsefulOutBuf_MakeOnStack(UOB, 100);
 
    const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness
    const uint64_t u64 = 1984738472938472;
@@ -695,6 +728,10 @@
       return "expected error after seek";
    }
 
+   if(UsefulInputBuf_PointerToOffset(&UIB, O.ptr) != 0) {
+      return "PointerToOffset not working";
+   }
+
    return NULL;
 }
 
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 16f0831..949ccbd 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -1813,7 +1813,7 @@
       }
 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
 
-      
+
       // Iterate until there is an error of some sort error
       QCBORItem Item;
       do {
@@ -7026,8 +7026,90 @@
 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
 
 
+/*
+ * An array of an integer and an array. The second array contains
+ * a bstr-wrapped map.
+ *
+ * [7, [h'A36D6669... (see next lines) 73']]
+ *
+ * {"first integer": 42,
+ *   "an array of two strings": ["string1", "string2"],
+ *    "map in a map":
+ *      { "bytes 1": h'78787878',
+ *        "bytes 2": h'79797979',
+ *        "another int": 98,
+ *        "text 2": "lies, damn lies and statistics"
+ *      }
+ *   }
+ */
 
-int32_t PeekTest()
+static const uint8_t pValidWrappedMapEncoded[] = {
+   0x82, 0x07, 0x81, 0x58, 0x97,
+   0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e,
+   0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e,
+   0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20,
+   0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+   0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31,
+   0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d,
+   0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61,
+   0x70, 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
+
+/* As above, but the arrays are indefinite length */
+static const uint8_t pValidIndefWrappedMapEncoded[] = {
+   0x9f, 0x07, 0x9f, 0x58, 0x97,
+   0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e,
+   0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e,
+   0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20,
+   0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+   0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31,
+   0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d,
+   0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61,
+   0x70, 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,
+   0xff, 0xff
+};
+#endif
+
+
+static const uint8_t pWithEmptyMap[] = {0x82, 0x18, 0x64, 0xa0};
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+static const uint8_t pWithEmptyMapInDef[] = {0x9f, 0x18, 0x64, 0xbf, 0xff, 0xff};
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
+static const uint8_t pWrappedByIndefiniteLength[] = {
+   0x81,
+   0xd8, 0x18,
+   0x5f,
+   0x41, 0x83,
+   0x41, 0x18,
+   0x43, 0x2A, 0x18, 0x2B,
+   0x42, 0x18, 0x2C,
+   0xff
+};
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
+
+
+int32_t PeekAndRewindTest()
 {
    QCBORItem          Item;
    QCBORError         nCBORError;
@@ -7097,8 +7179,9 @@
       Item.uLabelAlloc ||
       UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
       Item.uDataType != QCBOR_TYPE_ARRAY ||
-      Item.val.uCount != 2)
+      Item.val.uCount != 2) {
       return 1400;
+   }
 
    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
       return 1500 + (int32_t)nCBORError;
@@ -7197,8 +7280,9 @@
       Item.uLabelAlloc ||
       UsefulBufCompareToSZ(Item.label.string, "another int") ||
       Item.uDataType != QCBOR_TYPE_INT64 ||
-      Item.val.int64 != 98)
+      Item.val.int64 != 98) {
       return 2900;
+   }
 
    if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
       return 3000 + (int32_t)nCBORError;
@@ -7224,5 +7308,399 @@
       return 3300;
    }
 
+
+
+   // Rewind to top level after entering several maps
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return (int32_t)nCBORError;
+    }
+    if(Item.uDataType != QCBOR_TYPE_MAP ||
+       Item.val.uCount != 3) {
+       return 400;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 4000+(int32_t)nCBORError;
+    }
+
+    if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataType != QCBOR_TYPE_INT64 ||
+       Item.val.int64 != 42 ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+       return 4100;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 4100+(int32_t)nCBORError;
+    }
+    if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+       Item.uDataType != QCBOR_TYPE_ARRAY ||
+       Item.val.uCount != 2) {
+       return 4200;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 4200+(int32_t)nCBORError;
+    }
+    if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.val.string, "string1")) {
+       return 4300;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 4300+(int32_t)nCBORError;
+    }
+    if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.val.string, "string2")) {
+       return 4400;
+    }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 4400+(int32_t)nCBORError;
+    }
+    if(Item.uDataType != QCBOR_TYPE_MAP ||
+       Item.val.uCount != 3) {
+       return 4500;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return (int32_t)nCBORError;
+    }
+
+    if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataType != QCBOR_TYPE_INT64 ||
+       Item.val.int64 != 42 ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+       return 4600;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return (int32_t)nCBORError;
+    }
+    if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+       Item.uDataType != QCBOR_TYPE_ARRAY ||
+       Item.val.uCount != 2) {
+       return 4700;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return (int32_t)nCBORError;
+    }
+    if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.val.string, "string1")) {
+       return 4800;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 4900+(int32_t)nCBORError;
+    }
+    if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.val.string, "string2")) {
+       return 5000;
+    }
+
+
+   // Rewind an entered map
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+   QCBORDecode_EnterMap(&DCtx, NULL);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 5100+(int32_t)nCBORError;
+   }
+
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataType != QCBOR_TYPE_INT64 ||
+       Item.val.int64 != 42 ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+       return 5200;
+    }
+
+    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 5200+(int32_t)nCBORError;
+    }
+    if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+       Item.uDataAlloc ||
+       Item.uLabelAlloc ||
+       UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+       Item.uDataType != QCBOR_TYPE_ARRAY ||
+       Item.val.uCount != 2) {
+       return -5300;
+    }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+       return 5300+(int32_t)nCBORError;
+   }
+
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 42 ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+      return 5400;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 5400+(int32_t)nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      Item.val.uCount != 2) {
+      return 5500;
+   }
+
+
+   // Rewind and entered array inside an entered map
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+   QCBORDecode_EnterMap(&DCtx, NULL);
+
+   QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings");
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 5600+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string1")) {
+      return 5700;
+   }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 5700+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string1")) {
+      return 5800;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string2")) {
+      return 5900;
+   }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 5900+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBufCompareToSZ(Item.val.string, "string1")) {
+      return 6000;
+   }
+
+
+   // Rewind a byte string inside an array inside an array
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidWrappedMapEncoded), 0);
+
+   QCBORDecode_EnterArray(&DCtx, NULL);
+
+   uint64_t i;
+   QCBORDecode_GetUInt64(&DCtx, &i);
+
+   QCBORDecode_EnterArray(&DCtx, NULL);
+
+   QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 6100;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return (int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 6200;
+   }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 6300+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 6400;
+   }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   // Rewind a byte string inside an indefinite-length array inside
+   // indefinite-length array
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidIndefWrappedMapEncoded), 0);
+
+   QCBORDecode_EnterArray(&DCtx, NULL);
+
+   QCBORDecode_GetUInt64(&DCtx, &i);
+
+   QCBORDecode_EnterArray(&DCtx, NULL);
+
+   QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
+   if(QCBORDecode_GetError(&DCtx)) {
+      return 6500;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 6600+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 6700;
+   }
+
+   QCBORDecode_Rewind(&DCtx);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return 6800+(int32_t)nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+      return 6900;
+   }
+#endif
+
+   // Rewind an empty map
+   // [100, {}]
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMap), 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 100) {
+      return 7010;
+   }
+   QCBORDecode_EnterMap(&DCtx, NULL);
+
+   /* Do it 5 times to be sure multiple rewinds work */
+   for(int n = 0; n < 5; n++) {
+      nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+      if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) {
+         return 7000 + n;
+      }
+      QCBORDecode_Rewind(&DCtx);
+   }
+   QCBORDecode_ExitMap(&DCtx);
+   QCBORDecode_Rewind(&DCtx);
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 100) {
+      return 7010;
+   }
+   QCBORDecode_ExitArray(&DCtx);
+   QCBORDecode_Rewind(&DCtx);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   i = 9;
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 100) {
+      return 7020;
+   }
+   if(QCBORDecode_GetError(&DCtx)){
+      return 7030;
+   }
+
+   // Rewind an empty indefinite length map
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMapInDef), 0);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 100) {
+      return 7810;
+   }
+   QCBORDecode_EnterMap(&DCtx, NULL);
+
+   /* Do it 5 times to be sure multiple rewinds work */
+   for(int n = 0; n < 5; n++) {
+      nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+      if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) {
+         return 7800 + n;
+      }
+      QCBORDecode_Rewind(&DCtx);
+   }
+   QCBORDecode_ExitMap(&DCtx);
+   QCBORDecode_Rewind(&DCtx);
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 100) {
+      return 7810;
+   }
+   QCBORDecode_ExitArray(&DCtx);
+   QCBORDecode_Rewind(&DCtx);
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   i = 9;
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 100) {
+      return 7820;
+   }
+   if(QCBORDecode_GetError(&DCtx)){
+      return 7830;
+   }
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   // Rewind an indefnite length byte-string wrapped sequence
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
+   QCBORDecode_Init(&DCtx,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWrappedByIndefiniteLength),
+                    0);
+   UsefulBuf_MAKE_STACK_UB(Pool, 100);
+   QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+
+   QCBORDecode_EnterArray(&DCtx, NULL);
+   QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INPUT_TOO_LARGE) {
+      /* this is what happens when trying to enter byte string
+       wrapped CBOR.  Tolerate for now. Eventually it needs
+       to be fixed so this works, but that is not simple. */
+      return 7300;
+   }
+
+   /*
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 42) {
+      return 7110;
+   }
+   QCBORDecode_Rewind(&DCtx);
+   QCBORDecode_GetUInt64(&DCtx, &i);
+   if(i != 42) {
+      return 7220;
+   }*/
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
+
+
+   // Rewind an indefnite length byte-string wrapped sequence
+
    return 0;
 }
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index e6a22f6..c2a4165 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -305,7 +305,7 @@
 /*
  Test PeekNext().
  */
-int32_t PeekTest(void);
+int32_t PeekAndRewindTest(void);
 
 
 
diff --git a/test/run_tests.c b/test/run_tests.c
index 5fb0895..314525c 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -123,7 +123,7 @@
     TEST_ENTRY(CBORSequenceDecodeTests),
     TEST_ENTRY(IntToTests),
     TEST_ENTRY(DecodeTaggedTypeTests),
-    TEST_ENTRY(PeekTest),
+    TEST_ENTRY(PeekAndRewindTest),
 #ifndef     QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
     TEST_ENTRY(EncodeLengthThirtyoneTest),
     TEST_ENTRY(ExponentAndMantissaDecodeTests),