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/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);