QCBOR: Add CBOR encoder / decoder library

QCBOR supports encoding and decoding of most
of the CBOR standard, RFC 7049. QCBOR is open
source maintained at
  https://github.com/laurencelundblade/QCBOR

Change-Id: I5632379e4a1fdb16e0df7f03dfa2374160b7ed7f
Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/lib/ext/qcbor/README.md b/lib/ext/qcbor/README.md
new file mode 100644
index 0000000..58a7080
--- /dev/null
+++ b/lib/ext/qcbor/README.md
@@ -0,0 +1,175 @@
+# QCBOR
+
+QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR.
+
+## Characteristics
+
+**Implemented in C with minimal dependency** – Only dependencies are
+  C99, <stdint.h>, <stddef.h>, <stdbool.h> and <string.h> making it
+  highly portable. There are no #ifdefs to be configured at all.
+
+**Focused on C / native data representation** – Simpler code because
+  there is no support for encoding/decoding to/from JSON, pretty
+  printing, diagnostic notation... Only encoding from native C
+  representations and decoding to native C representations is supported.
+
+**Small simple memory model** – Malloc is not needed. The encode
+  context is 136 bytes, decode context is 104 bytes and the
+  description of decoded data item is 56 bytes. Stack use is light and
+  there is no recursion. The caller supplies the memory to hold the
+  encoded CBOR and encode/decode contexts so caller has full control
+  of memory usage making it good for embedded implementations that
+  have to run in small fixed memory.
+
+**Supports nearly all of RFC 7049** – Only minor, corner-case parts of
+  RFC 7049 are not directly supported (canonicalization, decimal
+  fractions, big floats). Decoding indefinite length strings is supported,
+  but requires a string allocator (see documentation). Encoding indefinite
+  length strings is not supported, but is also not necessary or
+  preferred.
+
+**Extensible and general** – Provides a way to handle data types that
+  are not directly supported.
+
+**Secure coding style** – Uses a construct called UsefulBuf as a
+  discipline for very safe coding the handling of binary data.
+
+**Small code size** – When optimized for size using the compiler -Os
+  option, x86 code is about 4KB (~1.1KB encode, ~2.5KB decode,
+  ~0.4KB common). Other decoders may be smaller, but they may
+  also do less for you, so overall size of the implementation may
+  be larger. For example, QCBOR internally tracks error status
+  so you don't have to check a return code on every operation.
+
+**Clear documented public interface** – The public interface is
+  separated from the implementation. It can be put to use without
+  reading the source.
+
+**Comprehensive test suite** – Easy to verify on a new platform
+  or OS with the test suite. The test suite dependencies are also
+  minimal, only additionally requiring <math.h> for floating point
+  tests.
+
+## Code Status
+
+QCBOR was originally developed by Qualcomm. It was [open sourced
+through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a
+permissive Linux license, September 2018 (thanks Qualcomm!).
+
+This code in [Laurence's
+GitHub](https://github.com/laurencelundblade/QCBOR) has diverged from
+the CAF source with some small simplifications and tidying up.
+
+From Nov 3, 2018, the interface and code are fairly stable. Large
+changes are not planned or expected, particularly in the
+interface. The test coverage is pretty good.
+
+## Building
+
+There is a simple makefile for the UNIX style command line binary that
+compiles everything to run the tests.
+
+These seven files, the contents of the src and inc directories, make
+up the entire implementation.
+
+* inc
+   * UsefulBuf.h
+   * qcbor.h
+* src
+   * UsefulBuf.c
+   * qcbor_encode.c
+   * qcbor_decode.c
+   * ieee754.h
+   * ieee754.c
+
+For most use cases you should just be able to add them to your
+project. Hopefully the easy portability of this implementation makes
+this work straight away, whatever your development environment is.
+
+The files ieee754.c and ieee754.h are support for half-precision
+floating point. The encoding side of the floating point functionality
+is about 500 bytes. If it is never called because no floating point
+numbers are ever encoded, all 500 bytes will be dead stripped and not
+impact code size. The decoding side is about 150 bytes of object
+code. It is never dead stripped because it directly referenced by the
+core decoder, however it doesn't add very much to the size.
+
+The test directory includes some tests that are nearly as portable as
+the main implementation.  If your development environment doesn't
+support UNIX style command line and make, you should be able to make a
+simple project and add the test files to it.  Then just call
+RunTests() to invoke them all.
+
+
+## Changes from CAF Version
+* Float support is restored
+* Minimal length float encoding is added
+* indefinite length arrays/maps are supported
+* indefinite length strings are supported
+* Tag decoding is changed; unlimited number of tags supported, any tag
+value supported, tag utility function for easier tag checking
+* Addition functions in UsefulBuf
+* QCBOREncode_Init takes a UsefulBuf instead of a pointer and size
+* QCBOREncode_Finish takes a UsefulBufC and EncodedCBOR is remove
+* bstr wrapping of arrays/maps is replaced with OpenBstrwrap
+* AddRaw renamed to AddEncoded and can now only add whole arrays or maps,
+not partial maps and arrays (simplification; was a dangerous feature)
+* Finish cannot be called repeatedly on a partial decode (some tests used
+this, but it is not really a good thing to use in the first place)
+* UsefulOutBuf_OutUBuf changed to work differently
+* UsefulOutBuf_Init works differently
+* The "_3" functions are replaced with a small number of simpler functions
+* There is a new AddTag functon instead of the "_3" functions, making
+the interface simpler and saving some code
+* QCBOREncode_AddRawSimple_2 is removed (the macros that referenced
+still exist and work the same)
+
+## Credits
+* Ganesh Kanike for porting to QSEE
+* Mark Bapst for sponsorship and release as open source by Qualcomm
+* Sachin Sharma for release through CAF
+* Tamas Ban for porting to TF-M and 32-bit ARM
+
+## Copyright and License
+
+QCBOR is available under what is essentially the 3-Clause BSD License.
+
+Files created inside Qualcomm and open-sourced through CAF (The Code
+Aurora Forum) have a slightly modified 3-Clause BSD License. The
+modification additionally disclaims NON-INFRINGEMENT.
+
+Files created after release to CAF use the standard 3-Clause BSD
+License with no modification. These files have the SPDX license
+identifier, "SPDX-License-Identifier: BSD-3-Clause" in them.
+
+### BSD-3-Clause license
+
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+### Copyright for this README
+
+Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+
+
diff --git a/lib/ext/qcbor/inc/UsefulBuf.h b/lib/ext/qcbor/inc/UsefulBuf.h
new file mode 100644
index 0000000..fa17b6c
--- /dev/null
+++ b/lib/ext/qcbor/inc/UsefulBuf.h
@@ -0,0 +1,1536 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+/*===================================================================================
+ FILE:  UsefulBuf.h
+
+ DESCRIPTION:  General purpose input and output buffers
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when               who             what, where, why
+ --------           ----            ---------------------------------------------------
+ 12/17/2018         llundblade      Remove const from UsefulBuf and UsefulBufC .len
+ 12/13/2018         llundblade      Documentation improvements
+ 09/18/2018         llundblade      Cleaner distinction between UsefulBuf and UsefulBufC
+ 02/02/18           llundbla        Full support for integers in and out; fix pointer
+                                    alignment bug. Incompatible change: integers in/out
+                                    are now in network byte order.
+ 08/12/17           llundbla        Added UsefulOutBuf_AtStart and UsefulBuf_Find
+ 06/27/17           llundbla        Fix UsefulBuf_Compare() bug. Only affected comparison
+                                    for < or > for unequal length buffers.  Added
+                                    UsefulBuf_Set() function.
+ 05/30/17           llundbla        Functions for NULL UsefulBufs and const / unconst
+ 11/13/16           llundbla        Initial Version.
+
+
+ =====================================================================================*/
+
+#ifndef _UsefulBuf_h
+#define _UsefulBuf_h
+
+
+#include <stdint.h> // for uint8_t, uint16_t....
+#include <string.h> // for strlen, memcpy, memmove, memset
+#include <stddef.h> // for size_t
+
+/**
+ @file UsefulBuf.h
+
+ The goal of this code is to make buffer and pointer manipulation
+ easier and safer when working with binary data.
+
+ You use the UsefulBuf, UsefulOutBuf and UsefulInputBuf
+ structures to represent buffers rather than ad hoc pointers and lengths.
+
+ With these it will often be possible to write code that does little or no
+ direct pointer manipulation for copying and formatting data. For example
+ the QCBOR encoder was rewritten using these and has no direct pointer
+ manipulation.
+
+ While it is true that object code using these functions will be a little
+ larger and slower than a white-knuckle clever use of pointers might be, but
+ not by that much or enough to have an affect for most use cases. For
+ security-oriented code this is highly worthwhile. Clarity, simplicity,
+ reviewability and are more important.
+
+ There are some extra sanity and double checks in this code to help catch
+ coding errors and simple memory corruption. They are helpful, but not a
+ substitute for proper code review, input validation and such.
+
+ This code consists of a lot of inline functions and a few that are not.
+ It should not generate very much object code, especially with the
+ optimizer turned up to -Os or -O3. The idea is that the inline
+ functions are easier to review and understand and the optimizer does
+ the work of making the code small.
+ */
+
+
+/*...... This is a ruler that is 80 characters long...........................*/
+
+/**
+ UsefulBufC and UsefulBuf are simple data structures to hold a pointer and
+ length for a binary data.  In C99 this data structure can be passed on the
+ stack making a lot of code cleaner than carrying around a pointer and
+ length as two parameters.
+
+ This is also conducive to secure code practice as the lengths are
+ always carried with the pointer and the convention for handling a
+ pointer and a length is clear.
+
+ While it might be possible to write buffer and pointer code more
+ efficiently in some use cases, the thought is that unless there is an
+ extreme need for performance (e.g., you are building a gigabit-per-second
+ IP router), it is probably better to have cleaner code you can be most
+ certain about the security of.
+
+ The non-const UsefulBuf is usually used to refer a buffer to be filled in.
+ The length is the size of the buffer.
+
+ The const UsefulBufC is usually used to refer to some data that has been
+ filled in. The length is amount of valid data pointed to.
+
+ A common use is to pass a UsefulBuf to a function, the function fills it
+ in, the function returns a UsefulBufC. The pointer is the same in both.
+
+ A UsefulBuf is NULL, it has no value, when the ptr in it is NULL.
+
+ There are utility functions for the following:
+  - Checking for UsefulBufs that are NULL, empty or both
+  - Copying, copying with offset, copying head or tail
+  - Comparing and finding substrings
+  - Initializating
+  - Create initialized const UsefulBufC from compiler literals
+  - Create initialized const UsefulBufC from NULL-terminated string
+  - Make an empty UsefulBuf on the stack
+
+ See also UsefulOutBuf. It is a richer structure that has both the size of
+ the valid data and the size of the buffer.
+
+ UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it can go
+ on the stack and be a function parameter or return value.
+
+ UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his birthday.
+ Eeyore's balloon fits beautifully, "it goes in and out like anything".
+
+*/
+typedef struct useful_buf_c {
+    const void *ptr;
+    size_t      len;
+} UsefulBufC;
+
+
+/**
+ The non-const UsefulBuf typically used for some allocated memory
+ that is to be filled in. The len is the amount of memory,
+ not the length of the valid data in the buffer.
+ */
+typedef struct useful_buf {
+   void  *ptr;
+   size_t len;
+} UsefulBuf;
+
+
+/**
+ A "NULL" UsefulBufC is one that has no value in the same way a NULL pointer has no value.
+ A UsefulBuf is NULL when the ptr field is NULL. It doesn't matter what len is.
+ See UsefulBuf_IsEmpty() for the distinction between NULL and empty.
+ */
+#define NULLUsefulBufC  ((UsefulBufC) {NULL, 0})
+
+/** A NULL UsefulBuf is one that has no memory associated the say way
+ NULL points to nothing. It does not matter what len is.
+ */
+#define NULLUsefulBuf   ((UsefulBuf) {NULL, 0})
+
+
+/**
+ @brief Check if a UsefulBuf is NULL or not
+
+ @param[in] UB The UsefulBuf to check
+
+ @return 1 if it is NULL, 0 if not.
+ */
+static inline int UsefulBuf_IsNULL(UsefulBuf UB) {
+   return !UB.ptr;
+}
+
+
+/**
+ @brief Check if a UsefulBufC is NULL or not
+
+ @param[in] UB The UsefulBufC to check
+
+ @return 1 if it is NULL, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLC(UsefulBufC UB) {
+   return !UB.ptr;
+}
+
+
+/**
+ @brief Check if a UsefulBuf is empty or not
+
+ @param[in] UB The UsefulBuf to check
+
+ @return 1 if it is empty, 0 if not.
+
+ An "Empty" UsefulBuf is one that has a value and can be considered to be set,
+ but that value is of zero length.  It is empty when len is zero. It
+ doesn't matter what the ptr is.
+
+ A lot of uses will not need to clearly distinguish a NULL UsefulBuf
+ from an empty one and can have the ptr NULL and the len 0.  However
+ if a use of UsefulBuf needs to make a distinction then ptr should
+ not be NULL when the UsefulBuf is considered empty, but not NULL.
+
+ */
+static inline int UsefulBuf_IsEmpty(UsefulBuf UB) {
+   return !UB.len;
+}
+
+
+/**
+ @brief Check if a UsefulBufC is empty or not
+
+ @param[in] UB The UsefulBufC to check
+
+ @return 1 if it is empty, 0 if not.
+ */
+static inline int UsefulBuf_IsEmptyC(UsefulBufC UB) {
+   return !UB.len;
+}
+
+
+/**
+ @brief Check if a UsefulBuf is NULL or empty
+
+ @param[in] UB The UsefulBuf to check
+
+ @return 1 if it is either NULL or empty, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB) {
+   return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
+}
+
+
+/**
+ @brief Check if a UsefulBufC is NULL or empty
+
+ @param[in] UB The UsefulBufC to check
+
+ @return 1 if it is either NULL or empty, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB) {
+   return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
+}
+
+
+/**
+ @brief Convert a non const UsefulBuf to a const UsefulBufC
+
+ @param[in] UB The UsefulBuf to convert
+
+ Returns: a UsefulBufC struct
+ */
+
+static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
+{
+   return (UsefulBufC){UB.ptr, UB.len};
+}
+
+
+/**
+ @brief Convert a const UsefulBufC to a non-const UsefulBuf
+
+ @param[in] UBC The UsefulBuf to convert
+
+ Returns: a non const UsefulBuf struct
+ */
+static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
+{
+   return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+
+
+/**
+ Convert a literal string to a UsefulBufC.
+
+ szString must be a literal string that you can take sizeof.
+ This is better for literal strings than UsefulBuf_FromSZ()
+ because it generates less code. It will not work on
+ non-literal strings.
+
+ The terminating \0 (NULL) is NOT included in the length!
+
+ */
+#define UsefulBuf_FROM_SZ_LITERAL(szString) \
+    ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+
+/**
+ Convert a literal byte array to a UsefulBufC.
+
+ pBytes must be a literal string that you can take sizeof.
+ It will not work on  non-literal arrays.
+
+ */
+#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
+    ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+
+/**
+ Make an automatic variable with name of type UsefulBuf and point it to a stack
+ variable of the give size
+ */
+#define  UsefulBuf_MAKE_STACK_UB(name, size) \
+    uint8_t    __pBuf##name[(size)];\
+    UsefulBuf  name = {__pBuf##name , sizeof( __pBuf##name )}
+
+
+/**
+ Make a byte array in to a UsefulBuf
+ */
+#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
+    ((UsefulBuf) {(pBytes), sizeof(pBytes)})
+
+/**
+ @brief Convert a NULL terminated string to a UsefulBufC.
+
+ @param[in] szString The string to convert
+
+ @return a UsefulBufC struct
+
+ UsefulBufC.ptr points to the string so it's lifetime
+ must be maintained.
+
+ The terminating \0 (NULL) is NOT included in the length!
+
+ */
+static inline UsefulBufC UsefulBuf_FromSZ(const char *szString){
+    return ((UsefulBufC) {szString, strlen(szString)});
+}
+
+
+/**
+ @brief Copy one UsefulBuf into another at an offset
+
+ @param[in] Dest Destiation buffer to copy into
+ @param[in] uOffset The byte offset in Dest at which to copy to
+ @param[in] Src The bytes to copy
+
+ @return Pointer and length of the copy
+
+ This fails and returns NULLUsefulBufC Src.len + uOffset > Dest.len.
+
+ Like memcpy, there is no check for NULL. If NULL is passed
+ this will crash.
+
+ There is an assumption that there is valid data in Dest up to
+ uOffset as the resulting UsefulBufC returned starts
+ at the beginning of Dest and goes to Src.len + uOffset.
+
+ */
+UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
+
+
+/**
+ @brief Copy one UsefulBuf into another
+
+ @param[in] Dest The destination buffer to copy into
+ @param[out] Src  The source to copy from
+
+ @return filled in UsefulBufC on success, NULLUsefulBufC on failure
+
+ This fails if Src.len is greater than Dest.len.
+
+ Note that like memcpy, the pointers are not checked and
+ this will crash, rather than return NULLUsefulBufC if
+ they are NULL or invalid.
+
+ Results are undefined if Dest and Src overlap.
+
+ */
+static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src) {
+   return UsefulBuf_CopyOffset(Dest, 0, Src);
+}
+
+
+/**
+ @brief Set all bytes in a UsefulBuf to a value, for example 0
+
+ @param[in] pDest The destination buffer to copy into
+ @param[in] value The value to set the bytes to
+
+ Note that like memset, the pointer in pDest is not checked and
+ this will crash if NULL or invalid.
+
+ */
+static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
+{
+   memset(pDest.ptr, value, pDest.len);
+   return (UsefulBufC){pDest.ptr, pDest.len};
+}
+
+
+/**
+ @brief Copy a pointer into a UsefulBuf
+
+ @param[in,out] Dest The destination buffer to copy into
+ @param[in] ptr  The source to copy from
+ @param[in] len  Length of the source; amoutn to copy
+
+ @return 0 on success, 1 on failure
+
+ This fails and returns NULLUsefulBufC if len is greater than
+ pDest->len.
+
+ Note that like memcpy, the pointers are not checked and
+ this will crash, rather than return 1 if they are NULL
+ or invalid.
+
+ */
+inline static UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
+{
+   return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
+}
+
+
+/**
+  @brief Returns a truncation of a UsefulBufC
+
+  @param[in] UB The buffer to get the head of
+  @param[in] uAmount The number of bytes in the head
+
+  @return A UsefulBufC that is the head of UB
+
+ */
+static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
+{
+   if(uAmount > UB.len) {
+      return NULLUsefulBufC;
+   }
+   return (UsefulBufC){UB.ptr, uAmount};
+}
+
+
+/**
+ @brief  Returns bytes from the end of a UsefulBufC
+
+ @param[in] UB       The buffer to get the tail of
+ @param[in] uAmount  The offset from the start where the tail is to begin
+
+ @return A UsefulBufC that is the tail of UB or NULLUsefulBufC if
+         uAmount is greater than the length of the UsefulBufC
+
+ If the input UsefulBufC is NULL, but the len is not, then the
+ length of the tail will be calculated and returned along
+ with a NULL ptr.
+ */
+static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
+{
+   UsefulBufC ReturnValue;
+
+   if(uAmount > UB.len) {
+      ReturnValue = NULLUsefulBufC;
+   } else if(UB.ptr == NULL) {
+      ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
+   } else {
+      ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
+   }
+
+   return ReturnValue;
+}
+
+
+/**
+ @brief Compare two UsefulBufCs
+
+ @param[in] UB1 The destination buffer to copy into
+ @param[in] UB2  The source to copy from
+
+ @return 0 if equal...
+
+ Returns a negative value if UB1 if is less than UB2. UB1 is
+ less than UB2 if it is shorter or the first byte that is not
+ the same is less.
+
+ Returns 0 if the UsefulBufs are the same.
+
+ Returns a positive value if UB2 is less than UB1.
+
+ All that is of significance is that the result is positive,
+ negative or 0. (This doesn't return the difference between
+ the first non-matching byte like memcmp).
+
+ */
+int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
+
+
+/**
+ @brief Find one UsefulBuf in another
+
+ @param[in] BytesToSearch  UsefulBuf to search through
+ @param[in] BytesToFind    UsefulBuf with bytes to be found
+
+ @return position of found bytes or SIZE_MAX if not found.
+
+ */
+size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
+
+
+
+
+#if 0 // NOT_DEPRECATED
+/** Deprecated macro; use UsefulBuf_FROM_SZ_LITERAL instead */
+#define SZLiteralToUsefulBufC(szString) \
+    ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
+#define  MakeUsefulBufOnStack(name, size) \
+    uint8_t    __pBuf##name[(size)];\
+    UsefulBuf  name = {__pBuf##name , sizeof( __pBuf##name )}
+
+/** Deprecated macro; use UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
+#define ByteArrayLiteralToUsefulBufC(pBytes) \
+    ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+/** Deprecated function; use UsefulBuf_Unconst() instead */
+static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
+{
+    return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+#endif
+
+
+
+/*
+ Convenient functions to avoid type punning, compiler warnings and such
+ The optimizer reduces them to a simple assignment
+ This is a crusty corner of C. It shouldn't be this hard.
+ */
+static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
+{
+    uint32_t u32;
+    memcpy(&u32, &f, sizeof(uint32_t));
+    return u32;
+}
+
+static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
+{
+    uint64_t u64;
+    memcpy(&u64, &d, sizeof(uint64_t));
+    return u64;
+}
+
+static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
+{
+    double d;
+    memcpy(&d, &u64, sizeof(uint64_t));
+    return d;
+}
+
+static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
+{
+    float f;
+    memcpy(&f, &u32, sizeof(uint32_t));
+    return f;
+}
+
+
+
+
+
+/**
+ UsefulOutBuf is a structure and functions (an object) that are good
+ for serializing data into a buffer such as is often done with network
+ protocols or data written to files.
+
+ The main idea is that all the pointer manipulation for adding data is
+ done by UsefulOutBuf functions so the caller doesn't have to do any.
+ All the pointer manipulation is centralized here.  This code will
+ have been reviewed and written carefully so it spares the caller of
+ much of this work and results in much safer code with much less work.
+
+ The functions to add data to the output buffer always check the
+ length and will never write off the end of the output buffer. If an
+ attempt to add data that will not fit is made, an internal error flag
+ will be set and further attempts to add data will not do anything.
+
+ Basically, if you initialized with the correct buffer, there is no
+ way to ever write off the end of that buffer when calling the Add
+ and Insert functions here.
+
+ The functions to add data do not return an error. The working model
+ is that the caller just makes all the calls to add data without any
+ error checking on each one. The error is instead checked after all the
+ data is added when the result is to be used.  This makes the caller's
+ code cleaner.
+
+ There is a utility function to get the error status anytime along the
+ way if the caller wants. There are functions to see how much room is
+ left and see if some data will fit too, but their use is generally
+ not necessary.
+
+ The general call flow is like this:
+
+    - Initialize the UsefulOutBuf with the buffer that is to have the
+      data added.  The caller allocates the buffer.  It can be heap
+      or stack or shared memory (or other).
+
+    - Make calls to add data to the output buffer. Insert and append
+      are both supported. The append and insert calls will never write
+      off the end of the buffer.
+
+    - When all data is added, check the error status to make sure
+      everything fit.
+
+    - Get the resulting serialized data either as a UsefulBuf (a
+      pointer and length) or have it copied to another buffer.
+
+ UsefulOutBuf can be initialized with just a buffer length by passing
+ NULL as the pointer to the output buffer. This is useful if you want
+ to go through the whole serialization process to either see if it
+ will fit into a given buffer or compute the size of the buffer
+ needed. Pass a very large buffer size when calling Init, if you want
+ just to compute the size.
+
+ Some inexpensive simple sanity checks are performed before every data
+ addition to guard against use of an uninitialized or corrupted
+ UsefulOutBuf.
+
+ This has been used to create a CBOR encoder. The CBOR encoder has
+ almost no pointer manipulation in it, is much easier to read, and
+ easier to review.
+
+ A UsefulOutBuf is 27 bytes or 15 bytes on 64- or 32-bit machines so it
+ can go on the stack or be a C99 function parameter.
+ */
+
+typedef struct useful_out_buf {
+   UsefulBuf  UB; // Memory that is being output to
+   size_t     data_len;  // length of the data
+   uint16_t   magic; // Used to detect corruption and lack of initialization
+   uint8_t    err;
+} UsefulOutBuf;
+
+
+/**
+ @brief Initialize and supply the actual output buffer
+
+ @param[out] me The UsefulOutBuf to initialize
+ @param[in] Storage  Buffer to output into
+
+ Intializes the UsefulOutBuf with storage. Sets the current position
+ to the beginning of the buffer clears the error.
+
+ This must be called before the UsefulOutBuf is used.
+ */
+void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage);
+
+
+
+
+/** Convenience marco to make a UsefulOutBuf on the stack and
+   initialize it with stack buffer
+ */
+#define  UsefulOutBuf_MakeOnStack(name, size) \
+   uint8_t       __pBuf##name[(size)];\
+   UsefulOutBuf  name;\
+   UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)});
+
+
+
+/**
+ @brief Reset a UsefulOutBuf for re use
+
+ @param[in] me Pointer to the UsefulOutBuf
+
+ This sets the amount of data in the output buffer to none and
+ clears the error state.
+
+ The output buffer is still the same one and size as from the
+ UsefulOutBuf_Init() call.
+
+ It doesn't zero the data, just resets to 0 bytes of valid data.
+ */
+static inline void UsefulOutBuf_Reset(UsefulOutBuf *me)
+{
+   me->data_len = 0;
+   me->err    = 0;
+}
+
+
+/**
+ @brief Returns position of end of data in the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+
+ @return position of end of data
+
+ On a freshly initialized UsefulOutBuf with no data added, this will
+ return 0. After ten bytes have been added, it will return 10 and so
+ on.
+
+ Generally callers will not need this function for most uses of
+ UsefulOutBuf.
+
+ */
+static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *me)
+{
+   return me->data_len;
+}
+
+
+/**
+ @brief Returns whether any data has been added to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+
+ @return 1 if output position is at start
+
+ */
+static inline int UsefulOutBuf_AtStart(UsefulOutBuf *me)
+{
+   return 0 == me->data_len;
+}
+
+
+/**
+ @brief Inserts bytes into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] NewData UsefulBuf with the bytes to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ NewData is the pointer and length for the bytes to be added to the
+ output buffer. There must be room in the output buffer for all of
+ NewData or an error will occur.
+
+ The insertion point must be between 0 and the current valid data. If
+ not an error will occur. Appending data to the output buffer is
+ achieved by inserting at the end of the valid data. This can be
+ retrieved by calling UsefulOutBuf_GetEndPosition().
+
+ When insertion is performed, the bytes between the insertion point and
+ the end of data previously added to the output buffer is slid to the
+ right to make room for the new data.
+
+ Overlapping buffers are OK. NewData can point to data in the output
+ buffer.
+
+ If an error occurs an error state is set in the UsefulOutBuf. No
+ error is returned.  All subsequent attempts to add data will do
+ nothing.
+
+ Call UsefulOutBuf_GetError() to find out if there is an error. This
+ is usually not needed until all additions of data are complete.
+
+ */
+void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uPos);
+
+
+/**
+ @brief Insert a data buffer into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] pBytes Pointer to the bytes to insert
+ @param[in] uLen Length of the bytes to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a pointer and length is passed in rather than an
+ UsefulBuf.
+
+ */
+static inline void UsefulOutBuf_InsertData(UsefulOutBuf *me, const void *pBytes, size_t uLen, size_t uPos)
+{
+   UsefulBufC Data = {pBytes, uLen};
+   UsefulOutBuf_InsertUsefulBuf(me, Data, uPos);
+}
+
+
+/**
+ @brief Insert a NULL-terminated string into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] szString string to append
+
+ */
+static inline void UsefulOutBuf_InsertString(UsefulOutBuf *me, const char *szString, size_t uPos)
+{
+   UsefulOutBuf_InsertUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}, uPos);
+}
+
+
+/**
+ @brief Insert a byte into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] byte Bytes to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+ */
+static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me, uint8_t byte, size_t uPos)
+{
+   UsefulOutBuf_InsertData(me, &byte, 1, uPos);
+}
+
+
+/**
+ @brief Insert a 16-bit integer into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] uInteger16 Integer to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+
+ The integer will be inserted in network byte order (big endian)
+ */
+static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me, uint16_t uInteger16, size_t uPos)
+{
+   // Converts native integer format to network byte order (big endian)
+   uint8_t tmp[2];
+   tmp[0] = (uInteger16 & 0xff00) >> 8;
+   tmp[1] = (uInteger16 & 0xff);
+   UsefulOutBuf_InsertData(me, tmp, 2, uPos);
+}
+
+
+/**
+ @brief Insert a 32-bit integer into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] uInteger32 Integer to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+
+ The integer will be inserted in network byte order (big endian)
+ */
+static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *me, uint32_t uInteger32, size_t uPos)
+{
+   // Converts native integer format to network byte order (big endian)
+   uint8_t tmp[4];
+   tmp[0] = (uInteger32 & 0xff000000) >> 24;
+   tmp[1] = (uInteger32 & 0xff0000) >> 16;
+   tmp[2] = (uInteger32 & 0xff00) >> 8;
+   tmp[3] = (uInteger32 & 0xff);
+   UsefulOutBuf_InsertData(me, tmp, 4, uPos);
+}
+
+
+/**
+ @brief Insert a 64-bit integer into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] uInteger64 Integer to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+
+ The integer will be inserted in network byte order (big endian)
+ */
+static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *me, uint64_t uInteger64, size_t uPos)
+{
+   // Converts native integer format to network byte order (big endian)
+   uint8_t tmp[8];
+   tmp[0] = (uInteger64 & 0xff00000000000000) >> 56;
+   tmp[1] = (uInteger64 & 0xff000000000000) >> 48;
+   tmp[2] = (uInteger64 & 0xff0000000000) >> 40;
+   tmp[3] = (uInteger64 & 0xff00000000) >> 32;
+   tmp[4] = (uInteger64 & 0xff000000) >> 24;
+   tmp[5] = (uInteger64 & 0xff0000) >> 16;
+   tmp[6] = (uInteger64 & 0xff00) >> 8;
+   tmp[7] = (uInteger64 & 0xff);
+   UsefulOutBuf_InsertData(me, tmp, 8, uPos);
+}
+
+
+/**
+ @brief Insert a float into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] f Integer to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+
+ The float will be inserted in network byte order (big endian)
+ */
+static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *me, float f, size_t uPos)
+{
+   UsefulOutBuf_InsertUint32(me, UsefulBufUtil_CopyFloatToUint32(f), uPos);
+}
+
+
+/**
+ @brief Insert a double into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBul
+ @param[in] d Integer to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+
+ The double will be inserted in network byte order (big endian)
+ */
+static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *me, double d, size_t uPos)
+{
+   UsefulOutBuf_InsertUint64(me, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
+}
+
+
+
+/**
+ Append a UsefulBuf into the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] NewData UsefulBuf with the bytes to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+*/
+static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData)
+{
+   // An append is just a insert at the end
+   UsefulOutBuf_InsertUsefulBuf(me, NewData, UsefulOutBuf_GetEndPosition(me));
+}
+
+
+/**
+ Append bytes to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] pBytes Pointer to bytes to append
+ @param[in] uLen Index in output buffer at which to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+ */
+
+static inline void UsefulOutBuf_AppendData(UsefulOutBuf *me, const void *pBytes, size_t uLen)
+{
+   UsefulBufC Data = {pBytes, uLen};
+   UsefulOutBuf_AppendUsefulBuf(me, Data);
+}
+
+
+/**
+ Append a NULL-terminated string to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] szString string to append
+
+ */
+static inline void UsefulOutBuf_AppendString(UsefulOutBuf *me, const char *szString)
+{
+   UsefulOutBuf_AppendUsefulBuf(me, (UsefulBufC){szString, strlen(szString)});
+}
+
+
+/**
+ @brief Append a byte to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] byte Bytes to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+ */
+static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *me, uint8_t byte)
+{
+   UsefulOutBuf_AppendData(me, &byte, 1);
+}
+
+/**
+ @brief Append an integer to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] uInteger16 Integer to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *me, uint16_t uInteger16){
+   UsefulOutBuf_InsertUint16(me, uInteger16, UsefulOutBuf_GetEndPosition(me));
+}
+
+/**
+ @brief Append an integer to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] uInteger32 Integer to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *me, uint32_t uInteger32){
+   UsefulOutBuf_InsertUint32(me, uInteger32, UsefulOutBuf_GetEndPosition(me));
+}
+
+/**
+ @brief Append an integer to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] uInteger64 Integer to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *me, uint64_t uInteger64){
+   UsefulOutBuf_InsertUint64(me, uInteger64, UsefulOutBuf_GetEndPosition(me));
+}
+
+
+/**
+ @brief Append a float to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] f Float to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The float will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *me, float f){
+   UsefulOutBuf_InsertFloat(me, f, UsefulOutBuf_GetEndPosition(me));
+}
+
+/**
+ @brief Append a float to the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] d Double to append
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The double will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *me, double d){
+   UsefulOutBuf_InsertDouble(me, d, UsefulOutBuf_GetEndPosition(me));
+}
+
+/**
+ @brief Returns the current error status
+
+ @param[in] me Pointer to the UsefulOutBuf
+
+ @return 0 if all OK, 1 on error
+
+ This is the error status since the call to either
+ UsefulOutBuf_Reset() of UsefulOutBuf_Init().  Once it goes into error
+ state it will stay until one of those functions is called.
+
+ Possible error conditions are:
+   - bytes to be inserted will not fit
+   - insertion point is out of buffer or past valid data
+   - current position is off end of buffer (probably corruption or uninitialized)
+   - detect corruption / uninitialized by bad magic number
+ */
+
+static inline int UsefulOutBuf_GetError(UsefulOutBuf *me)
+{
+   return me->err;
+}
+
+
+/**
+ @brief Returns number of bytes unused used in the output buffer
+
+ @param[in] me Pointer to the UsefulOutBuf
+
+ @return Number of unused bytes or zero
+
+ Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf()
+ it is usually not necessary to use this.
+ */
+
+static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *me)
+{
+   return me->UB.len - me->data_len;
+}
+
+
+/**
+ @brief Returns true / false if some number of bytes will fit in the UsefulOutBuf
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[in] uLen Number of bytes for which to check
+
+ @return 1 or 0 if nLen bytes would fit
+
+ Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf()
+ it is usually not necessary to use this.
+ */
+
+static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *me, size_t uLen)
+{
+   return uLen <= UsefulOutBuf_RoomLeft(me);
+}
+
+
+/**
+   @brief Returns the resulting valid data in a UsefulOutBuf
+
+   @param[in] me Pointer to the UsefulOutBuf.
+
+   @return The valid data in UsefulOutBuf.
+
+   The storage for the returned data is Storage parameter passed
+   to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
+
+   This can be called anytime and many times to get intermediate
+   results. It doesn't change the data or reset the current position
+   so you can keep adding data.
+ */
+
+UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me);
+
+
+/**
+ @brief Copies the valid data out into a supplied buffer
+
+ @param[in] me Pointer to the UsefulOutBuf
+ @param[out] Dest The destination buffer to copy into
+
+ @return Pointer and length of copied data.
+
+ This is the same as UsefulOutBuf_OutUBuf() except it copies the data.
+*/
+
+UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf Dest);
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ UsefulInputBuf is the counterpart to UsefulOutBuf and is for parsing
+ data read or received.  Initialize it with the data
+ from the network and its length. Then  use the functions
+ here to get the various data types out of it. It maintains a position
+ for getting the next item. This means you don't have to track a
+ pointer as you get each object. UsefulInputBuf does that for you and
+ makes sure it never goes off the end of the buffer.  The QCBOR
+ implementation parser makes use of this for all its pointer math and
+ length checking.
+
+ UsefulInputBuf also maintains an internal error state so you do not have
+ to. Once data has been requested off the end of the buffer, it goes
+ into an error state. You can keep calling functions to get more data
+ but they will either return 0 or NULL. As long as you don't
+ dereference the NULL, you can wait until all data items have been
+ fetched before checking for the error and this can simplify your
+ code.
+
+ The integer and float parsing expects network byte order (big endian).
+ Network byte order is what is used by TCP/IP, CBOR and most internet
+ protocols.
+
+ Lots of inlining is used to keep code size down. The code optimizer,
+ particularly with the -Os, also reduces code size a lot. The only
+ non-inline code is UsefulInputBuf_GetBytes() which is less than 100
+ bytes so use of UsefulInputBuf doesn't add much code for all the messy
+ hard-to-get right issues with parsing in C that is solves.
+
+ The parse context size is:
+   64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
+   32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
+
+ */
+
+#define UIB_MAGIC (0xB00F)
+
+typedef struct useful_input_buf {
+   // Private data structure
+   UsefulBufC UB;     // Data being parsed
+   size_t     cursor; // Current offset in data being parse
+   uint16_t   magic;  // Check for corrupted or uninitialized UsefulInputBuf
+   uint8_t    err;    // Set request goes off end or magic number is bad
+} UsefulInputBuf;
+
+
+
+/**
+ @brief Initialize the UsefulInputBuf structure before use.
+
+ @param[in] me Pointer to the UsefulInputBuf instance.
+ @param[in] UB Pointer to the data to parse.
+
+ */
+static inline void UsefulInputBuf_Init(UsefulInputBuf *me, UsefulBufC UB)
+{
+   me->cursor = 0;
+   me->err    = 0;
+   me->magic  = UIB_MAGIC;
+   me->UB     = UB;
+}
+
+
+/**
+ @brief Returns current position in input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return Integer position of the cursor
+
+ The position that the next bytes will be returned from.
+
+ */
+static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *me)
+{
+   return me->cursor;
+}
+
+
+/**
+ @brief Sets current position in input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+ @param[in] uPos  Position to set to
+
+ If the position is off the end of the input buffer, the error state
+ is entered and all functions will do nothing.
+
+ Seeking to a valid position in the buffer will not reset the error
+ state. Only re initialization will do that.
+
+ */
+static inline void UsefulInputBuf_Seek(UsefulInputBuf *me, size_t uPos)
+{
+   if(uPos > me->UB.len) {
+      me->err = 1;
+   } else {
+      me->cursor = uPos;
+   }
+}
+
+
+/**
+ @brief Returns the number of bytes from the cursor to the end of the buffer,
+ the uncomsummed bytes.
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return number of bytes unconsumed or 0 on error.
+
+ This is a critical function for input length validation. This does
+ some pointer / offset math.
+
+ Returns 0 if the cursor it invalid or corruption of the structure is
+ detected.
+
+ Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *me)
+{
+   // Magic number is messed up. Either the structure got overwritten
+   // or was never initialized.
+   if(me->magic != UIB_MAGIC) {
+      return 0;
+   }
+
+   // The cursor is off the end of the input buffer given
+   // Presuming there are no bugs in this code, this should never happen.
+   // If it so, the struct was corrupted. The check is retained as
+   // as a defense in case there is a bug in this code or the struct is corrupted.
+   if(me->cursor > me->UB.len) {
+      return 0;
+   }
+
+   // subtraction can't go neative because of check above
+   return me->UB.len - me->cursor;
+}
+
+
+/**
+ @brief Check if there are any unconsumed bytes
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return 1 if len bytes are available after the cursor, and 0 if not
+
+ */
+static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *me, size_t uLen)
+{
+   return UsefulInputBuf_BytesUnconsumed(me) >= uLen ? 1 : 0;
+}
+
+
+/**
+ @brief Get pointer to bytes out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+ @param[in] uNum  Number of bytes to get
+
+ @return Pointer to bytes.
+
+ This consumes n bytes from the input buffer. It returns a pointer to
+ the start of the n bytes.
+
+ If there are not n bytes in the input buffer, NULL will be returned
+ and an error will be set.
+
+ It advances the current position by n bytes.
+ */
+const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uNum);
+
+
+/**
+ @brief Get UsefulBuf out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+ @param[in] uNum  Number of bytes to get
+
+ @return UsefulBufC with ptr and length for bytes consumed.
+
+ This consumes n bytes from the input buffer and returns the pointer
+ and len to them as a UsefulBufC. The len returned will always be n.
+
+ If there are not n bytes in the input buffer, UsefulBufC.ptr will be
+ NULL and UsefulBufC.len will be 0. An error will be set.
+
+ It advances the current position by n bytes.
+ */
+static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *me, size_t uNum)
+{
+   const void *pResult = UsefulInputBuf_GetBytes(me, uNum);
+   if(!pResult) {
+      return NULLUsefulBufC;
+   } else {
+      return (UsefulBufC){pResult, uNum};
+   }
+}
+
+
+/**
+ @brief Get a byte out of the input buffer.
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The byte
+
+ This consumes 1 byte from the input buffer. It returns the byte.
+
+ If there is not 1 byte in the buffer, 0 will be returned for the byte
+ and an error set internally.  You must check the error at some point
+ to know whether the 0 was the real value or just returned in error,
+ but you may not have to do that right away.  Check the error state
+ with UsefulInputBuf_GetError().  You can also know you are in the
+ error state if UsefulInputBuf_GetBytes() returns NULL or the ptr from
+ UsefulInputBuf_GetUsefulBuf() is NULL.
+
+ It advances the current position by 1 byte.
+ */
+static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *me)
+{
+   const void *pResult = UsefulInputBuf_GetBytes(me, sizeof(uint8_t));
+
+   return pResult ? *(uint8_t *)pResult : 0;
+}
+
+
+/**
+ @brief Get a uint16_t out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The uint16_t
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a uint16_t and two bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *me)
+{
+   const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint16_t));
+
+   if(!pResult) {
+      return 0;
+   }
+
+   return  ((uint16_t)pResult[0] << 8) + (uint16_t)pResult[1];
+}
+
+
+/**
+ @brief Get a uint32_t out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The uint32_t
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a uint32_t and four bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *me)
+{
+   const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint32_t));
+
+   if(!pResult) {
+      return 0;
+   }
+
+   return ((uint32_t)pResult[0]<<24) +
+          ((uint32_t)pResult[1]<<16) +
+          ((uint32_t)pResult[2]<<8) +
+           (uint32_t)pResult[3];
+}
+
+
+/**
+ @brief Get a uint64_t out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The uint64_t
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a uint64_t and eight bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *me)
+{
+   const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint64_t));
+
+   if(!pResult) {
+      return 0;
+   }
+
+   return   ((uint64_t)pResult[0]<<56) +
+            ((uint64_t)pResult[1]<<48) +
+            ((uint64_t)pResult[2]<<40) +
+            ((uint64_t)pResult[3]<<32) +
+            ((uint64_t)pResult[4]<<24) +
+            ((uint64_t)pResult[5]<<16) +
+            ((uint64_t)pResult[6]<<8)  +
+            (uint64_t)pResult[7];
+}
+
+
+/**
+ @brief Get a float out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The float
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a float and four bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *me)
+{
+   uint32_t uResult = UsefulInputBuf_GetUint32(me);
+
+   return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
+}
+
+/**
+ @brief Get a double out of the input buffer
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The double
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a double and eight bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *me)
+{
+   uint64_t uResult = UsefulInputBuf_GetUint64(me);
+
+   return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
+}
+
+
+/**
+ @brief Get the error status
+
+ @param[in] me Pointer to the UsefulInputBuf.
+
+ @return The error.
+
+ Zero is success, non-zero is error. Once in the error state, the only
+ way to clear it is to call Init again.
+
+ You may be able to only check the error state at the end after all
+ the Get()'s have been done, but if what you get later depends on what
+ you get sooner you cannot. For example if you get a length or count
+ of following items you will have to check the error.
+
+ */
+static inline int UsefulInputBuf_GetError(UsefulInputBuf *me)
+{
+   return me->err;
+}
+
+
+#endif  // _UsefulBuf_h
+
+
diff --git a/lib/ext/qcbor/inc/qcbor.h b/lib/ext/qcbor/inc/qcbor.h
new file mode 100644
index 0000000..3011cc6
--- /dev/null
+++ b/lib/ext/qcbor/inc/qcbor.h
@@ -0,0 +1,2597 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+
+/*===================================================================================
+ FILE:  qcbor.h
+
+ DESCRIPTION:  This is the full public API and data structures for QCBOR
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when               who             what, where, why
+ --------           ----            ---------------------------------------------------
+ 12/18/18           llundblade      Move decode malloc optional code to separate repository
+ 12/13/18           llundblade      Documentatation improvements
+ 11/29/18           llundblade      Rework to simpler handling of tags and labels.
+ 11/9/18            llundblade      Error codes are now enums.
+ 11/1/18            llundblade      Floating support.
+ 10/31/18           llundblade      Switch to one license that is almost BSD-3.
+ 10/15/18           llundblade      Indefinite length maps and arrays supported
+ 10/8/18            llundblade      Indefinite length strings supported
+ 09/28/18           llundblade      Added bstr wrapping feature for COSE implementation.
+ 07/05/17           llundbla        Add bstr wrapping of maps/arrays for COSE.
+ 03/01/17           llundbla        More data types; decoding improvements and fixes.
+ 11/13/16           llundbla        Integrate most TZ changes back into github version.
+ 09/30/16           gkanike         Porting to TZ.
+ 03/15/16           llundbla        Initial Version.
+
+ =====================================================================================*/
+
+#ifndef __QCBOR__qcbor__
+#define __QCBOR__qcbor__
+
+/*...... This is a ruler that is 80 characters long...........................*/
+
+/* ===========================================================================
+   BEGINNING OF PRIVATE PART OF THIS FILE
+
+   Caller of QCBOR should not reference any of the details below up until
+   the start of the public part.
+   =========================================================================== */
+
+/*
+ Standard integer types are used in the interface to be precise about
+ sizes to be better at preventing underflow/overflow errors.
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include "UsefulBuf.h"
+
+
+/*
+ The maxium nesting of arrays and maps when encoding or decoding.
+ (Further down in the file there is a definition that refers to this
+ that is public. This is done this way so there can be a nice
+ separation of public and private parts in this file.
+*/
+#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255
+
+
+/* The largest offset to the start of an array or map. It is slightly
+ less than UINT32_MAX so the error condition can be tests on 32-bit machines.
+ UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t.
+
+ This will cause trouble on a machine where size_t is less than 32-bits.
+ */
+#define QCBOR_MAX_ARRAY_OFFSET  (UINT32_MAX - 100)
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Holds the data for tracking array and map nesting during encoding. Pairs up with
+ the Nesting_xxx functions to make an "object" to handle nesting encoding.
+
+ uStart is a uint32_t instead of a size_t to keep the size of this
+ struct down so it can be on the stack without any concern.  It would be about
+ double if size_t was used instead.
+
+ Size approximation (varies with CPU/compiler):
+    64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
+    32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
+*/
+typedef struct __QCBORTrackNesting {
+   // PRIVATE DATA STRUCTURE
+   struct {
+      // See function OpenArrayInternal() for detailed comments on how this works
+      uint32_t  uStart;     // uStart is the byte position where the array starts
+      uint16_t  uCount;     // Number of items in the arrary or map; counts items in a map, not pairs of items
+      uint8_t   uMajorType; // Indicates if item is a map or an array
+   } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
+   *pCurrentNesting; // the current nesting level
+} QCBORTrackNesting;
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Context / data object for encoding some CBOR. Used by all encode functions to
+ form a public "object" that does the job of encdoing.
+
+ Size approximation (varies with CPU/compiler):
+   64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
+   32-bit machine: 15 + 1 + 132 = 148 bytes
+*/
+struct _QCBOREncodeContext {
+   // PRIVATE DATA STRUCTURE
+   UsefulOutBuf      OutBuf;  // Pointer to output buffer, its length and position in it
+   uint8_t           uError;  // Error state
+   QCBORTrackNesting nesting; // Keep track of array and map nesting
+};
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Holds the data for array and map nesting for decoding work. This structure
+ and the DecodeNesting_xxx functions form an "object" that does the work
+ for arrays and maps.
+
+ Size approximation (varies with CPU/compiler):
+   64-bit machine: 4 * 16 + 8 = 72
+   32-bit machine: 4 * 16 + 4 = 68
+ */
+typedef struct __QCBORDecodeNesting  {
+  // PRIVATE DATA STRUCTURE
+   struct {
+      uint16_t uCount;
+      uint8_t  uMajorType;
+   } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1],
+   *pCurrent;
+} QCBORDecodeNesting;
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ The decode context. This data structure plus the public QCBORDecode_xxx
+ functions form an "object" that does CBOR decoding.
+
+ Size approximation (varies with CPU/compiler):
+   64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 = 128 bytes
+   32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8  = 68 bytes
+ */
+struct _QCBORDecodeContext {
+   // PRIVATE DATA STRUCTURE
+   UsefulInputBuf InBuf;
+
+   uint8_t        uDecodeMode;
+   uint8_t        bStringAllocateAll;
+
+   QCBORDecodeNesting nesting;
+
+   // This is NULL or points to a QCBORStringAllocator. It is void
+   // here because _QCBORDecodeContext is defined early in the
+   // private part of this file and QCBORStringAllocat is defined
+   // later in the public part of this file.
+   void *pStringAllocator;
+
+   // This is NULL or points to QCBORTagList.
+   // It is type void for the same reason as above.
+   const void *pCallerConfiguredTagList;
+};
+
+// Used internally in the impementation here
+// Must not conflict with any of the official CBOR types
+#define CBOR_MAJOR_NONE_TYPE_RAW  9
+#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
+
+
+/* ===========================================================================
+   END OF PRIVATE PART OF THIS FILE
+
+   BEGINNING OF PUBLIC PART OF THIS FILE
+   =========================================================================== */
+
+
+
+/* ===========================================================================
+   BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
+
+   It is not necessary to use these directly when encoding or decoding
+   CBOR with this implementation.
+   =========================================================================== */
+
+/* Standard CBOR Major type for positive integers of various lengths */
+#define CBOR_MAJOR_TYPE_POSITIVE_INT 0
+
+/* Standard CBOR Major type for negative integer of various lengths */
+#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1
+
+/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */
+#define CBOR_MAJOR_TYPE_BYTE_STRING  2
+
+/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8
+ with no encoding and no NULL termination */
+#define CBOR_MAJOR_TYPE_TEXT_STRING  3
+
+/* Standard CBOR Major type for an ordered array of other CBOR data items */
+#define CBOR_MAJOR_TYPE_ARRAY        4
+
+/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The
+ first item in the pair is the "label" (key, name or identfier) and the second
+ item is the value.  */
+#define CBOR_MAJOR_TYPE_MAP          5
+
+/* Standard CBOR optional tagging. This tags things like dates and URLs */
+#define CBOR_MAJOR_TYPE_OPTIONAL     6
+
+/* Standard CBOR extra simple types like floats and the values true and false */
+#define CBOR_MAJOR_TYPE_SIMPLE       7
+
+
+/*
+ These are special values for the AdditionalInfo bits that are part of the first byte.
+ Mostly they encode the length of the data item.
+ */
+#define LEN_IS_ONE_BYTE    24
+#define LEN_IS_TWO_BYTES   25
+#define LEN_IS_FOUR_BYTES  26
+#define LEN_IS_EIGHT_BYTES 27
+#define ADDINFO_RESERVED1  28
+#define ADDINFO_RESERVED2  29
+#define ADDINFO_RESERVED3  30
+#define LEN_IS_INDEFINITE  31
+
+
+/*
+ 24 is a special number for CBOR. Integers and lengths
+ less than it are encoded in the same byte as the major type
+ */
+#define CBOR_TWENTY_FOUR   24
+
+
+/*
+ Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These are
+ the ones defined in the CBOR spec.
+ */
+/** See QCBOREncode_AddDateString() below */
+#define CBOR_TAG_DATE_STRING    0
+/** See QCBOREncode_AddDateEpoch_2() */
+#define CBOR_TAG_DATE_EPOCH     1
+#define CBOR_TAG_POS_BIGNUM     2
+#define CBOR_TAG_NEG_BIGNUM     3
+#define CBOR_TAG_FRACTION       4
+#define CBOR_TAG_BIGFLOAT       5
+
+#define CBOR_TAG_COSE_ENCRYPTO 16
+#define CBOR_TAG_COSE_MAC0     17
+#define CBOR_TAG_COSE_SIGN1    18
+
+/* The data in byte string should be converted in base 64 URL when encoding in JSON or similar text-based representations */
+#define CBOR_TAG_ENC_AS_B64URL 21
+/* The data in byte string should be encoded in base 64 when encoding in JSON */
+#define CBOR_TAG_ENC_AS_B64    22
+/* The data in byte string should be encoded in base 16 when encoding in JSON */
+#define CBOR_TAG_ENC_AS_B16    23
+#define CBOR_TAG_CBOR          24
+/** The data in the string is a URIs, as defined in RFC3986 */
+#define CBOR_TAG_URI           32
+/** The data in the string is a base 64'd URL */
+#define CBOR_TAG_B64URL        33
+/** The data in the string is base 64'd */
+#define CBOR_TAG_B64           34
+/** regular expressions in Perl Compatible Regular Expressions (PCRE) / JavaScript syntax ECMA262. */
+#define CBOR_TAG_REGEX         35
+/** MIME messages (including all headers), as defined in RFC2045 */
+#define CBOR_TAG_MIME          36
+/** Binary UUID */
+#define CBOR_TAG_BIN_UUID      37
+
+#define CBOR_TAG_CWT           61
+
+#define CBOR_TAG_ENCRYPT       96
+#define CBOR_TAG_MAC           97
+#define CBOR_TAG_SIGN          98
+
+#define CBOR_TAG_GEO_COORD    103
+
+
+/** The data is CBOR data */
+#define CBOR_TAG_CBOR_MAGIC 55799
+#define CBOR_TAG_NONE  UINT64_MAX
+
+
+/*
+ Values for the 5 bits for items of major type 7
+ */
+#define CBOR_SIMPLEV_FALSE   20
+#define CBOR_SIMPLEV_TRUE    21
+#define CBOR_SIMPLEV_NULL    22
+#define CBOR_SIMPLEV_UNDEF   23
+#define CBOR_SIMPLEV_ONEBYTE 24
+#define HALF_PREC_FLOAT      25
+#define SINGLE_PREC_FLOAT    26
+#define DOUBLE_PREC_FLOAT    27
+#define CBOR_SIMPLE_BREAK    31
+
+
+
+/* ===========================================================================
+
+ END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
+
+ BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER
+
+ =========================================================================== */
+
+/**
+
+ @file qcbor.h
+
+ Q C B O R   E n c o d e / D e c o d e
+
+ This implements CBOR -- Concise Binary Object Representation as defined
+ in RFC 7049. More info is at http://cbor.io.  This is a near-complete
+ implementation of the specification. Limitations are listed further down.
+
+ CBOR is intentionally designed to be translatable to JSON, but not
+ all CBOR can convert to JSON. See RFC 7049 for more info on how to
+ construct CBOR that is the most JSON friendly.
+
+ The memory model for encoding and decoding is that encoded CBOR
+ must be in a contiguous buffer in memory.  During encoding the
+ caller must supply an output buffer and if the encoding would go
+ off the end of the buffer an error is returned.  During decoding
+ the caller supplies the encoded CBOR in a contiguous buffer
+ and the decoder returns pointers and lengths into that buffer
+ for strings.
+
+ This implementation does not require malloc. All data structures
+ passed in/out of the APIs can fit on the stack.
+
+ Decoding of indefinite length strings is a special case that requires
+ a "string allocator" to allocate memory into which the segments of
+ the string are coalesced. Without this, decoding will error out if
+ an indefinite length string is encountered (indefinite length maps
+ and arrays do not require the string allocator). A simple string
+ allocator called MemPool is built-in and will work if supplied with
+ a block of memory to allocate. The string allocator can optionally
+ use malloc() or some other custom scheme.
+
+ Here are some terms and definitions:
+
+ - "Item", "Data Item": An integer or string or such. The basic "thing" that
+ CBOR is about. An array is an item itself that contains some items.
+
+ - "Array": An ordered sequence of items, the same as JSON.
+
+ - "Map": A collection of label/value pairs. Each pair is a data
+ item. A JSON "object" is the same as a CBOR "map".
+
+ - "Label": The data item in a pair in a map that names or identifies the
+ pair, not the value. This implementation refers to it as a "label".
+ JSON refers to it as the "name". The CBOR RFC refers to it this as a "key".
+ This implementation chooses label instead because key is too easily confused
+ with a cryptographic key. The COSE standard, which uses CBOR, has also
+ chosen to use the term "label" rather than "key" for this same reason.
+
+ - "Key": See "Label" above.
+
+ - "Tag": Optional info that can be added before each data item. This is always
+ CBOR major type 6.
+
+ - "Initial Byte": The first byte of an encoded item. Encoding and decoding of
+ this byte is taken care of by the implementation.
+
+ - "Additional Info": In addition to the major type, all data items have some
+ other info. This is usually the length of the data, but can be several
+ other things. Encoding and decoding of this is taken care of by the
+ implementation.
+
+ CBOR has two mechanisms for tagging and labeling the data
+ values like integers and strings. For example, an integer that
+ represents someone's birthday in epoch seconds since Jan 1, 1970
+ could be encoded like this:
+
+ - First it is CBOR_MAJOR_TYPE_POSITIVE_INT, the primitive positive
+ integer.
+ - Next it has a "tag" CBOR_TAG_DATE_EPOCH indicating the integer
+ represents a date in the form of the number of seconds since
+ Jan 1, 1970.
+ - Last it has a string "label" like "BirthDate" indicating
+ the meaning of the data.
+
+ The encoded binary looks like this:
+   a1                      # Map of 1 item
+      69                   # Indicates text string of 9 bytes
+        426972746844617465 # The text "BirthDate"
+     c1                    # Tags next int as epoch date
+        1a                 # Indicates 4 byte integer
+            580d4172       # unsigned integer date 1477263730
+
+ Implementors using this API will primarily work with labels. Generally
+ tags are only needed for making up new data types. This implementation
+ covers most of the data types defined in the RFC using tags. It also,
+ allows for the creation of news tags if necessary.
+
+ This implementation explicitly supports labels that are text strings
+ and integers. Text strings translate nicely into JSON objects and
+ are very readable.  Integer labels are much less readable, but
+ can be very compact. If they are in the range of -23 to
+ 23 they take up only one byte.
+
+ CBOR allows a label to be any type of data including an array or
+ a map. It is possible to use this API to construct and
+ parse such labels, but it is not explicitly supported.
+
+ A common encoding usage mode is to invoke the encoding twice. First
+ with no output buffer to compute the length of the needed output
+ buffer. Then the correct sized output buffer is allocated. Last the
+ encoder is invoked again, this time with the output buffer.
+
+ The double invocation is not required if the max output buffer size
+ can be predicted. This is usually possible for simple CBOR structures.
+ If the double invocation is implemented, it can be
+ in a loop or function as in the example code so that the code doesn't
+ have to actually be written twice, saving code size.
+
+ If a buffer too small to hold the encoded output is given, the error
+ QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be
+ written off the end of the output buffer no matter which functions
+ here are called or what parameters are passed to them.
+
+ The error handling is simple. The only possible errors are trying to
+ encode structures that are too large or too complex. There are no
+ internal malloc calls so there will be no failures for out of memory.
+ Only the final call, QCBOREncode_Finish(), returns an error code.
+ Once an error happens, the encoder goes into an error state and calls
+ to it will do nothing so the encoding can just go on. An error
+ check is not needed after every data item is added.
+
+ Encoding generally proceeds by calling QCBOREncode_Init(), calling
+ lots of "Add" functions and calling QCBOREncode_Finish(). There
+ are many "Add" functions for various data types. The input
+ buffers need only to be valid during the "Add" calls. The
+ data is copied into the output buf during the "Add" call.
+
+ There are three `Add` functions for each data type. The first
+ / main one for the type is for adding the data item to an array.
+ The second one's name ends in `ToMap`, is used for adding
+ data items to maps and takes a string
+ argument that is its label in the map. The third one ends in
+ `ToMapN`, is also used for adding data items to maps, and
+ takes an integer argument that is its label in the map.
+
+ The simplest aggregate type is an array, which is a simple ordered
+ set of items without labels the same as JSON arrays. Call
+ QCBOREncode_OpenArray() to open a new array, then "Add" to
+ put items in the array and then QCBOREncode_CloseArray(). Nesting
+ to a limit is allowed.  All opens must be matched by closes or an
+ encoding error will be returned.
+
+ The other aggregate type is a map which does use labels. The
+ `Add` functions that end in `ToMap` and `ToMapN` are convenient
+ ways to add labeled data items to a map. You can also call
+ any type of `Add` function once to add a label of any time and
+ then call any type of `Add` again to add its value.
+
+ Note that when you nest arrays or maps in a map, the nested
+ array or map has a label.
+
+ Usually it is not necessary to add tags explicitly as most
+ tagged types have functions here, but they can be added by
+ calling QCBOREncode_AddTag().  There is an IANA registry for new tags that are
+ for broad use and standardization as per RFC 7049. It is also
+ allowed for protocols to make up new tags in the range above 256.
+ Note that even arrays and maps can be tagged.
+
+ Summary Limits of this implementation:
+ - The entire encoded CBOR must fit into contiguous memory.
+ - Max size of encoded / decoded CBOR data is UINT32_MAX (4GB).
+ - Max array / map nesting level when encoding / decoding is
+   QCBOR_MAX_ARRAY_NESTING (this is typically 15).
+ - Max items in an array or map when encoding / decoding is
+   QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
+ - Does not support encoding indefinite lengths (decoding is supported).
+ - Does not directly support some tagged types: decimal fractions, big floats
+ - Does not directly support labels in maps other than text strings and ints.
+ - Does not directly support int labels greater than INT64_MAX
+ - Epoch dates limited to INT64_MAX (+/- 292 billion years)
+ - Tags on labels are ignored during decoding
+
+ This implementation is intended to run on 32 and 64-bit CPUs. Minor
+ modifications are needed for it to work on 16-bit CPUs.
+
+ The public interface uses 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 UINT32_MAX (4GB) which should be
+ enough.
+
+ This implementation assumes two's compliment integer
+ machines. Stdint.h also requires this. It of course would be easy to
+ fix this implementation for another integer representation, but all
+ modern machines seem to be two's compliment.
+
+ */
+
+
+/**
+ The maximum number of items in a single array or map when encoding of decoding.
+*/
+// -1 is because the value UINT16_MAX is used to track indefinite length arraysUINT16_MAX
+#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1)
+
+/**
+ The maximum nesting of arrays and maps when encoding or decoding. The
+ error QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on encoding
+ of decoding if it is exceeded
+*/
+#define QCBOR_MAX_ARRAY_NESTING  QCBOR_MAX_ARRAY_NESTING1
+
+/**
+ The maximum number of tags that can be in QCBORTagListIn and passed to
+ QCBORDecode_SetCallerConfiguredTagList()
+ */
+#define QCBOR_MAX_CUSTOM_TAGS    16
+
+
+typedef enum {
+   /** The encode or decode completely correctly. */
+   QCBOR_SUCCESS = 0,
+
+   /** The buffer provided for the encoded output when doing encoding was
+       too small and the encoded output will not fit. Also, when the buffer
+       given to QCBORDecode_SetMemPool() is too small. */
+   QCBOR_ERR_BUFFER_TOO_SMALL,
+
+   /** During encoding or decoding, the array or map nesting was deeper than
+    this implementation can handle. Note that in the interest of code size
+    and memory use, this implementation has a hard limit on array nesting. The
+    limit is defined as the constant QCBOR_MAX_ARRAY_NESTING. */
+   QCBOR_ERR_ARRAY_NESTING_TOO_DEEP,
+
+   /** During decoding or encoding, the array or map had too many items in it.
+       This limit QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,535. */
+   QCBOR_ERR_ARRAY_TOO_LONG,
+
+   /** During encoding, more arrays or maps were closed than opened. This is a
+       coding error on the part of the caller of the encoder. */
+   QCBOR_ERR_TOO_MANY_CLOSES,
+
+   /** During decoding, some CBOR construct was encountered that this decoder
+        doesn't support, primarily this is the reserved additional info values,
+        28 through 30. */
+   QCBOR_ERR_UNSUPPORTED,
+
+   /** During decoding, hit the end of the given data to decode. For example,
+       a byte string of 100 bytes was expected, but the end of the input was
+       hit before finding those 100 bytes.  Corrupted CBOR input will often
+       result in this error. */
+   QCBOR_ERR_HIT_END,
+
+   /** During encoding, the length of the encoded CBOR exceeded UINT32_MAX.
+     */
+   QCBOR_ERR_BUFFER_TOO_LARGE,
+
+   /** During decoding, an integer smaller than INT64_MIN was received (CBOR
+       can represent integers smaller than INT64_MIN, but C cannot). */
+   QCBOR_ERR_INT_OVERFLOW,
+
+   /** During decoding, the label for a map entry is bad. What causes this
+       error depends on the decoding mode. */
+   QCBOR_ERR_MAP_LABEL_TYPE,
+
+   /** During encoding or decoding, the number of array or map opens was not
+       matched by the number of closes. */
+   QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN,
+
+   /** During encoding, the simple value is not between CBOR_SIMPLEV_FALSE
+       and CBOR_SIMPLEV_UNDEF. */
+   QCBOR_ERR_BAD_SIMPLE,
+
+   /** During decoding, a date greater than +- 292 billion years from Jan 1
+       1970 encountered during parsing. */
+   QCBOR_ERR_DATE_OVERFLOW,
+
+   /** During decoding, the CBOR is not valid, primarily a simple type is encoded in
+      a prohibited way. */
+   QCBOR_ERR_INVALID_CBOR,
+
+   /** Optional tagging that doesn't make sense (an int is tagged as a
+       date string) or can't be handled. */
+   QCBOR_ERR_BAD_OPT_TAG,
+
+   /** Returned by QCBORDecode_Finish() if all the inputs bytes have not
+       been consumed. */
+   QCBOR_ERR_EXTRA_BYTES,
+
+   /** During encoding, QCBOREncode_Close() call with a different type than
+       is currently open. */
+   QCBOR_ERR_CLOSE_MISMATCH,
+
+   /** Unable to decode an indefinite length string because no string
+       allocator was configured. */
+   QCBOR_ERR_NO_STRING_ALLOCATOR,
+
+   /** One of the chunks in an indefinite length string is not of the type of
+       the string. */
+   QCBOR_ERR_INDEFINITE_STRING_CHUNK,
+
+   /** Error allocating space for a string, usually for an indefinite length
+       string. */
+   QCBOR_ERR_STRING_ALLOCATE,
+
+   /** During decoding, a break occurred outside an indefinite length item. */
+   QCBOR_ERR_BAD_BREAK,
+
+   /** During decoding, too many tags in the caller-configured tag list, or not
+       enough space in QCBORTagListOut. */
+   QCBOR_ERR_TOO_MANY_TAGS,
+
+   /** Returned by QCBORDecode_SetMemPool() when xx is too small. This should
+       never happen on a machine with 64-bit or smaller pointers. Fixing
+       it is probably by increasing QCBOR_DECODE_MIN_MEM_POOL_SIZE. */
+   QCBOR_ERR_MEM_POOL_INTERNAL
+
+} QCBORError;
+
+
+typedef enum {
+   /** See QCBORDecode_Init() */
+   QCBOR_DECODE_MODE_NORMAL = 0,
+   /** See QCBORDecode_Init() */
+   QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
+   /** See QCBORDecode_Init() */
+   QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
+} QCBORDecodeMode;
+
+
+
+
+
+/* Do not renumber these. Code depends on some of these values. */
+/** The type is unknown, unset or invalid */
+#define QCBOR_TYPE_NONE           0
+/** Type for an integer that decoded either between INT64_MIN and INT32_MIN or INT32_MAX and INT64_MAX; val.int64 */
+#define QCBOR_TYPE_INT64          2
+/** Type for an integer that decoded to a more than INT64_MAX and UINT64_MAX; val.uint64 */
+#define QCBOR_TYPE_UINT64         3
+/** Type for an array. The number of items in the array is in val.uCount. */
+#define QCBOR_TYPE_ARRAY          4
+/** Type for a map; number of items in map is in val.uCount */
+#define QCBOR_TYPE_MAP            5
+/** Type for a buffer full of bytes. Data is in val.string. */
+#define QCBOR_TYPE_BYTE_STRING    6
+/** Type for a UTF-8 string. It is not NULL terminated. Data is in val.string.  */
+#define QCBOR_TYPE_TEXT_STRING    7
+/** Type for a positive big number. Data is in val.bignum, a pointer and a length. */
+#define QCBOR_TYPE_POSBIGNUM     9
+/** Type for a negative big number. Data is in val.bignum, a pointer and a length. */
+#define QCBOR_TYPE_NEGBIGNUM     10
+/** Type for RFC 3339 date string, possibly with time zone. Data is in val.dateString */
+#define QCBOR_TYPE_DATE_STRING   11
+/** Type for integer seconds since Jan 1970 + floating point fraction. Data is in val.epochDate */
+#define QCBOR_TYPE_DATE_EPOCH    12
+/** A simple type that this CBOR implementation doesn't know about; Type is in val.uSimple. */
+#define QCBOR_TYPE_UKNOWN_SIMPLE 13
+/** Type for the simple value false; nothing more; nothing in val union. */
+#define QCBOR_TYPE_FALSE         20
+/** Type for the simple value true; nothing more; nothing in val union. */
+#define QCBOR_TYPE_TRUE          21
+/** Type for the simple value null; nothing more; nothing in val union. */
+#define QCBOR_TYPE_NULL          22
+/** Type for the simple value undef; nothing more; nothing in val union. */
+#define QCBOR_TYPE_UNDEF         23
+/** Type for a floating point number. Data is in val.float. */
+#define QCBOR_TYPE_FLOAT         26
+/** Type for a double floating point number. Data is in val.double. */
+#define QCBOR_TYPE_DOUBLE        27
+/** For QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is being traversed as an array. See QCBORDecode_Init() */
+#define QCBOR_TYPE_MAP_AS_ARRAY  32
+
+#define QCBOR_TYPE_BREAK         31 // Used internally; never returned
+
+#define QCBOR_TYPE_OPTTAG       254 // Used internally; never returned
+
+
+
+/*
+ Approx Size of this:
+   8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding on 64-bit machine) = 24 for first part (20 on a 32-bit machine)
+   16 bytes for the val union
+   16 bytes for label union
+   total = 56 bytes (52 bytes on 32-bit machine)
+ */
+
+/**
+ QCBORItem holds the type, value and other info for a decoded item returned by GetNextItem().
+ */
+typedef struct _QCBORItem {
+   uint8_t  uDataType;     /** Tells what element of the val union to use. One of QCBOR_TYPE_XXXX */
+   uint8_t  uNestingLevel; /** How deep the nesting from arrays and maps are. 0 is the top level with no arrays or maps entered */
+   uint8_t  uLabelType;    /** Tells what element of the label union to use */
+   uint8_t  uDataAlloc;    /** 1 if allocated with string allocator, 0 if not. See QCBORDecode_MakeMallocStringAllocator() */
+   uint8_t  uLabelAlloc;   /** Like uDataAlloc, but for label */
+   uint8_t  uNextNestLevel; /** If not equal to uNestingLevel, this item closed out at least one map/array */
+
+   union {
+      int64_t     int64;      /** The value for uDataType QCBOR_TYPE_INT64 */
+      uint64_t    uint64;     /** The value for uDataType QCBOR_TYPE_UINT64 */
+
+      UsefulBufC  string;     /** The value for uDataType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */
+      uint16_t    uCount;     /** The "value" for uDataType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP -- the number of items in the array or map
+                                  UINT16_MAX when decoding indefinite lengths maps and arrays. */
+      double      dfnum;      /** The value for uDataType QCBOR_TYPE_DOUBLE */
+      struct {
+         int64_t  nSeconds;
+         double   fSecondsFraction;
+      } epochDate;            /** The value for uDataType QCBOR_TYPE_DATE_EPOCH */
+      UsefulBufC  dateString; /** The value for uDataType QCBOR_TYPE_DATE_STRING */
+      UsefulBufC  bigNum;     /** The value for uDataType QCBOR_TYPE_BIGNUM */
+      uint8_t     uSimple;    /** The integer value for unknown simple types */
+      uint64_t    uTagV;
+
+   } val;  /** The union holding the item's value. Select union member based on uDataType */
+
+   union {
+      UsefulBufC  string;  /** The label for uLabelType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */
+      int64_t     int64;   /** The label for uLabelType for QCBOR_TYPE_INT64 */
+      uint64_t    uint64;  /** The label for uLabelType for QCBOR_TYPE_UINT64 */
+   } label; /** Union holding the different label types selected based on uLabelType */
+
+   uint64_t uTagBits; /** Bit indicating which tags (major type 6) on this item.  */
+
+} QCBORItem;
+
+
+/**
+ This is a set of functions and pointer context (in object-oriented parlance,
+ an "object") used to allocate memory for coalescing the segments of an indefinite
+ length string into one.
+
+ The fAllocate function works as an initial allocator and a reallocator to
+ expand the string for each new segment. When it is an initial allocator
+ pOldMem is NULL.
+
+ The fFree function is called to clean up an individual allocation when an error occurs.
+
+ The fDesctructor function is called when QCBORDecode_Finish is called.
+
+ Any memory allocated with this will be marked by setting uDataAlloc
+ or uLabelAlloc in the QCBORItem structure so the caller knows they
+ have to free it.
+
+ fAllocate is only ever called to increase the single most recent
+ allocation made, making implementation of a memory pool very simple.
+
+ fFree is also only called on the single most recent allocation.
+ */
+typedef struct {
+   void       *pAllocaterContext;
+   UsefulBuf (*fAllocate)(void *pAllocaterContext, void *pOldMem, size_t uNewSize);
+   void      (*fFree)(void *pAllocaterContext, void *pMem);
+   void      (*fDestructor)(void *pAllocaterContext);
+} QCBORStringAllocator;
+
+
+/**
+ This only matters if you use a string allocator
+ and and set it up with QCBORDecode_SetMemPool(). It is
+ the size of the overhead needed needed by
+ QCBORDecode_SetMemPool().  If you write your own
+ string allocator or use the separately available malloc
+ based string allocator, this size will not apply
+ */
+#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 72
+
+
+/**
+ This is used to tell the decoder about tags that it should
+ record in uTagBits in QCBORItem beyond the built-in
+ tags. puTags points to an
+ array of uint64_t integers that are the tags. uNumTags
+ is the number of integers in the array. The maximum
+ size is QCBOR_MAX_CUSTOM_TAGS.  See QCBORDecode_IsTagged()
+ and QCBORDecode_SetCallerAddedTagMap().
+ */
+typedef struct {
+   uint8_t uNumTags;
+   const uint64_t *puTags;
+} QCBORTagListIn;
+
+
+/**
+ This is for QCBORDecode_GetNextWithTags() to be able to return the
+ full list of tags on an item. It not needed for most CBOR protocol
+ implementations. Its primary use is for pretty-printing CBOR or
+ protocol conversion to another format.
+
+ On input, puTags points to a buffer to be filled in
+ and uNumAllocated is the number of uint64_t values
+ in the buffer.
+
+ On output the buffer contains the tags for the item.
+ uNumUsed tells how many there are.
+ */
+typedef struct {
+   uint8_t uNumUsed;
+   uint8_t uNumAllocated;
+   uint64_t *puTags;
+} QCBORTagListOut;
+
+
+/**
+ QCBOREncodeContext is the data type that holds context for all the
+ encoding functions. It is less than 200 bytes, so it can go on
+ the stack. The contents are opaque, and the caller should not access
+ any internal items.  A context may be re used serially as long as
+ it is re initialized.
+ */
+typedef struct _QCBOREncodeContext QCBOREncodeContext;
+
+
+/**
+ Initialize the the encoder to prepare to encode some CBOR.
+
+ @param[in,out]  pCtx    The encoder context to initialize.
+ @param[in]      Storage The buffer into which this encoded result will be placed.
+
+ Call this once at the start of an encoding of a CBOR structure. Then
+ call the various QCBOREncode_AddXXX() functions to add the data
+ items. Then call QCBOREncode_Finish().
+
+ The maximum output buffer is UINT32_MAX (4GB). This is not a practical
+ limit in any way and reduces the memory needed by the implementation.
+ The error QCBOR_ERR_BUFFER_TOO_LARGE will be returned by QCBOR_Finish()
+ if a larger buffer length is passed in.
+
+ If this is called with pBuf as NULL and uBufLen a large value like
+ UINT32_MAX, all the QCBOREncode_AddXXXX() functions and
+ QCBORE_Encode_Finish() can still be called. No data will be encoded,
+ but the length of what would be encoded will be calculated. The
+ length of the encoded structure will be handed back in the call to
+ QCBOREncode_Finish(). You can then allocate a buffer of that size
+ and call all the encoding again, this time to fill in the buffer.
+
+ A QCBORContext can be reused over and over as long as
+ QCBOREncode_Init() is called.
+ */
+void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage);
+
+
+/**
+ @brief  Add a signed 64-bit integer to the encoded output.
+
+ @param[in] pCtx      The encoding context to add the integer to.
+ @param[in] nNum      The integer to add.
+
+ The integer will be encoded and added to the CBOR output.
+
+ This function figures out the size and the sign and encodes in the
+ correct minimal CBOR. Specifically, it will select CBOR major type 0 or 1
+ based on sign and will encode to 1, 2, 4 or 8 bytes depending on the
+ value of the integer. Values less than 24 effectively encode to one
+ byte because they are encoded in with the CBOR major type.  This is
+ a neat and efficient characteristic of CBOR that can be taken
+ advantage of when designing CBOR-based protocols. If integers like
+ tags can be kept between -23 and 23 they will be encoded in one byte
+ including the major type.
+
+ If you pass a smaller int, say an int16_t or a small value, say 100,
+ the encoding will still be CBOR's most compact that can represent the
+ value.  For example, CBOR always encodes the value 0 as one byte,
+ 0x00. The representation as 0x00 includes identification of the type
+ as an integer too as the major type for an integer is 0. See RFC 7049
+ Appendix A for more examples of CBOR encoding. This compact encoding
+ is also canonical CBOR as per section 3.9 in RFC 7049.
+
+ There are no functions to add int16_t or int32_t because they are
+ not necessary because this always encodes to the smallest number
+ of bytes based on the value (If this code is running on a 32-bit
+ machine having a way to add 32-bit integers would reduce code size some).
+
+ If the encoding context is in an error state, this will do
+ nothing. If an error occurs when adding this integer, the internal
+ error flag will be set, and the error will be returned when
+ QCBOREncode_Finish() is called.
+
+ See also QCBOREncode_AddUInt64().
+ */
+void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum);
+
+static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum);
+
+static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum);
+
+
+/**
+ @brief  Add an unsigned 64-bit integer to the encoded output.
+
+ @param[in] pCtx      The encoding context to add the integer to.
+ @param[in] uNum      The integer to add.
+
+ The integer will be encoded and added to the CBOR output.
+
+ The only reason so use this function is for integers larger than
+ INT64_MAX and smaller than UINT64_MAX. Otherwise QCBOREncode_AddInt64()
+ will work fine.
+
+ Error handling is the same as for QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
+
+static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
+
+static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum);
+
+
+/**
+
+ @brief  Add a UTF-8 text string to the encoded output
+
+ @param[in] pCtx     The context to initialize.
+ @param[in] Text    Pointer and length of text to add.
+
+ The text passed in must be unencoded UTF-8 according to RFC
+ 3629. There is no NULL termination. The text is added as CBOR
+ major type 3.
+
+ If called with nBytesLen equal to 0, an empty string will be
+ added. When nBytesLen is 0, pBytes may be NULL.
+
+ Note that the restriction of the buffer length to an uint32_t is
+ entirely intentional as this encoder is not capable of encoding
+ lengths greater. This limit to 4GB for a text string should not be a
+ problem.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text);
+
+static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text);
+
+static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text);
+
+
+/**
+ @brief  Add a UTF-8 text string to the encoded output
+
+ @param[in] pCtx      The context to initialize.
+ @param[in] szString  Null-terminated text to add.
+
+ This works the same as QCBOREncode_AddText().
+ */
+static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString);
+
+static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString);
+
+static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString);
+
+
+/**
+ @brief  Add a floating-point number to the encoded output
+
+ @param[in] pCtx      The encoding context to add the float to.
+ @param[in] dNum      The double precision number to add.
+
+ This outputs a floating-point number with CBOR major type 7.
+
+ This will selectively encode the double-precision floating point
+ number as either double-precision, single-precision or
+ half-precision. It will always encode infinity, NaN and 0 has half
+ precision. If no precision will be lost in the conversion to
+ half-precision then it will be converted and encoded. If not and no
+ precision will be lost in conversion to single-precision, then it
+ will be converted and encoded. If not, then no conversion is
+ performed, and it encoded as a double.
+
+ Half-precision floating point numbers take up 2 bytes, half that of
+ single-precision, one quarter of double-precision
+
+ This automatically reduces the size of encoded messages a lot, maybe
+ even by four if most of values are 0, infinity or NaN.
+
+ On decode, these will always be returned as a double.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
+
+static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum);
+
+static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum);
+
+
+/**
+ @brief[in] Add an optional tag
+
+ @param[in] pCtx  The encoding context to add the integer to.
+ @param[in] uTag  The tag to add
+
+ This outputs a CBOR major type 6 optional tag.
+
+ The tag is applied to the next data item added to the encoded
+ output. That data item that is to be tagged can be of any major
+ CBOR type. Any number of tags can be added to a data item by calling
+ this multiple times before the data item is added.
+
+ For many of the common standard tags a function to encode
+ data using it already exists and this is not needed. For example,
+ QCBOREncode_AddDateEpoch() already exists to output
+ integers representing dates with the right tag.
+*/
+void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag);
+
+
+/**
+ @brief  Add an epoch-based date
+
+ @param[in] pCtx     The encoding context to add the simple value to.
+ @param[in] date     Number of seconds since 1970-01-01T00:00Z in UTC time.
+
+ As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is
+ the most compact way to specify a date and time in CBOR. Note that this
+ is always UTC and does not include the time zone.  Use
+ QCBOREncode_AddDateString() if you want to include the time zone.
+
+ The integer encoding rules apply here so the date will be encoded in a
+ minimal number of 1, 2 4 or 8 bytes. Until about the year 2106 these
+ dates should encode in 6 bytes -- one byte for the tag, one byte for the type
+ and 4 bytes for the integer.
+
+ If you care about leap-seconds and that level of accuracy, make sure the
+ system you are running this code on does it correctly. This code just takes
+ the value passed in.
+
+ This implementation cannot encode fractional seconds using float or double
+ even though that is allowed by CBOR, but you can encode them if you
+ want to by calling QCBOREncode_AddDouble()
+ with the right parameters.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date);
+
+static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date);
+
+static  void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date);
+
+
+/**
+ @brief Add a byte string to the encoded output.
+
+ @param[in] pCtx      The context to initialize.
+ @param[in] Bytes     Pointer and length of the input data.
+
+ Simply adds the bytes to the encoded output as CBOR major type 2.
+
+ If called with Bytes.len equal to 0, an empty string will be
+ added. When Bytes.len is 0, Bytes.ptr may be NULL.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+
+/**
+ @brief Add a binary UUID to the encoded output.
+
+ @param[in] pCtx      The context to initialize.
+ @param[in] Bytes     Pointer and length of the binary UUID.
+
+ A binary UUID as defined in RFC 4122 is added to the ouput.
+
+ It is output as CBOR major type 2, a binary string, with
+ optional tag 36 indicating the binary string is a UUID.
+ */
+static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a positive big number to the encoded output.
+
+ @param[in] pCtx      The context to initialize.
+ @param[in] Bytes     Pointer and length of the big number.
+
+ Big numbers are integers larger than 64-bits. Their format
+ is described in RFC 7049.
+
+ It is output as CBOR major type 2, a binary string, with
+ optional tag 2 indicating the binary string is a positive big
+ number.
+
+ Often big numbers are used to represent cryptographic keys,
+ however, COSE which defines representations for keys chose not
+ to use this particular type.
+ */
+static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a negative big number to the encoded output.
+
+ @param[in] pCtx      The context to initialize.
+ @param[in] Bytes     Pointer and length of the big number.
+
+ Big numbers are integers larger than 64-bits. Their format
+ is described in RFC 7049.
+
+ It is output as CBOR major type 2, a binary string, with
+ optional tag 2 indicating the binary string is a negative big
+ number.
+
+ Often big numbers are used to represent cryptographic keys,
+ however, COSE which defines representations for keys chose not
+ to use this particular type.
+ */
+static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a text URI to the encoded output.
+
+ @param[in] pCtx    The context to initialize.
+ @param[in] URI     Pointer and length of the URI.
+
+ The format of URI is RFC 3986.
+
+ It is output as CBOR major type 3, a text string, with
+ optional tag 32 indicating the text string is a URI.
+ */
+static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI);
+
+static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI);
+
+static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI);
+
+
+/**
+ @brief Add base 64-encoded text to encoded output.
+
+ @param[in] pCtx     The context to initialize.
+ @param[in] B64Text  Pointer and length of the base-64 encoded text.
+
+ The text content is base 64 encoded data per RFC 4648.
+
+ It is output as CBOR major type 3, a text string, with
+ optional tag 34 indicating the text string is a URI.
+ */
+static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
+
+
+/**
+ @brief Add base 64URL -encoded URL to encoded output.
+
+ @param[in] pCtx    The context to initialize.
+ @param[in] B64Text  Pointer and length of the base-64 encoded text.
+
+ The text content is base 64 URL format encoded text as per RFC 4648.
+
+ It is output as CBOR major type 3, a text string, with
+ optional tag 33 indicating the text string is a URI.
+ */
+static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
+
+
+/**
+ @brief Add Perl Compatible Regular Expression
+
+ @param[in] pCtx    The context to initialize.
+ @param[in] Regex   Pointer and length of the regular expression.
+
+ The text content is Perl Compatible Regular
+ Expressions (PCRE) / JavaScript syntax [ECMA262].
+
+ It is output as CBOR major type 3, a text string, with
+ optional tag 35 indicating the text string is a regular expression.
+ */
+static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex);
+
+static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex);
+
+static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex);
+
+
+/**
+ @brief MIME encoded text to the encoded output.
+
+ @param[in] pCtx      The context to initialize.
+ @param[in] MIMEData  Pointer and length of the regular expression.
+
+ The text content is in MIME format per RFC 2045 including the headers.
+
+ It is output as CBOR major type 3, a text string, with
+ optional tag 36 indicating the text string is MIME data.
+ */
+static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData);
+
+static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData);
+
+static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData);
+
+
+/**
+ @brief  Add an RFC 3339 date string
+
+ @param[in] pCtx      The encoding context to add the simple value to.
+ @param[in] szDate    Null-terminated string with date to add
+
+ The string szDate should be in the form of RFC 3339 as defined by section
+ 3.3 in RFC 4287. This is as described in section 2.4.1 in RFC 7049.
+
+ Note that this function doesn't validate the format of the date string
+ at all. If you add an incorrect format date string, the generated
+ CBOR will be incorrect and the receiver may not be able to handle it.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate);
+
+static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate);
+
+static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate);
+
+
+/**
+ @brief  Add a standard boolean.
+
+ @param[in] pCtx   The encoding context to add the simple value to.
+ @param[in] b      true or false from stdbool. Anything will result in an error.
+
+ Adds a boolean value as CBOR major type 7.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b);
+
+static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b);
+
+static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b);
+
+
+
+/**
+ @brief  Add a NULL to the encoded output.
+
+ @param[in] pCtx   The encoding context to add the simple value to.
+
+ Adds the NULL value as CBOR major type 7.
+
+ This NULL doesn't have any special meaning in CBOR such as a terminating
+ value for a string or an empty value.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief  Add an "undef" to the encoded output.
+
+ @param[in] pCtx   The encoding context to add the simple value to.
+
+ Adds the undef value as CBOR major type 7.
+
+ Note that this value will not translate to JSON.
+
+ This Undef doesn't have any special meaning in CBOR such as a terminating
+ value for a string or an empty value.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief  Indicates that the next items added are in an array.
+
+ @param[in] pCtx The encoding context to open the array in.
+
+ Arrays are the basic CBOR aggregate or structure type. Call this
+ function to start or open an array. Then call the various AddXXX
+ functions to add the items that go into the array. Then call
+ QCBOREncode_CloseArray() when all items have been added. The data
+ items in the array can be of any type and can be of mixed types.
+
+ Nesting of arrays and maps is allowed and supported just by calling
+ QCBOREncode_OpenArray() again before calling CloseArray.  While CBOR
+ has no limit on nesting, this implementation does in order to keep it
+ smaller and simpler.  The limit is QCBOR_MAX_ARRAY_NESTING. This is
+ the max number of times this can be called without calling
+ QCBOREncode_CloseArray(). QCBOREncode_Finish() will return
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function
+ just sets an error state and returns no value when this occurs.
+
+ If you try to add more than QCBOR_MAX_ITEMS_IN_ARRAY items to a
+ single array or map, QCBOR_ERR_ARRAY_TOO_LONG will be returned when
+ QCBOREncode_Finish() is called.
+
+ An array itself must have a label if it is being added to a map.
+ Note that array elements do not have labels (but map elements do).
+
+ An array itself may be tagged.
+ */
+static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx,  int64_t nLabel);
+
+
+/**
+ @brief Close an open array.
+
+ @param[in] pCtx The context to add to.
+
+ The closes an array opened by QCBOREncode_OpenArray(). It reduces
+ nesting level by one. All arrays (and maps) must be closed before
+ calling QCBOREncode_Finish().
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_OpenArray(), then
+ QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish()
+ is called.
+
+ If this is called and it is not an array that is currently open,
+ QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
+
+
+/**
+ @brief  Indicates that the next items added are in a map.
+
+ @param[in] pCtx The context to add to.
+
+ See QCBOREncode_OpenArray() for more information, particularly error
+ handling.
+
+ CBOR maps are an aggregate type where each item in the map consists
+ of a label and a value. They are similar to JSON objects.
+
+ The value can be any CBOR type including another map.
+
+ The label can also be any CBOR type, but in practice they are
+ typically, integers as this gives the most compact output. They might
+ also be text strings which gives readability and translation to JSON.
+
+ Every QCBOREncode_AddXXX() call has once version that is "InMap" for
+ adding items to maps with string labels and on that is "InMapN" that
+ is for adding with integer labels.
+
+ RFC 7049 uses the term "key" instead of "label".
+
+ If you wish to use map labels that are neither integer labels or
+ text strings, then just call the QCBOREncode_AddXXX() function
+ explicitly to add the label. Then call it again to add the value.
+
+ See the RFC7049 for a lot more information on creating maps.
+ */
+static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+
+/**
+ @brief Close an open map.
+
+ @param[in] pCtx The context to add to.
+
+ The closes a map opened by QCBOREncode_OpenMap(). It reduces nesting
+ level by one.
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_OpenMap(),
+ then QCBOR_ERR_TOO_MANY_CLOSES will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this is called and it is not a map that is currently
+ open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx);
+
+
+/**
+ @brief Indicate start of encoded CBOR to be wrapped in a bstr.
+
+ @param[in] pCtx The context to add to.
+
+ All added encoded items between this call and a call to
+ QCBOREncode_CloseBstrWrap() will be wrapped in a bstr. They will
+ appear in the final output as a byte string.  That byte string will
+ contain encoded CBOR.
+
+ The typical use case is for encoded CBOR that is to be
+ cryptographically hashed, as part of a COSE (RFC 8152)
+ implementation. This avoids having to encode the items first in one
+ buffer (e.g., the COSE payload) and then add that buffer as a bstr to
+ another encoding (e.g. the COSE to-be-signed bytes, the
+ Sig_structure) potentially saving a lot of memory.
+
+ When constructing cryptographically signed CBOR objects, maps or
+ arrays, they typically are encoded normally and then wrapped as a
+ byte string. The COSE standard for example does this. The wrapping is
+ simply treating the encoded CBOR map as a byte string.
+
+ The stated purpose of this wrapping is to prevent code relaying the
+ signed data but not verifying it from tampering with the signed data
+ thus making the signature unverifiable. It is also quite beneficial
+ for the signature verification code. Standard CBOR parsers usually do
+ not give access to partially parsed CBOR as would be need to check
+ the signature of some CBOR. With this wrapping, standard CBOR parsers
+ can be used to get to all the data needed for a signature
+ verification.
+ */
+static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Close a wrapping bstr.
+
+ @param[in] pCtx The context to add to.
+ @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes
+
+ The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces
+ nesting level by one.
+
+ A pointer and length of the enclosed encoded CBOR is returned in
+ *pWrappedCBOR if it is not NULL. The main purpose of this is so this
+ data can be hashed (e.g., with SHA-256) as part of a COSE (RFC 8152)
+ implementation. **WARNING**, this pointer and length should be used
+ right away before any other calls to QCBOREncode_xxxx() as they will
+ move data around and the pointer and length will no longer be to the
+ correct encoded CBOR.
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times then QCBOREncode_BstrWrap(),
+ then QCBOR_ERR_TOO_MANY_CLOSES will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this is called and it is not a wrapping bstr that is currently
+ open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR);
+
+
+/**
+ @brief Add some already-encoded CBOR bytes.
+
+ @param[in] pCtx The context to add to.
+ @param[in] Encoded The already-encoded CBOR to add to the context.
+
+ The encoded CBOR being added must be fully conforming CBOR. It must
+ be complete with no arrays or maps that are incomplete. While this
+ encoder doesn't ever produce indefinite lengths, it is OK for the
+ raw CBOR added here to have indefinite lengths.
+
+ The raw CBOR added here is not checked in anyway. If it is not
+ conforming or has open arrays or such, the final encoded CBOR
+ will probably be wrong or not what was intended.
+
+ If the encoded CBOR being added here contains multiple items, they
+ must be enclosed in a map or array. At the top level the raw
+ CBOR must be a single data item.
+ */
+static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded);
+
+static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded);
+
+static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded);
+
+
+/**
+ @brief Get the encoded result.
+
+ @param[in] pCtx  The context to finish encoding with.
+ @param[out] pEncodedCBOR  Pointer and length of encoded CBOR.
+
+ @return
+ One of the CBOR error codes.
+
+ If this returns success QCBOR_SUCCESS the encoding was a success and
+ the return length is correct and complete.
+
+ If no buffer was passed to QCBOR_Init(), then only the length and
+ number of items was computed. The length is in
+ pEncodedCBOR->Bytes.len. pEncodedCBOR->Bytes.ptr is NULL.
+
+ If a buffer was passed, then pEncodedCBOR->Bytes.ptr is the same as
+ the buffer passed to QCBOR_Init() and contains the encoded CBOR
+ and the length is filled in.
+
+ If an error is returned, the buffer may have partially encoded
+ incorrect CBOR in it and it should not be used. Likewise, the length
+ may be incorrect and should not be used.
+
+ Note that the error could have occurred in one of the many
+ QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This
+ error handling approach reduces the CBOR implementation size, but makes
+ debugging a problem a little more difficult.
+ */
+QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
+
+
+/**
+ @brief Get the encoded CBOR and error status.
+
+ @param[in] pCtx  The context to finish encoding with.
+ @param[out] uEncodedLen The length of the encoded or potentially encoded CBOR in bytes.
+
+ @return
+ One of the CBOR error codes.
+
+ If this returns success QCBOR_SUCCESS the encoding was a success and
+ the return length is correct and complete.
+
+ If no buffer was passed to QCBOR_Init(), then only the length was
+ computed. If a buffer was passed, then the encoded CBOR is in the
+ buffer.
+
+ If an error is returned, the buffer may have partially encoded
+ incorrect CBOR in it and it should not be used. Likewise, the length
+ may be incorrect and should not be used.
+
+ Note that the error could have occurred in one of the many
+ QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This
+ error handling reduces the CBOR implementation size, but makes
+ debugging harder.
+ */
+QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen);
+
+
+
+
+
+
+/**
+ QCBORDecodeContext is the data type that holds context decoding the
+ data items for some received CBOR.  It is about 100 bytes, so it can go
+ on the stack.  The contents are opaque, and the caller should not
+ access any internal items.  A context may be re used serially as long
+ as it is re initialized.
+ */
+typedef struct _QCBORDecodeContext QCBORDecodeContext;
+
+
+/**
+ Initialize the CBOR decoder context.
+
+ @param[in] pCtx The context to initialize.
+ @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded.
+ @param[in] nMode One of QCBOR_DECODE_MODE_xxx
+
+ Initialize context for a pre-order travesal of the encoded CBOR tree.
+
+ Most CBOR decoding can be completed by calling this function to start
+ and QCBORDecode_GetNext() in a loop.
+
+ If indefinite length strings are to be decoded, then
+ QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
+ called to set up a string allocator.
+
+ If tags other than built-in tags are to be recognized, then
+ QCBORDecode_SetCallerAddedTagMap() must be called. The built-in tags
+ are those for which a macro of the form  CBOR_TAG_XXX is defined.
+
+ Three decoding modes are supported.  In normal mode,
+ QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and ints are
+ accepted as map labels. If a label is other than these, the error
+ QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
+
+ In strings-only mode, QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only text
+ strings are accepted for map labels.  This lines up with CBOR that
+ converts to JSON. The error QCBOR_ERR_MAP_LABEL_TYPE is returned by
+ QCBORDecode_GetNext() if anything but a text string label is
+ encountered.
+
+ In QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special arrays.
+ They will be return with special uDataType QCBOR_TYPE_MAP_AS_ARRAY
+ and uCount, the number of items, will be double what it would be
+ for a normal map because the labels are also counted. This mode
+ is useful for decoding CBOR that has labels that are not
+ integers or text strings, but the caller must manage much of
+ the map decoding.
+ */
+void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
+
+
+/**
+ @brief Set up the MemPool string allocator for indefinite length strings.
+
+ @param[in] pCtx The decode context.
+ @param[in] MemPool The pointer and length of the memory pool.
+ @param[in] bAllStrings true means to put even definite length strings in the pool.
+
+ @return error if the MemPool was less than QCBOR_DECODE_MIN_MEM_POOL_SIZE.
+
+ Indefinite length strings (text and byte) cannot be decoded unless
+ there is a string allocator configured. MemPool is a simple built-in
+ string allocator that allocates bytes from a memory pool handed to it
+ by calling this function.  The memory pool is just a pointer and
+ length for some block of memory that is to be used for string
+ allocation. It can come from the stack, heap or other.
+
+ The memory pool must be QCBOR_DECODE_MIN_MEM_POOL_SIZE plus space for
+ all the strings allocated.  There is no overhead per string allocated
+
+ This memory pool is used for all indefinite length strings that are
+ text strings or byte strings, including strings used as labels.
+
+ The pointers to strings in QCBORItem will point into the memory pool set
+ here. They do not need to be individually freed. Just discard the buffer
+ when they are no longer needed.
+
+ If bAllStrings is set, then the size will be the overhead plus the
+ space to hold **all** strings, definite and indefinite length, value
+ or label. The advantage of this is that after the decode is complete,
+ the original memory holding the encoded CBOR does not need to remain
+ valid.
+
+ If this function is never called because there is no need to support
+ indefinite length strings, the MemPool implementation should be
+ dead-stripped by the loader and not add to code size.
+ */
+QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings);
+
+
+/**
+ @brief Sets up a custom string allocator for indefinite length strings
+
+ @param[in] pCtx The decoder context to set up an allocator for
+ @param[in] pAllocator The string allocator "object"
+
+ See QCBORStringAllocator for the requirements of the string allocator.
+
+ Typically, this is used if the simple MemPool allocator isn't desired.
+
+ A malloc based string allocator can be obtained by calling
+ QCBOR_DMalloc(). This function is supply separately from qcbor
+ to keep qcbor smaller and neater. It is in a separate
+ GitHub repository.
+
+ You can also write your own allocator. Create the allocate, free,
+ and destroy functions and put pointers to them in a QCBORStringAllocator.
+ */
+void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllStrings);
+
+
+/**
+ @brief Configure list of caller selected tags to be recognized
+
+ @param[in] pCtx The decode context.
+ @param[out] pTagList Structure holding the list of tags to configure
+
+ This is used to tell the decoder about tags beyond those that are
+ built-in that should be recognized. The built-in tags are those
+ with macros of the form CBOR_TAG_XXX.
+
+ See description of QCBORTagListIn.
+ */
+void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList);
+
+
+/**
+ @brief Gets the next item (integer, byte string, array...) in pre order traversal of CBOR tree
+
+ @param[in]  pCtx          The decoder context.
+ @param[out] pDecodedItem  Holds the CBOR item just decoded.
+
+ @return 0 or error. All errors except QCBOR_ERR_TOO_MANY_TAGS
+ and QCBOR_ERR_STRING_ALLOCATE indicate that the CBOR input
+ could not be decoded. In most cases
+ this is because the CBOR is invalid. In a few cases
+ (QCBOR_ERR_ARRAY_NESTING_TOO_DEEP, QCBOR_ERR_INT_OVERFLOW,
+ QCBOR_ERR_DATE_OVERFLOW) it is because the CBOR is beyond
+ the limits of what this implementation can handle.
+ QCBOR_ERR_NO_STRING_ALLOCATOR indicates CBOR that cannot
+ be handled unless a string allocator is configured.
+ QCBOR_ERR_MAP_LABEL_TYPE is in a way a limitation of
+ this implementation, but can be avoided by decoding
+ in QCBOR_DECODE_MODE_MAP_AS_ARRAY mode.
+
+ pDecodedItem is filled in with the value parsed. Generally, the
+ following data is returned in the structure.
+
+ - The data type in uDataType which indicates which member of the val
+   union the data is in. This decoder figures out the type based on the
+   CBOR major type, the CBOR "additionalInfo", the CBOR optional tags
+   and the value of the integer.
+
+ - The value of the item, which might be an integer, a pointer and a
+   length, the count of items in an array, a floating-point number or
+   other.
+
+ - The nesting level for maps and arrays.
+
+ - The label for an item in a map, which may be a text or byte string or an integer.
+
+ - The CBOR optional tag or tags.
+
+ See documentation on in the data type QCBORItem for all the details
+ on what is returned.
+
+ This function also handles arrays and maps. When first encountered a
+ QCBORItem will be returned with major type CBOR_MAJOR_TYPE_ARRAY or
+ CBOR_MAJOR_TYPE_ARRAY_MAP. QCBORItem.val.uCount will indicate the number
+ of Items in the array or map.  Typically, an implementation will call
+ QCBORDecode_GetNext() in a for loop to fetch them all. When decoding
+ indefinite length maps and arrays, QCBORItem.val.uCount is UINT16_MAX
+ and uNextNestLevel must be used to know when the end of a map
+ or array is reached.
+
+ Nesting level 0 is the outside top-most nesting level. For example, in
+ a CBOR structure with two items, an integer and a byte string only,
+ both would be at nesting level 0.  A CBOR structure with an array
+ open, an integer and a byte string, would have the integer and byte
+ string as nesting level 1.
+
+ Here is an example of how the nesting level is reported with no arrays
+ or maps at all
+
+ @verbatim
+ CBOR Structure           Nesting Level
+ Integer                    0
+ Byte String                0
+ @endverbatim
+
+ Here is an example of how the nesting level is reported with an a simple
+ array and some top-level items.
+
+ @verbatim
+ Integer                    0
+ Array (with 2 items)       0
+ Byte String                1
+ Byte string                1
+ Integer                    0
+ @endverbatim
+
+
+ Here's a more complex example
+ @verbatim
+
+ Map with 2 items           0
+ Text string                1
+ Array with 3 integers      1
+ integer                    2
+ integer                    2
+ integer                    2
+ text string                1
+ byte string                1
+ @endverbatim
+
+ In QCBORItem, uNextNestLevel is the nesting level for the next call
+ to QCBORDecode_GetNext(). It indicates if any maps or arrays were closed
+ out during the processing of the just-fecthed QCBORItem. This processing
+ includes a look-ahead for any breaks that close out indefinite length
+ arrays or maps. This value is needed to be able to understand the
+ hierarchical structure. If uNextNestLevel is not equal to uNestLevel
+ the end of the current map or array has been encountered. This
+ works the same for both definite and indefinite length arrays.
+
+ Most uses of this decoder will not need to do anything extra for
+ tag handling. The built-in tags, those with a macro of the form
+ CBOR_TAG_XXXX, will be enough.
+
+ If tags beyond built-in tags are to be recognized, they must be
+ configured by calling QCBORDecode_SetCallerConfiguredTags(). If
+ a tag is not recognized it is silently ignored.
+
+ Several tagged types are automatically recognized and decoded and
+ returned in their decoded form.
+
+ To find out if a QCBORItem was tagged with a particular tag
+ call QCBORDecode_IsTagged(). This works only for built-in
+ tags and caller-configured tags.
+
+ To get the full list of tags on an Item without having to
+ pre-configure any predetermined list of tags use
+ QCBORDecode_GetNextWithTags().
+ */
+QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
+
+/**
+ @brief Gets the next item including full list of tags for item
+
+ @param[in]  pCtx          The decoder context.
+ @param[out] pDecodedItem  Holds the CBOR item just decoded.
+ @param[in,out] pTagList   On input array to put tags in; on output the tags on this item.
+
+ @return 0 or error.
+
+ This works the same as QCBORDecode_GetNext() except that it also returns
+ the full list of tags for the data item. This function should only
+ be needed when parsing CBOR to print it out or convert it to some other
+ format. It should not be needed in an actual CBOR protocol implementation.
+
+ Tags will be returned here whether or not they are in the built-in or
+ caller-configured tag lists.
+
+ CBOR has no upper bound of limit on the number of tags that can be
+ associated with a data item. In practice the number of tags on an item
+ will usually be small, perhaps less than five. This will return an error
+ if the array in pTagList is too small to hold all the tags for an item.
+
+ (This function is separate from  QCBORDecode_GetNext() so as to not have to
+ make QCBORItem large enough to be able to hold a full list of tags. Even a list of
+ five tags would nearly double its size because tags can be a uint64_t).
+ */
+QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList);
+
+
+/**
+ @brief Determine if a CBOR item was tagged with a particular tag
+
+ @param[in] pCtx    The decoder context.
+ @param[in] pItem   The CBOR item to check
+ @param[in] uTag    The tag to check
+
+ @return 1 if it was tagged, 0 if not
+
+ QCBORDecode_GetNext() processes tags by looking them up
+ in two lists and setting a bit corresponding to the tag
+ in uTagBits in the QCBORItem. To find out if a
+ QCBORItem was tagged with a particular tag, call
+ this function. It handles the mapping between
+ the two lists of tags and the bits set for it.
+
+ The first tag list is the built-in tags, those
+ with a macro of the form CBOR_TAG_XXX in this
+ header file. There are up to 48 of these,
+ corresponding to the lower 48 tag bits.
+
+ The other optional tag list is the ones
+ the caller configured using QCBORDecode_SetCallerConfiguredTagList()
+ There are QCBOR_MAX_CUSTOM_TAGS (16) of these corresponding to the
+ upper 16 tag bits.
+
+ See also QCBORDecode_GetTags() and QCBORDecode_GetNextWithTags().
+ */
+int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag);
+
+
+/**
+ Check whether all the bytes have been decoded and maps and arrays closed.
+
+ @param[in]  pCtx          The context to check
+
+ @return QCBOR_SUCCESS or error
+
+ This tells you if all the bytes given to QCBORDecode_Init() have
+ been consumed and whether all maps and arrays were closed.
+ The decode is considered to be incorrect or incomplete if not
+ and an error will be returned.
+ */
+QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
+
+
+
+
+/**
+  Convert int64_t to smaller int's safely
+
+ @param [in]  src    An int64_t
+ @param [out] dest   A smaller sized int to convert to
+
+ @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 INT64_MAX and
+ UINT64_MAX. That is, unless the value is so large that it can only be
+ represented as a uint64_t, it will be an int64_t.
+
+ CBOR itself doesn't size the individual integers it carries at
+ all. The only limits it puts on the major integer types is that they
+ are 8 bytes or less in length. Then encoders like this one use the
+ smallest number of 1, 2, 4 or 8 bytes to represent the integer based
+ on its value. There is thus no notion that one data item in CBOR is
+ an 1 byte integer and another is a 4 byte integer.
+
+ The interface to this CBOR encoder only uses 64-bit integers. Some
+ CBOR protocols or implementations of CBOR protocols may not want to
+ work with something smaller than a 64-bit integer.  Perhaps an array
+ of 1000 integers needs to be sent and none has a value larger than
+ 50,000 and are represented as uint16_t.
+
+ The sending / encoding side is easy. Integers are temporarily widened
+ to 64-bits as a parameter passing through QCBOREncode_AddInt64() and
+ encoded in the smallest way possible for their value, possibly in
+ less than an uint16_t.
+
+ On the decoding side the integers will be returned at int64_t even if
+ they are small and were represented by only 1 or 2 bytes in the
+ encoded CBOR. The functions here will convert integers to a small
+ representation with an overflow check.
+
+ (The decoder could have support 8 different integer types and
+ represented the integer with the smallest type automatically, but
+ this would have made the decoder more complex and code calling the
+ decoder more complex in most use cases.  In most use cases on 64-bit
+ machines it is no burden to carry around even small integers as
+ 64-bit values).
+ */
+static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest)
+{
+   if(src > INT32_MAX || src < INT32_MIN) {
+      return -1;
+   } else {
+      *dest = (int32_t) src;
+   }
+   return 0;
+}
+
+static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest)
+{
+   if(src > INT16_MAX || src < INT16_MIN) {
+      return -1;
+   } else {
+      *dest = (int16_t) src;
+   }
+   return 0;
+}
+
+static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest)
+{
+   if(src > INT8_MAX || src < INT8_MIN) {
+      return -1;
+   } else {
+      *dest = (int8_t) src;
+   }
+   return 0;
+}
+
+static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest)
+{
+   if(src > UINT32_MAX || src < 0) {
+      return -1;
+   } else {
+      *dest = (uint32_t) src;
+   }
+   return 0;
+}
+
+static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest)
+{
+   if(src > UINT16_MAX || src < 0) {
+      return -1;
+   } else {
+      *dest = (uint16_t) src;
+   }
+   return 0;
+}
+
+static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest)
+{
+   if(src > UINT8_MAX || src < 0) {
+      return -1;
+   } else {
+      *dest = (uint8_t) src;
+   }
+   return 0;
+}
+
+static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest)
+{
+   if(src > 0) {
+      return -1;
+   } else {
+      *dest = (uint64_t) src;
+   }
+   return 0;
+}
+
+
+
+
+
+/* ===========================================================================
+ BEGINNING OF PRIVATE INLINE IMPLEMENTATION
+
+ =========================================================================== */
+
+/**
+ @brief Semi-private method to add a buffer full of bytes to encoded output
+
+ @param[in] pCtx       The encoding context to add the integer to.
+ @param[in] uMajorType The CBOR major type of the bytes.
+ @param[in] Bytes      The bytes to add.
+
+ Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
+ QCBOREncode_AddEncoded() instead. They are inline functions
+ that call this and supply the correct major type. This function
+ is public to make the inline functions work to keep the overall
+ code size down and because the C language has no way to make
+ it private.
+
+ If this is called the major type should be CBOR_MAJOR_TYPE_TEXT_STRING,
+ CBOR_MAJOR_TYPE_BYTE_STRING or CBOR_MAJOR_NONE_TYPE_RAW. The last
+ one is special for adding already-encoded CBOR.
+ */
+void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes);
+
+
+/**
+ @brief Semi-private method to open a map, array or bstr wrapped CBOR
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
+ QCBOREncode_BstrWrap() instead of this.
+ */
+void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to close a map, array or bstr wrapped CBOR
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+ @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes
+
+ Call QCBOREncode_CloseArray(), QCBOREncode_CloseMap() or
+ QCBOREncode_CloseBstrWrap() instead of this.
+ */
+void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
+
+
+/**
+ @brief  Semi-private method to add simple types.
+
+ @param[in] pCtx      The encoding context to add the simple value to.
+ @param[in] uSize     Minimum encoding size for uNum. Usually 0.
+ @param[in] uNum      One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
+
+ This is used to add simple types like true and false.
+
+ Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), QCBOREncode_AddUndef()
+ instead of this.
+
+ This function can add simple values that are not defined by CBOR yet. This expansion
+ point in CBOR should not be used unless they are standardized.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+void  QCBOREncode_AddType7(QCBOREncodeContext *pCtx, size_t uSize, uint64_t uNum);
+
+
+static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
+{
+   QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet
+   QCBOREncode_AddInt64(pCtx, uNum);
+}
+
+static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddInt64(pCtx, uNum);
+}
+
+
+static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum)
+{
+   QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet
+   QCBOREncode_AddUInt64(pCtx, uNum);
+}
+
+static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddUInt64(pCtx, uNum);
+}
+
+
+static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text)
+{
+   QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
+}
+
+static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text)
+{
+   QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet
+   QCBOREncode_AddText(pCtx, Text);
+}
+
+static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddText(pCtx, Text);
+}
+
+
+inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString)
+{
+   QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString));
+}
+
+static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddSZString(pCtx, szString);
+}
+
+static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddSZString(pCtx, szString);
+}
+
+
+static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddDouble(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddDouble(pCtx, dNum);
+}
+
+
+static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+   QCBOREncode_AddInt64(pCtx, date);
+}
+
+static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+   QCBOREncode_AddInt64(pCtx, date);
+}
+
+static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+   QCBOREncode_AddInt64(pCtx, date);
+}
+
+
+static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+   QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+   QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+   QCBOREncode_AddText(pCtx, URI);
+}
+
+static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+   QCBOREncode_AddText(pCtx, URI);
+}
+
+static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+   QCBOREncode_AddText(pCtx, URI);
+}
+
+
+
+static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+   QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+   QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+   QCBOREncode_AddText(pCtx, B64Text);
+}
+
+
+static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+   QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+   QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+   QCBOREncode_AddText(pCtx, B64Text);
+}
+
+
+static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+   QCBOREncode_AddText(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+   QCBOREncode_AddText(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+   QCBOREncode_AddText(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+   QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+   QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+   QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+
+static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate)
+{
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+   QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+   QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+   QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+
+static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum)
+{
+   QCBOREncode_AddType7(pCtx, 0, uNum);
+}
+
+static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+
+static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b)
+{
+   uint8_t uSimple = CBOR_SIMPLEV_FALSE;
+   if(b) {
+      uSimple = CBOR_SIMPLEV_TRUE;
+   }
+   QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddBool(pCtx, b);
+}
+
+static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddBool(pCtx, b);
+}
+
+
+static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL);
+}
+
+static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddNULL(pCtx);
+}
+
+static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddNULL(pCtx);
+}
+
+
+static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF);
+}
+
+static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddUndef(pCtx);
+}
+
+static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddUndef(pCtx);
+}
+
+
+static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
+}
+
+static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_OpenArray(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx,  int64_t nLabel)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_OpenArray(pCtx);
+}
+
+static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY, NULL);
+}
+
+
+static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
+}
+
+static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_OpenMap(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_OpenMap(pCtx);
+}
+
+static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP, NULL);
+}
+
+
+static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
+{
+   QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING);
+}
+
+static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_BstrWrap(pCtx);
+}
+
+static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_BstrWrap(pCtx);
+}
+
+static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR)
+{
+   QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, pWrappedCBOR);
+}
+
+
+static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded)
+{
+   QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded);
+}
+
+static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddEncoded(pCtx, Encoded);
+}
+
+static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddEncoded(pCtx, Encoded);
+}
+
+
+/* ===========================================================================
+ END OF PRIVATE INLINE IMPLEMENTATION
+
+ =========================================================================== */
+
+#endif /* defined(__QCBOR__qcbor__) */
+
diff --git a/lib/ext/qcbor/inc/useful_buf.h b/lib/ext/qcbor/inc/useful_buf.h
new file mode 100644
index 0000000..dcb88b8
--- /dev/null
+++ b/lib/ext/qcbor/inc/useful_buf.h
@@ -0,0 +1,143 @@
+/*
+ * useful_buf.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.mdE.
+ */
+
+
+#ifndef __USEFUL_BUF_H__
+#define __USEFUL_BUF_H__
+
+#include "UsefulBuf.h"
+
+
+/**
+ * \file useful_buf.h
+ *
+ * \brief This is a TF-M coding style version of UsefulBuf.
+ *        See UsefulBuf for documentation of these functions.
+ */
+
+
+#define NULL_USEFUL_BUF_C  NULLUsefulBufC
+
+#define NULL_USEFUL_BUF    NULLUsefulBuf
+
+
+static inline int useful_buf_c_is_null(struct useful_buf_c in)
+{
+    return UsefulBuf_IsNULLC(in);
+}
+
+
+static inline int useful_buf_is_null(struct useful_buf in)
+{
+    return UsefulBuf_IsNULL(in);
+}
+
+
+static inline int useful_buf_c_is_empty(struct useful_buf_c in)
+{
+    return UsefulBuf_IsEmptyC(in);
+}
+
+static inline int useful_buf_is_empty(struct useful_buf in)
+{
+    return UsefulBuf_IsEmpty(in);
+}
+
+
+static inline int useful_buf_is_null_or_empty(struct useful_buf in)
+{
+    return UsefulBuf_IsNULLOrEmpty(in);
+}
+
+
+static inline int useful_buf_c_is_null_or_empty(struct useful_buf_c in)
+{
+    return UsefulBuf_IsNULLOrEmptyC(in);
+}
+
+
+static inline struct useful_buf useful_buf_unconst(struct useful_buf_c in)
+{
+    return UsefulBuf_Unconst(in);
+}
+
+#define USEFUL_BUF_FROM_SZ_LITERAL UsefulBuf_FROM_SZ_LITERAL
+
+#define USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL  UsefulBuf_FROM_BYTE_ARRAY_LITERAL
+
+#define USEFUL_BUF_MAKE_STACK_UB UsefulBuf_MAKE_STACK_UB
+
+#define USEFUL_BUF_FROM_BYTE_ARRAY UsefulBuf_FROM_BYTE_ARRAY
+
+
+static inline struct useful_buf_c useful_buf_from_sz(const char *string)
+{
+    return UsefulBuf_FromSZ(string);
+}
+
+static inline struct
+useful_buf_c useful_buf_copy_offset(struct useful_buf dest,
+                                    size_t offset,
+                                    struct useful_buf_c src)
+{
+    return UsefulBuf_CopyOffset(dest, offset, src);
+}
+
+
+
+static inline struct useful_buf_c useful_buf_copy(struct useful_buf dest,
+                                                  struct useful_buf_c src)
+{
+    return UsefulBuf_Copy(dest, src);
+}
+
+
+static inline struct useful_buf_c useful_buf_set(struct useful_buf dest,
+                                                 uint8_t value)
+{
+    return UsefulBuf_Set(dest, value);
+}
+
+
+static inline struct useful_buf_c useful_buf_copy_ptr(struct useful_buf dest,
+                                                      const void *ptr,
+                                                      size_t len)
+{
+    return UsefulBuf_CopyPtr(dest, ptr, len);
+}
+
+
+static inline struct useful_buf_c useful_buf_head(struct useful_buf_c buf,
+                                                  size_t amount)
+{
+    return UsefulBuf_Head(buf, amount);
+}
+
+static inline struct useful_buf_c useful_buf_tail(struct useful_buf_c buf,
+                                                  size_t amount)
+{
+    return UsefulBuf_Tail(buf, amount);
+}
+
+static inline int useful_buf_compare(const struct useful_buf_c buf1,
+                                     const struct useful_buf_c buf2)
+{
+    return UsefulBuf_Compare(buf1, buf2);
+}
+
+static inline size_t
+useful_buf_find_bytes(const struct useful_buf_c bytes_to_search,
+                      const struct useful_buf_c bytes_to_find)
+{
+    return UsefulBuf_FindBytes(bytes_to_search, bytes_to_find);
+}
+
+
+#endif /* __USEFUL_BUF_H__ */
diff --git a/lib/ext/qcbor/src/UsefulBuf.c b/lib/ext/qcbor/src/UsefulBuf.c
new file mode 100644
index 0000000..5a7d37b
--- /dev/null
+++ b/lib/ext/qcbor/src/UsefulBuf.c
@@ -0,0 +1,329 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+/*===================================================================================
+ FILE:  UsefulBuf.c
+
+ DESCRIPTION:  General purpose input and output buffers
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when               who             what, where, why
+ --------           ----            ---------------------------------------------------
+ 09/07/17           llundbla        Fix critical bug in UsefulBuf_Find() -- a read off
+                                    the end of memory when the bytes to find is longer
+                                    than the bytes to search.
+ 06/27/17           llundbla        Fix UsefulBuf_Compare() bug. Only affected comparison
+                                    for < or > for unequal length buffers.  Added
+                                    UsefulBuf_Set() function.
+ 05/30/17           llundbla        Functions for NULL UsefulBufs and const / unconst
+ 11/13/16           llundbla        Initial Version.
+
+ =====================================================================================*/
+
+#include "UsefulBuf.h"
+
+#define USEFUL_OUT_BUF_MAGIC  (0x0B0F) // used to catch use of uninitialized or corrupted UOBs
+
+
+/*
+ Public function -- see UsefulBuf.h
+ */
+UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src)
+{
+   // Do this with subtraction so it doesn't give erroneous result if uOffset + Src.len overflows
+   if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len
+      return NULLUsefulBufC;
+   }
+
+   memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len);
+
+   return (UsefulBufC){Dest.ptr, Src.len + uOffset};
+}
+
+
+/*
+   Public function -- see UsefulBuf.h
+ */
+int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2)
+{
+   // use the comparisons rather than subtracting lengths to
+   // return an int instead of a size_t
+   if(UB1.len < UB2.len) {
+      return -1;
+   } else if (UB1.len > UB2.len) {
+      return 1;
+   } // else UB1.len == UB2.len
+
+   return memcmp(UB1.ptr, UB2.ptr, UB1.len);
+}
+
+
+
+/*
+ Public function -- see UsefulBuf.h
+ */
+size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind)
+{
+   if(BytesToSearch.len < BytesToFind.len) {
+      return SIZE_MAX;
+   }
+
+   for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
+      if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
+         return uPos;
+      }
+   }
+
+   return SIZE_MAX;
+}
+
+
+/*
+ Public function -- see UsefulBuf.h
+
+ Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage)
+{
+    me->magic  = USEFUL_OUT_BUF_MAGIC;
+    UsefulOutBuf_Reset(me);
+    me->UB     = Storage;
+
+#if 0
+   // This check is off by default.
+
+   // The following check fails on ThreadX
+
+    // Sanity check on the pointer and size to be sure we are not
+    // passed a buffer that goes off the end of the address space.
+    // Given this test, we know that all unsigned lengths less than
+    // me->size are valid and won't wrap in any pointer additions
+    // based off of pStorage in the rest of this code.
+    const uintptr_t ptrM = UINTPTR_MAX - Storage.len;
+    if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) // Check #0
+        me->err = 1;
+#endif
+}
+
+
+
+/*
+ Public function -- see UsefulBuf.h
+
+ The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
+
+ Code Reviewers: THIS FUNCTION DOES POINTER MATH
+
+ This function inserts the source buffer, NewData, into the destination buffer, me->UB.ptr.
+
+ Destination is represented as:
+   me->UB.ptr -- start of the buffer
+   me->UB.len -- size of the buffer UB.ptr
+   me->data_len -- length of value data in UB
+
+ Source is data:
+   NewData.ptr -- start of source buffer
+   NewData.len -- length of source buffer
+
+ Insertion point:
+   uInsertionPos.
+
+ Steps:
+
+ 0. Corruption checks on UsefulOutBuf
+
+ 1. Figure out if the new data will fit or not
+
+ 2. Is insertion position in the range of valid data?
+
+ 3. If insertion point is not at the end, slide data to the right of the insertion point to the right
+
+ 4. Put the new data in at the insertion position.
+
+ */
+void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uInsertionPos)
+{
+   if(me->err) {
+      // Already in error state.
+      return;
+   }
+
+   /* 0. Sanity check the UsefulOutBuf structure */
+   // A "counter measure". If magic number is not the right number it
+   // probably means me was not initialized or it was corrupted. Attackers
+   // can defeat this, but it is a hurdle and does good with very
+   // little code.
+   if(me->magic != USEFUL_OUT_BUF_MAGIC) {
+      me->err = 1;
+      return;  // Magic number is wrong due to uninitalization or corrption
+   }
+
+   // Make sure valid data is less than buffer size. This would only occur
+   // if there was corruption of me, but it is also part of the checks to
+   // be sure there is no pointer arithmatic under/overflow.
+   if(me->data_len > me->UB.len) {  // Check #1
+      me->err = 1;
+      return; // Offset of valid data is off the end of the UsefulOutBuf due to uninitialization or corruption
+   }
+
+   /* 1. Will it fit? */
+   // WillItFit() is the same as: NewData.len <= (me->size - me->data_len)
+   // Check #1 makes sure subtraction in RoomLeft will not wrap around
+   if(! UsefulOutBuf_WillItFit(me, NewData.len)) { // Check #2
+      // The new data will not fit into the the buffer.
+      me->err = 1;
+      return;
+   }
+
+   /* 2. Check the Insertion Position */
+   // This, with Check #1, also confirms that uInsertionPos <= me->data_len
+   if(uInsertionPos > me->data_len) { // Check #3
+      // Off the end of the valid data in the buffer.
+      me->err = 1;
+      return;
+   }
+
+   /* 3. Slide existing data to the right */
+   uint8_t *pSourceOfMove       = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1
+   size_t   uNumBytesToMove     = me->data_len - uInsertionPos; // PtrMath #2
+   uint8_t *pDestinationOfMove  = pSourceOfMove + NewData.len; // PtrMath #3
+
+   if(uNumBytesToMove && me->UB.ptr) {
+      // To know memmove won't go off end of destination, see PtrMath #4
+      memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove);
+   }
+
+   /* 4. Put the new data in */
+   uint8_t *pInsertionPoint = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #5
+   if(me->UB.ptr) {
+      // To know memmove won't go off end of destination, see PtrMath #6
+      memmove(pInsertionPoint, NewData.ptr, NewData.len);
+   }
+   me->data_len += NewData.len ;
+}
+
+
+/*
+ Rationale that describes why the above pointer math is safe
+
+ PtrMath #1 will never wrap around over because
+    Check #0 in UsefulOutBuf_Init makes sure me->UB.ptr + me->UB.len doesn't wrap
+    Check #1 makes sure me->data_len is less than me->UB.len
+    Check #3 makes sure uInsertionPos is less than me->data_len
+
+ PtrMath #2 will never wrap around under because
+    Check #3 makes sure uInsertionPos is less than me->data_len
+
+ PtrMath #3 will never wrap around over because   todo
+    PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and a maximum valid ptr
+    Check #2 that NewData.len will fit
+
+ PtrMath #4 will never wrap under because
+    Calculation for extent or memmove is uRoomInDestination  = me->UB.len - (uInsertionPos + NewData.len)
+    Check #3 makes sure uInsertionPos is less than me->data_len
+    Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
+    This algebraically rearranges to me->size > uInsertionPos + NewData.len
+
+ PtrMath #5 is exactly the same as PtrMath #1
+
+ PtrMath #6 will never wrap under because
+    Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos;
+    Check #1 makes sure me->data_len is less than me->size
+    Check #3 makes sure uInsertionPos is less than me->data_len
+ */
+
+
+/*
+ Public function -- see UsefulBuf.h
+ */
+UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me)
+{
+   if(me->err) {
+      return NULLUsefulBufC;
+   }
+
+   if(me->magic != USEFUL_OUT_BUF_MAGIC) {
+      me->err = 1;
+      return NULLUsefulBufC;
+   }
+
+   return (UsefulBufC){me->UB.ptr,me->data_len};
+}
+
+
+/*
+ Public function -- see UsefulBuf.h
+
+ Copy out the data accumulated in to the output buffer.
+ */
+UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf pDest)
+{
+   const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(me);
+   if(UsefulBuf_IsNULLC(Tmp)) {
+      return NULLUsefulBufC;
+   }
+   return UsefulBuf_Copy(pDest, Tmp);
+}
+
+
+
+
+/*
+ Public function -- see UsefulBuf.h
+
+ The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer.
+
+ Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uAmount)
+{
+   // Already in error state. Do nothing.
+   if(me->err) {
+      return NULL;
+   }
+
+   if(!UsefulInputBuf_BytesAvailable(me, uAmount)) {
+      // The number of bytes asked for at current position are more than available
+      me->err = 1;
+      return NULL;
+   }
+
+   // This is going to succeed
+   const void * const result = ((uint8_t *)me->UB.ptr) + me->cursor;
+   me->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable()
+   return result;
+}
+
diff --git a/lib/ext/qcbor/src/ieee754.c b/lib/ext/qcbor/src/ieee754.c
new file mode 100644
index 0000000..6fdfda8
--- /dev/null
+++ b/lib/ext/qcbor/src/ieee754.c
@@ -0,0 +1,497 @@
+/*==============================================================================
+ ieee754.c -- floating point conversion between half, double and single precision
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 7/23/18
+ ==============================================================================*/
+
+#include "ieee754.h"
+#include <string.h> // For memcpy()
+
+
+/*
+ This code is written for clarity and verifiability, not for size, on the assumption
+ that the optimizer will do a good job. The LLVM optimizer, -Os, does seem to do the
+ job and the resulting object code is smaller from combining code for the many different
+ cases (normal, subnormal, infinity, zero...) for the conversions.
+
+ Dead stripping is also really helpful to get code size down when floating point
+ encoding is not needed.
+
+ This code works solely using shifts and masks and thus has no dependency on
+ any math libraries. It can even work if the CPU doesn't have any floating
+ point support, though that isn't the most useful thing to do.
+
+ The memcpy() dependency is only for CopyFloatToUint32() and friends which only
+ is needed to avoid type punning when converting the actual float bits to
+ an unsigned value so the bit shifts and masks can work.
+ */
+
+/*
+ The references used to write this code:
+
+ - IEEE 754-2008, particularly section 3.6 and 6.2.1
+
+ - https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages
+
+ - https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values
+ */
+
+
+// ----- Half Precsion -----------
+#define HALF_NUM_SIGNIFICAND_BITS (10)
+#define HALF_NUM_EXPONENT_BITS    (5)
+#define HALF_NUM_SIGN_BITS        (1)
+
+#define HALF_SIGNIFICAND_SHIFT    (0)
+#define HALF_EXPONENT_SHIFT       (HALF_NUM_SIGNIFICAND_BITS)
+#define HALF_SIGN_SHIFT           (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS)
+
+#define HALF_SIGNIFICAND_MASK     (0x3ff) // The lower 10 bits  // 0x03ff
+#define HALF_EXPONENT_MASK        (0x1f << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
+#define HALF_SIGN_MASK            (0x01 << HALF_SIGN_SHIFT) //  // 0x80001 bit of sign
+#define HALF_QUIET_NAN_BIT        (0x01 << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
+
+/* Biased    Biased    Unbiased   Use
+    0x00       0        -15       0 and subnormal
+    0x01       1        -14       Smallest normal exponent
+    0x1e      30         15       Largest normal exponent
+    0x1F      31         16       NaN and Infinity  */
+#define HALF_EXPONENT_BIAS        (15)
+#define HALF_EXPONENT_MAX         (HALF_EXPONENT_BIAS)    //  15 Unbiased
+#define HALF_EXPONENT_MIN         (-HALF_EXPONENT_BIAS+1) // -14 Unbiased
+#define HALF_EXPONENT_ZERO        (-HALF_EXPONENT_BIAS)   // -15 Unbiased
+#define HALF_EXPONENT_INF_OR_NAN  (HALF_EXPONENT_BIAS+1)  //  16 Unbiased
+
+
+// ------ Single Precision --------
+#define SINGLE_NUM_SIGNIFICAND_BITS (23)
+#define SINGLE_NUM_EXPONENT_BITS    (8)
+#define SINGLE_NUM_SIGN_BITS        (1)
+
+#define SINGLE_SIGNIFICAND_SHIFT    (0)
+#define SINGLE_EXPONENT_SHIFT       (SINGLE_NUM_SIGNIFICAND_BITS)
+#define SINGLE_SIGN_SHIFT           (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS)
+
+#define SINGLE_SIGNIFICAND_MASK     (0x7fffffUL) // The lower 23 bits
+#define SINGLE_EXPONENT_MASK        (0xffUL << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
+#define SINGLE_SIGN_MASK            (0x01UL << SINGLE_SIGN_SHIFT) // 1 bit of sign
+#define SINGLE_QUIET_NAN_BIT        (0x01UL << (SINGLE_NUM_SIGNIFICAND_BITS-1))
+
+/* Biased  Biased   Unbiased  Use
+    0x0000     0     -127      0 and subnormal
+    0x0001     1     -126      Smallest normal exponent
+    0x7f     127        0      1
+    0xfe     254      127      Largest normal exponent
+    0xff     255      128      NaN and Infinity  */
+#define SINGLE_EXPONENT_BIAS        (127)
+#define SINGLE_EXPONENT_MAX         (SINGLE_EXPONENT_BIAS)    // 127  unbiased
+#define SINGLE_EXPONENT_MIN         (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased
+#define SINGLE_EXPONENT_ZERO        (-SINGLE_EXPONENT_BIAS)   // -127 unbiased
+#define SINGLE_EXPONENT_INF_OR_NAN  (SINGLE_EXPONENT_BIAS+1)  // 128  unbiased
+
+
+// --------- Double Precision ----------
+#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
+#define DOUBLE_NUM_EXPONENT_BITS    (11)
+#define DOUBLE_NUM_SIGN_BITS        (1)
+
+#define DOUBLE_SIGNIFICAND_SHIFT    (0)
+#define DOUBLE_EXPONENT_SHIFT       (DOUBLE_NUM_SIGNIFICAND_BITS)
+#define DOUBLE_SIGN_SHIFT           (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
+
+#define DOUBLE_SIGNIFICAND_MASK     (0xfffffffffffffULL) // The lower 52 bits
+#define DOUBLE_EXPONENT_MASK        (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
+#define DOUBLE_SIGN_MASK            (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
+#define DOUBLE_QUIET_NAN_BIT        (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
+
+
+/* Biased      Biased   Unbiased  Use
+   0x00000000     0     -1023     0 and subnormal
+   0x00000001     1     -1022     Smallest normal exponent
+   0x000007fe  2046      1023     Largest normal exponent
+   0x000007ff  2047      1024     NaN and Infinity  */
+#define DOUBLE_EXPONENT_BIAS        (1023)
+#define DOUBLE_EXPONENT_MAX         (DOUBLE_EXPONENT_BIAS)    // unbiased
+#define DOUBLE_EXPONENT_MIN         (-DOUBLE_EXPONENT_BIAS+1) // unbiased
+#define DOUBLE_EXPONENT_ZERO        (-DOUBLE_EXPONENT_BIAS)   // unbiased
+#define DOUBLE_EXPONENT_INF_OR_NAN  (DOUBLE_EXPONENT_BIAS+1)  // unbiased
+
+
+
+/*
+ Convenient functions to avoid type punning, compiler warnings and such
+ The optimizer reduces them to a simple assignment.
+ This is a crusty corner of C. It shouldn't be this hard.
+
+ These are also in UsefulBuf.h under a different name. They are copied
+ here to avoid a dependency on UsefulBuf.h. There is no
+ object code size impact because these always optimze down to a
+ simple assignment.
+ */
+static inline uint32_t CopyFloatToUint32(float f)
+{
+    uint32_t u32;
+    memcpy(&u32, &f, sizeof(uint32_t));
+    return u32;
+}
+
+static inline uint64_t CopyDoubleToUint64(double d)
+{
+    uint64_t u64;
+    memcpy(&u64, &d, sizeof(uint64_t));
+    return u64;
+}
+
+static inline float CopyUint32ToFloat(uint32_t u32)
+{
+    float f;
+    memcpy(&f, &u32, sizeof(uint32_t));
+    return f;
+}
+
+static inline double CopyUint64ToDouble(uint64_t u64)
+{
+    double d;
+    memcpy(&d, &u64, sizeof(uint64_t));
+    return d;
+}
+
+
+// Public function; see ieee754.h
+uint16_t IEEE754_FloatToHalf(float f)
+{
+    // Pull the three parts out of the single-precision float
+    const uint32_t uSingle = CopyFloatToUint32(f);
+    const int32_t  nSingleUnbiasedExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
+    const uint32_t uSingleSign             =  (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT;
+    const uint32_t uSingleSignificand      =   uSingle & SINGLE_SIGNIFICAND_MASK;
+
+
+    // Now convert the three parts to half-precision.
+    uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+    if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
+        // +/- Infinity and NaNs -- single biased exponent is 0xff
+        uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
+        if(!uSingleSignificand) {
+            // Infinity
+            uHalfSignificand = 0;
+        } else {
+            // Copy the LBSs of the NaN payload that will fit from the single to the half
+            uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT);
+            if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) {
+                // It's a qNaN; copy the qNaN bit
+                uHalfSignificand |= HALF_QUIET_NAN_BIT;
+            } else {
+                // It's a sNaN; make sure the significand is not zero so it stays a NaN
+                // This is needed because not all significand bits are copied from single
+                if(!uHalfSignificand) {
+                    // Set the LSB. This is what wikipedia shows for sNAN.
+                    uHalfSignificand |= 0x01;
+                }
+            }
+        }
+    } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) {
+        // 0 or a subnormal number  -- singled biased exponent is 0
+        uHalfBiasedExponent = 0;
+        uHalfSignificand    = 0; // Any subnormal single will be too small to express as a half precision
+    } else if(nSingleUnbiasedExponent > HALF_EXPONENT_MAX) {
+        // Exponent is too large to express in half-precision; round up to infinity
+        uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
+        uHalfSignificand    = 0;
+    } else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) {
+        // Exponent is too small to express in half-precision normal; make it a half-precision subnormal
+        uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS);
+        // Difference between single normal exponent and the base exponent of a half subnormal
+        const uint32_t nExpDiff = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN);
+        // Also have to shift the significand by the difference in number of bits between a single and a half significand
+        const int32_t nSignificandBitsDiff = SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
+        // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
+        const uint32_t uSingleSignificandSubnormal = uSingleSignificand + (0x01L << SINGLE_NUM_SIGNIFICAND_BITS);
+        uHalfSignificand = uSingleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
+    } else {
+        // The normal case
+        uHalfBiasedExponent = nSingleUnbiasedExponent + HALF_EXPONENT_BIAS;
+        uHalfSignificand    = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+    }
+    uHalfSign = uSingleSign;
+
+    // Put the 3 values in the right place for a half precision
+    const uint16_t uHalfPrecision =  uHalfSignificand |
+                                    (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
+                                    (uHalfSign << HALF_SIGN_SHIFT);
+    return uHalfPrecision;
+}
+
+
+// Public function; see ieee754.h
+uint16_t IEEE754_DoubleToHalf(double d)
+{
+    // Pull the three parts out of the double-precision float
+    const uint64_t uDouble = CopyDoubleToUint64(d);
+    const int64_t  nDoubleUnbiasedExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
+    const uint64_t uDoubleSign             =  (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT;
+    const uint64_t uDoubleSignificand      =   uDouble & DOUBLE_SIGNIFICAND_MASK;
+
+
+    // Now convert the three parts to half-precision.
+    uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+    if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
+        // +/- Infinity and NaNs -- single biased exponent is 0xff
+        uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
+        if(!uDoubleSignificand) {
+            // Infinity
+            uHalfSignificand = 0;
+        } else {
+            // Copy the LBSs of the NaN payload that will fit from the double to the half
+            uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT);
+            if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) {
+                // It's a qNaN; copy the qNaN bit
+                uHalfSignificand |= HALF_QUIET_NAN_BIT;
+            } else {
+                // It's an sNaN; make sure the significand is not zero so it stays a NaN
+                // This is needed because not all significand bits are copied from single
+                if(!uHalfSignificand) {
+                    // Set the LSB. This is what wikipedia shows for sNAN.
+                    uHalfSignificand |= 0x01;
+                }
+            }
+        }
+    } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) {
+        // 0 or a subnormal number  -- double biased exponent is 0
+        uHalfBiasedExponent = 0;
+        uHalfSignificand    = 0; // Any subnormal single will be too small to express as a half precision; TODO, is this really true?
+    } else if(nDoubleUnbiasedExponent > HALF_EXPONENT_MAX) {
+        // Exponent is too large to express in half-precision; round up to infinity; TODO, is this really true?
+        uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
+        uHalfSignificand    = 0;
+    } else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) {
+        // Exponent is too small to express in half-precision; round down to zero
+        uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS);
+        // Difference between double normal exponent and the base exponent of a half subnormal
+        const uint64_t nExpDiff = -(nDoubleUnbiasedExponent - HALF_EXPONENT_MIN);
+        // Also have to shift the significand by the difference in number of bits between a double and a half significand
+        const int64_t nSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
+        // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
+        const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01ULL << DOUBLE_NUM_SIGNIFICAND_BITS);
+        uHalfSignificand = uDoubleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
+    } else {
+        // The normal case
+        uHalfBiasedExponent = nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS;
+        uHalfSignificand    = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+    }
+    uHalfSign = uDoubleSign;
+
+
+    // Put the 3 values in the right place for a half precision
+    const uint16_t uHalfPrecision =  uHalfSignificand |
+                                    (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
+                                    (uHalfSign << HALF_SIGN_SHIFT);
+    return uHalfPrecision;
+}
+
+
+// Public function; see ieee754.h
+float IEEE754_HalfToFloat(uint16_t uHalfPrecision)
+{
+    // Pull out the three parts of the half-precision float
+    const uint16_t uHalfSignificand      =   uHalfPrecision & HALF_SIGNIFICAND_MASK;
+    const int16_t  nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
+    const uint16_t uHalfSign             =  (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
+
+
+    // Make the three parts of the single-precision number
+    uint32_t uSingleSignificand, uSingleSign, uSingleBiasedExponent;
+    if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) {
+        // 0 or subnormal
+        if(uHalfSignificand) {
+            // Subnormal case
+            uSingleBiasedExponent = -HALF_EXPONENT_BIAS + SINGLE_EXPONENT_BIAS +1;
+            // A half-precision subnormal can always be converted to a normal single-precision float because the ranges line up
+            uSingleSignificand = uHalfSignificand;
+            // Shift bits from right of the decimal to left, reducing the exponent by 1 each time
+            do {
+                uSingleSignificand <<= 1;
+                uSingleBiasedExponent--;
+            } while ((uSingleSignificand & 0x400) == 0);
+            uSingleSignificand &= HALF_SIGNIFICAND_MASK;
+            uSingleSignificand <<= (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+        } else {
+            // Just zero
+            uSingleBiasedExponent = SINGLE_EXPONENT_ZERO + SINGLE_EXPONENT_BIAS;
+            uSingleSignificand = 0;
+        }
+    } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) {
+        // NaN or Inifinity
+        uSingleBiasedExponent = SINGLE_EXPONENT_INF_OR_NAN + SINGLE_EXPONENT_BIAS;
+        if(uHalfSignificand) {
+            // NaN
+            // First preserve the NaN payload from half to single
+            uSingleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT;
+            if(uHalfSignificand & HALF_QUIET_NAN_BIT) {
+                // Next, set qNaN if needed since half qNaN bit is not copied above
+                uSingleSignificand |= SINGLE_QUIET_NAN_BIT;
+            }
+        } else {
+            // Infinity
+            uSingleSignificand = 0;
+        }
+    } else {
+        // Normal number
+        uSingleBiasedExponent = nHalfUnBiasedExponent + SINGLE_EXPONENT_BIAS;
+        uSingleSignificand = uHalfSignificand << (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+    }
+    uSingleSign = uHalfSign;
+
+
+    // Shift the three parts of the single precision into place
+    const uint32_t uSinglePrecision = uSingleSignificand |
+                                     (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) |
+                                     (uSingleSign << SINGLE_SIGN_SHIFT);
+
+    return CopyUint32ToFloat(uSinglePrecision);
+}
+
+
+// Public function; see ieee754.h
+double IEEE754_HalfToDouble(uint16_t uHalfPrecision)
+{
+    // Pull out the three parts of the half-precision float
+    const uint16_t uHalfSignificand      =   uHalfPrecision & HALF_SIGNIFICAND_MASK;
+    const int16_t  nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
+    const uint16_t uHalfSign             =  (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
+
+
+    // Make the three parts of hte single-precision number
+    uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent;
+    if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) {
+        // 0 or subnormal
+        uDoubleBiasedExponent = DOUBLE_EXPONENT_ZERO + DOUBLE_EXPONENT_BIAS;
+        if(uHalfSignificand) {
+            // Subnormal case
+            uDoubleBiasedExponent = -HALF_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS +1;
+            // A half-precision subnormal can always be converted to a normal double-precision float because the ranges line up
+            uDoubleSignificand = uHalfSignificand;
+            // Shift bits from right of the decimal to left, reducing the exponent by 1 each time
+            do {
+                uDoubleSignificand <<= 1;
+                uDoubleBiasedExponent--;
+            } while ((uDoubleSignificand & 0x400) == 0);
+            uDoubleSignificand &= HALF_SIGNIFICAND_MASK;
+            uDoubleSignificand <<= (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+        } else {
+            // Just zero
+            uDoubleSignificand = 0;
+        }
+    } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) {
+        // NaN or Inifinity
+        uDoubleBiasedExponent = DOUBLE_EXPONENT_INF_OR_NAN + DOUBLE_EXPONENT_BIAS;
+        if(uHalfSignificand) {
+            // NaN
+            // First preserve the NaN payload from half to single
+            uDoubleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT;
+            if(uHalfSignificand & HALF_QUIET_NAN_BIT) {
+                // Next, set qNaN if needed since half qNaN bit is not copied above
+                uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT;
+            }
+        } else {
+            // Infinity
+            uDoubleSignificand = 0;
+        }
+    } else {
+        // Normal number
+        uDoubleBiasedExponent = nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS;
+        uDoubleSignificand    = (uint64_t)uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+    }
+    uDoubleSign = uHalfSign;
+
+
+    // Shift the 3 parts into place as a double-precision
+    const uint64_t uDouble = uDoubleSignificand |
+                            (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) |
+                            (uDoubleSign << DOUBLE_SIGN_SHIFT);
+    return CopyUint64ToDouble(uDouble);
+}
+
+
+// Public function; see ieee754.h
+IEEE754_union IEEE754_FloatToSmallest(float f)
+{
+    IEEE754_union result;
+
+    // Pull the neeed two parts out of the single-precision float
+    const uint32_t uSingle = CopyFloatToUint32(f);
+    const int32_t  nSingleExponent    = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
+    const uint32_t uSingleSignificand =   uSingle & SINGLE_SIGNIFICAND_MASK;
+
+    // Bit mask that is the significand bits that would be lost when converting
+    // from single-precision to half-precision
+    const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
+
+    // Optimizer will re organize so there is only one call to IEEE754_FloatToHalf()
+    if(uSingle == 0) {
+        // Value is 0.0000, not a a subnormal
+        result.uSize = IEEE754_UNION_IS_HALF;
+        result.uValue  = IEEE754_FloatToHalf(f);
+    } else if(nSingleExponent == SINGLE_EXPONENT_INF_OR_NAN) {
+        // NaN, +/- infinity
+        result.uSize = IEEE754_UNION_IS_HALF;
+        result.uValue  = IEEE754_FloatToHalf(f);
+    } else if((nSingleExponent >= HALF_EXPONENT_MIN) && nSingleExponent <= HALF_EXPONENT_MAX && (!(uSingleSignificand & uDroppedSingleBits))) {
+        // Normal number in exponent range and precision won't be lost
+        result.uSize = IEEE754_UNION_IS_HALF;
+        result.uValue  = IEEE754_FloatToHalf(f);
+    } else {
+        // Subnormal, exponent out of range, or precision will be lost
+        result.uSize = IEEE754_UNION_IS_SINGLE;
+        result.uValue  = uSingle;
+    }
+
+    return result;
+}
+
+// Public function; see ieee754.h
+IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision)
+{
+    IEEE754_union result;
+
+    // Pull the needed two parts out of the double-precision float
+    const uint64_t uDouble = CopyDoubleToUint64(d);
+    const int64_t  nDoubleExponent     = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
+    const uint64_t uDoubleSignificand  =   uDouble & DOUBLE_SIGNIFICAND_MASK;
+
+    // Masks to check whether dropped significand bits are zero or not
+    const uint64_t uDroppedDoubleBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
+    const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS;
+
+    // The various cases
+    if(d == 0.0) { // Take care of positive and negative zero
+        // Value is 0.0000, not a a subnormal
+        result.uSize  = IEEE754_UNION_IS_HALF;
+        result.uValue = IEEE754_DoubleToHalf(d);
+    } else if(nDoubleExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
+        // NaN, +/- infinity
+        result.uSize  = IEEE754_UNION_IS_HALF;
+        result.uValue = IEEE754_DoubleToHalf(d);
+    } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedDoubleBits))) {
+        // Can convert to half without precision loss
+        result.uSize  = IEEE754_UNION_IS_HALF;
+        result.uValue = IEEE754_DoubleToHalf(d);
+    } else if((nDoubleExponent >= SINGLE_EXPONENT_MIN) && nDoubleExponent <= SINGLE_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedSingleBits))) {
+        // Can convert to single without precision loss
+        result.uSize  = IEEE754_UNION_IS_SINGLE;
+        result.uValue = CopyFloatToUint32((float)d);
+    } else {
+        // Can't convert without precision loss
+        result.uSize  = IEEE754_UNION_IS_DOUBLE;
+        result.uValue = uDouble;
+    }
+
+    return result;
+}
+
diff --git a/lib/ext/qcbor/src/ieee754.h b/lib/ext/qcbor/src/ieee754.h
new file mode 100644
index 0000000..2530f98
--- /dev/null
+++ b/lib/ext/qcbor/src/ieee754.h
@@ -0,0 +1,168 @@
+/*==============================================================================
+ ieee754.c -- floating point conversion between half, double and single precision
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 7/23/18
+ ==============================================================================*/
+
+#ifndef ieee754_h
+#define ieee754_h
+
+#include <stdint.h>
+
+
+
+/*
+ General comments
+
+ This is a complete in that it handles all conversion cases
+ including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN
+ and NaN payloads.
+
+ This confirms to IEEE 754-2008, but note that this doesn't
+ specify conversions, just the encodings.
+
+ NaN payloads are preserved with alignment on the LSB. The
+ qNaN bit is handled differently and explicity copied. It
+ is always the MSB of the significand. The NaN payload MSBs
+ (except the qNaN bit) are truncated when going from
+ double or single to half.
+
+ TODO: what does the C cast do with NaN payloads from
+ double to single?
+
+
+
+ */
+
+/*
+ Most simply just explicilty encode the type you want, single or double.
+ This works easily everywhere since standard C supports both
+ these types and so does qcbor.  This encoder also supports
+ half precision and there's a few ways to use it to encode
+ floating point numbers in less space.
+
+ Without losing precision, you can encode a single or double
+ such that the special values of 0, NaN and Infinity encode
+ as half-precision.  This CBOR decodoer and most others
+ should handle this properly.
+
+ If you don't mind losing precision, then you can use half-precision.
+ One way to do this is to set up your environment to use
+ ___fp_16. Some compilers and CPUs support it even though it is not
+ standard C. What is nice about this is that your program
+ will use less memory and floating point operations like
+ multiplying, adding and such will be faster.
+
+ Another way to make use of half-precision is to represent
+ the values in your program as single or double, but encode
+ them in CBOR as half-precision. This cuts the size
+ of the encoded messages by 2 or 4, but doesn't reduce
+ memory needs or speed because you are still using
+ single or double in your code.
+
+
+ encode:
+    - float as float
+    - double as double
+    - half as half
+ - float as half_precision, for environments that don't support a half-precision type
+ - double as half_precision, for environments that don't support a half-precision type
+ - float with NaN, Infinity and 0 as half
+ - double with NaN, Infinity and 0 as half
+
+
+
+
+ */
+
+
+
+/*
+ Convert single precision float to half-precision float.
+ Precision and NaN payload bits will be lost. Too large
+ values will round up to infinity and too small to zero.
+ */
+uint16_t IEEE754_FloatToHalf(float f);
+
+
+/*
+ Convert half precision float to single precision float.
+ This is a loss-less conversion.
+ */
+float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
+
+
+/*
+ Convert double precision float to half-precision float.
+ Precision and NaN payload bits will be lost. Too large
+ values will round up to infinity and too small to zero.
+ */
+uint16_t IEEE754_DoubleToHalf(double d);
+
+
+/*
+ Convert half precision float to double precision float.
+ This is a loss-less conversion.
+ */
+double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
+
+
+
+// Both tags the value and gives the size
+#define IEEE754_UNION_IS_HALF   2
+#define IEEE754_UNION_IS_SINGLE 4
+#define IEEE754_UNION_IS_DOUBLE 8
+
+typedef struct {
+    uint8_t uSize;  // One of IEEE754_IS_xxxx
+    uint64_t uValue;
+} IEEE754_union;
+
+
+/*
+ Converts double-precision to single-precision or half-precision if possible without
+ loss of precisions. If not, leaves it as a double. Only converts to single-precision
+ unless bAllowHalfPrecision is set.
+ */
+IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision);
+
+/*
+ Converts double-precision to single-precision if possible without
+ loss of precision. If not, leaves it as a double.
+ */
+static inline IEEE754_union IEEE754_DoubleToSmall(double d)
+{
+    return IEEE754_DoubleToSmallestInternal(d, 0);
+}
+
+
+/*
+ Converts double-precision to single-precision or half-precision if possible without
+ loss of precisions. If not, leaves it as a double.
+ */
+static inline IEEE754_union IEEE754_DoubleToSmallest(double d)
+{
+    return IEEE754_DoubleToSmallestInternal(d, 1);
+}
+
+/*
+ Converts single-precision to half-precision if possible without
+ loss of precision. If not leaves as single-precision.
+ */
+IEEE754_union IEEE754_FloatToSmallest(float f);
+
+
+#endif /* ieee754_h */
+
+
+
+
+
+
+
diff --git a/lib/ext/qcbor/src/qcbor_decode.c b/lib/ext/qcbor/src/qcbor_decode.c
new file mode 100644
index 0000000..2286038
--- /dev/null
+++ b/lib/ext/qcbor/src/qcbor_decode.c
@@ -0,0 +1,1319 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+/*===================================================================================
+ FILE:  qcbor_decode.c
+
+ DESCRIPTION:  This file contains the implementation of QCBOR.
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when               who             what, where, why
+ --------           ----            ---------------------------------------------------
+ 01/10/19           llundblade      Clever type and argument decoder is 250 bytes smaller
+ 11/9/18            llundblade      Error codes are now enums.
+ 11/2/18            llundblade      Simplify float decoding and align with preferred
+                                    float encoding
+ 10/31/18           llundblade      Switch to one license that is almost BSD-3.
+ 10/28/18           llundblade      Reworked tag decoding
+ 10/15/18           llundblade      Indefinite length maps and arrays supported
+ 10/8/18            llundblade      Indefinite length strings supported
+ 02/04/17           llundbla        Work on CPUs that don's require pointer alignment
+                                    by making use of changes in UsefulBuf
+ 03/01/17           llundbla        More data types; decoding improvements and fixes
+ 11/13/16           llundbla        Integrate most TZ changes back into github version.
+ 09/30/16           gkanike         Porting to TZ.
+ 03/15/16           llundbla        Initial Version.
+
+ =====================================================================================*/
+
+#include "qcbor.h"
+#include "ieee754.h"
+
+
+/*
+ This casts away the const-ness of a pointer, usually so it can be
+ freed or realloced.
+ */
+#define UNCONST_POINTER(ptr)    ((void *)(ptr))
+
+
+/*
+ Collection of functions to track the map/array nesting for decoding
+ */
+
+inline static int IsMapOrArray(uint8_t uDataType)
+{
+   return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY;
+}
+
+inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting)
+{
+   return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]);
+}
+
+inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
+{
+   return pNesting->pCurrent->uCount == UINT16_MAX;
+}
+
+inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
+{
+   return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
+}
+
+inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
+{
+   if(!DecodeNesting_IsNested(pNesting)) {
+      return 0;
+   }
+
+   return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
+}
+
+// Process a break. This will either ascend the nesting or error out
+inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
+{
+   // breaks must always occur when there is nesting
+   if(!DecodeNesting_IsNested(pNesting)) {
+      return QCBOR_ERR_BAD_BREAK;
+   }
+
+   // breaks can only occur when the map/array is indefinite length
+   if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
+      return QCBOR_ERR_BAD_BREAK;
+   }
+
+   // if all OK, the break reduces the level of nesting
+   pNesting->pCurrent--;
+
+   return QCBOR_SUCCESS;
+}
+
+// Called on every single item except breaks including the opening of a map/array
+inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
+{
+   if(!DecodeNesting_IsNested(pNesting)) {
+      // at top level where there is no tracking
+      return;
+   }
+
+   if(DecodeNesting_IsIndefiniteLength(pNesting)) {
+      // There is no count for indefinite length arrays/maps
+      return;
+   }
+
+   // Decrement the count of items in this array/map
+   pNesting->pCurrent->uCount--;
+
+   // Pop up nesting levels if the counts at the levels are zero
+   while(DecodeNesting_IsNested(pNesting) && 0 == pNesting->pCurrent->uCount) {
+      pNesting->pCurrent--;
+      if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
+         pNesting->pCurrent->uCount--;
+      }
+   }
+}
+
+// Called on every map/array
+inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
+{
+   QCBORError nReturn = QCBOR_SUCCESS;
+
+   if(pItem->val.uCount == 0) {
+      // Nothing to do for empty definite lenth arrays. They are just are
+      // effectively the same as an item that is not a map or array
+      goto Done;
+      // Empty indefinite length maps and arrays are handled elsewhere
+   }
+
+   // Error out if arrays is too long to handle
+   if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
+      nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
+      goto Done;
+   }
+
+   // Error out if nesting is too deep
+   if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
+      nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
+      goto Done;
+   }
+
+   // The actual descend
+   pNesting->pCurrent++;
+
+   // Record a few details for this nesting level
+   pNesting->pCurrent->uMajorType = pItem->uDataType;
+   pNesting->pCurrent->uCount     = pItem->val.uCount;
+
+Done:
+   return nReturn;;
+}
+
+inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting)
+{
+   pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
+}
+
+
+
+/*
+ This list of built-in tags. Only add tags here that are
+ clearly established and useful. Once a tag is added here
+ it can't be taken out as that would break backwards compatibility.
+ There are only 48 slots available forever.
+ */
+static const uint16_t spBuiltInTagMap[] = {
+   CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_FOUR
+   CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_FOUR
+   CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
+   CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
+   CBOR_TAG_FRACTION,
+   CBOR_TAG_BIGFLOAT,
+   CBOR_TAG_COSE_ENCRYPTO,
+   CBOR_TAG_COSE_MAC0,
+   CBOR_TAG_COSE_SIGN1,
+   CBOR_TAG_ENC_AS_B64URL,
+   CBOR_TAG_ENC_AS_B64,
+   CBOR_TAG_ENC_AS_B16,
+   CBOR_TAG_CBOR,
+   CBOR_TAG_URI,
+   CBOR_TAG_B64URL,
+   CBOR_TAG_B64,
+   CBOR_TAG_REGEX,
+   CBOR_TAG_MIME,
+   CBOR_TAG_BIN_UUID,
+   CBOR_TAG_CWT,
+   CBOR_TAG_ENCRYPT,
+   CBOR_TAG_MAC,
+   CBOR_TAG_SIGN,
+   CBOR_TAG_GEO_COORD,
+   CBOR_TAG_CBOR_MAGIC
+};
+
+// This is used in a bit of cleverness in GetNext_TaggedItem() to
+// keep code size down and switch for the internal processing of
+// these types. This will break if the first four items in
+// spBuiltInTagMap don't have values 0,1,2,3. That is the
+// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3.
+#define QCBOR_TAGFLAG_DATE_STRING    (0x01LL << CBOR_TAG_DATE_STRING)
+#define QCBOR_TAGFLAG_DATE_EPOCH     (0x01LL << CBOR_TAG_DATE_EPOCH)
+#define QCBOR_TAGFLAG_POS_BIGNUM     (0x01LL << CBOR_TAG_POS_BIGNUM)
+#define QCBOR_TAGFLAG_NEG_BIGNUM     (0x01LL << CBOR_TAG_NEG_BIGNUM)
+
+#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
+                               QCBOR_TAGFLAG_DATE_EPOCH  |\
+                               QCBOR_TAGFLAG_POS_BIGNUM  |\
+                               QCBOR_TAGFLAG_NEG_BIGNUM)
+
+#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t
+#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48
+#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48
+
+static inline int TagMapper_LookupBuiltIn(uint64_t uTag)
+{
+   if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) {
+      // This is a cross-check to make sure the above array doesn't
+      // accidentally get made too big.
+      // In normal conditions the above test should optimize out
+      // as all the values are known at compile time.
+      return -1;
+   }
+
+   if(uTag > UINT16_MAX) {
+      // This tag map works only on 16-bit tags
+      return -1;
+   }
+
+   for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) {
+      if(spBuiltInTagMap[nTagBitIndex] == uTag) {
+         return nTagBitIndex;
+      }
+   }
+   return -1; // Indicates no match
+}
+
+static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag)
+{
+   for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) {
+      if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) {
+         return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX;
+      }
+   }
+
+   return -1; // Indicates no match
+}
+
+/*
+  Find the tag bit index for a given tag value, or error out
+
+ This and the above functions could probably be optimized and made
+ clearer and neater.
+ */
+static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex)
+{
+   int nTagBitIndex = TagMapper_LookupBuiltIn(uTag);
+   if(nTagBitIndex >= 0) {
+      // Cast is safe because TagMapper_LookupBuiltIn never returns > 47
+      *puTagBitIndex = (uint8_t)nTagBitIndex;
+      return QCBOR_SUCCESS;
+   }
+
+   if(pCallerConfiguredTagMap) {
+      if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) {
+         return QCBOR_ERR_TOO_MANY_TAGS;
+      }
+      nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag);
+      if(nTagBitIndex >= 0) {
+         // Cast is safe because TagMapper_LookupBuiltIn never returns > 63
+
+         *puTagBitIndex = (uint8_t)nTagBitIndex;
+         return QCBOR_SUCCESS;
+      }
+   }
+
+   return QCBOR_ERR_BAD_OPT_TAG;
+}
+
+
+
+
+/*
+ Public function, see header file
+ */
+void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode)
+{
+   memset(me, 0, sizeof(QCBORDecodeContext));
+   UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
+   // Don't bother with error check on decode mode. If a bad value is passed it will just act as
+   // if the default normal mode of 0 was set.
+   me->uDecodeMode = nDecodeMode;
+   DecodeNesting_Init(&(me->nesting));
+}
+
+
+/*
+ Public function, see header file
+ */
+void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllocAll)
+{
+   pCtx->pStringAllocator = (void *)pAllocator;
+   pCtx->bStringAllocateAll = bAllocAll;
+}
+
+void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList)
+{
+   me->pCallerConfiguredTagList = pTagList;
+}
+
+
+/*
+ This decodes the fundamental part of a CBOR data item, the type and number
+
+ This is the Counterpart to InsertEncodedTypeAndNumber().
+
+ This does the network->host byte order conversion. The conversion here
+ also results in the conversion for floats in addition to that for
+ lengths, tags and integer values.
+
+ This returns:
+   pnMajorType -- the major type for the item
+   puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays
+   puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite
+
+ */
+inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
+                                              int *pnMajorType,
+                                              uint64_t *puArgument,
+                                              uint8_t *puAdditionalInfo)
+{
+   QCBORError nReturn;
+
+   // Get the initial byte that every CBOR data item has
+   const uint8_t uInitialByte = UsefulInputBuf_GetByte(pUInBuf);
+
+   // Break down the initial byte
+   const uint8_t uTmpMajorType   = uInitialByte >> 5;
+   const uint8_t uAdditionalInfo = uInitialByte & 0x1f;
+
+   // Where the number or argument accumulates
+   uint64_t uArgument;
+
+   if(uAdditionalInfo >= LEN_IS_ONE_BYTE && uAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
+      // Need to get 1,2,4 or 8 additional argument bytes
+      // Map LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length
+      static const uint8_t aIterate[] = {1,2,4,8};
+
+      // Loop getting all the bytes in the argument
+      uArgument = 0;
+      for(int i = aIterate[uAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
+         // This shift and add gives the endian conversion
+         uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
+      }
+   } else if(uAdditionalInfo >= ADDINFO_RESERVED1 && uAdditionalInfo <= ADDINFO_RESERVED3) {
+      // The reserved and thus-far unused additional info values
+      nReturn = QCBOR_ERR_UNSUPPORTED;
+      goto Done;
+   } else {
+      // Less than 24, additional info is argument or 31, an indefinite length
+      // No more bytes to get
+      uArgument = uAdditionalInfo;
+   }
+
+   if(UsefulInputBuf_GetError(pUInBuf)) {
+      nReturn = QCBOR_ERR_HIT_END;
+      goto Done;
+   }
+
+   // All successful if we got here.
+   nReturn           = QCBOR_SUCCESS;
+   *pnMajorType      = uTmpMajorType;
+   *puArgument       = uArgument;
+   *puAdditionalInfo = uAdditionalInfo;
+
+Done:
+   return nReturn;
+}
+
+/*
+ CBOR doesn't explicitly specify two's compliment for integers but all CPUs
+ use it these days and the test vectors in the RFC are so. All integers in the CBOR
+ structure are positive and the major type indicates positive or negative.
+ CBOR can express positive integers up to 2^x - 1 where x is the number of bits
+ and negative integers down to 2^x.  Note that negative numbers can be one
+ more away from zero than positive.
+ Stdint, as far as I can tell, uses two's compliment to represent
+ negative integers.
+
+ See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
+ used here in any way including in the interface
+ */
+inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
+{
+   // Stack usage: int/ptr 1 -- 8
+   QCBORError nReturn = QCBOR_SUCCESS;
+
+   if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
+      if (uNumber <= INT64_MAX) {
+         pDecodedItem->val.int64 = (int64_t)uNumber;
+         pDecodedItem->uDataType = QCBOR_TYPE_INT64;
+
+      } else {
+         pDecodedItem->val.uint64 = uNumber;
+         pDecodedItem->uDataType  = QCBOR_TYPE_UINT64;
+
+      }
+   } else {
+      if(uNumber <= INT64_MAX) {
+         pDecodedItem->val.int64 = -uNumber-1;
+         pDecodedItem->uDataType = QCBOR_TYPE_INT64;
+
+      } else {
+         // C can't represent a negative integer in this range
+         // so it is an error.  todo -- test this condition
+         nReturn = QCBOR_ERR_INT_OVERFLOW;
+      }
+   }
+
+   return nReturn;
+}
+
+// Make sure #define value line up as DecodeSimple counts on this.
+#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
+#error QCBOR_TYPE_FALSE macro value wrong
+#endif
+
+#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
+#error QCBOR_TYPE_TRUE macro value wrong
+#endif
+
+#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
+#error QCBOR_TYPE_NULL macro value wrong
+#endif
+
+#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
+#error QCBOR_TYPE_UNDEF macro value wrong
+#endif
+
+#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
+#error QCBOR_TYPE_BREAK macro value wrong
+#endif
+
+#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
+#error QCBOR_TYPE_DOUBLE macro value wrong
+#endif
+
+#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
+#error QCBOR_TYPE_FLOAT macro value wrong
+#endif
+
+/*
+ Decode true, false, floats, break...
+ */
+
+inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
+{
+   // Stack usage: 0
+   QCBORError nReturn = QCBOR_SUCCESS;
+
+   // uAdditionalInfo is 5 bits from the initial byte
+   // compile time checks above make sure uAdditionalInfo values line up with uDataType values
+   pDecodedItem->uDataType = uAdditionalInfo;
+
+   switch(uAdditionalInfo) {
+      case ADDINFO_RESERVED1:  // 28
+      case ADDINFO_RESERVED2:  // 29
+      case ADDINFO_RESERVED3:  // 30
+         nReturn = QCBOR_ERR_UNSUPPORTED;
+         break;
+
+      case HALF_PREC_FLOAT:
+         pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
+         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+         break;
+      case SINGLE_PREC_FLOAT:
+         pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
+         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+         break;
+      case DOUBLE_PREC_FLOAT:
+         pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
+         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+         break;
+
+      case CBOR_SIMPLEV_FALSE: // 20
+      case CBOR_SIMPLEV_TRUE:  // 21
+      case CBOR_SIMPLEV_NULL:  // 22
+      case CBOR_SIMPLEV_UNDEF: // 23
+      case CBOR_SIMPLE_BREAK:  // 31
+         break; // nothing to do
+
+      case CBOR_SIMPLEV_ONEBYTE: // 24
+         if(uNumber <= CBOR_SIMPLE_BREAK) {
+            // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
+            nReturn = QCBOR_ERR_INVALID_CBOR;
+            goto Done;
+         }
+         /* FALLTHROUGH */
+         // fall through intentionally
+
+      default: // 0-19
+         pDecodedItem->uDataType   = QCBOR_TYPE_UKNOWN_SIMPLE;
+         // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24
+         // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above
+         pDecodedItem->val.uSimple = (uint8_t)uNumber;
+         break;
+   }
+
+Done:
+   return nReturn;
+}
+
+
+
+/*
+ Decode text and byte strings. Call the string allocator if asked to.
+ */
+inline static QCBORError DecodeBytes(const QCBORStringAllocator *pAlloc, int nMajorType, uint64_t uStrLen, UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem)
+{
+   // Stack usage: UsefulBuf 2, int/ptr 1  40
+   QCBORError nReturn = QCBOR_SUCCESS;
+
+   const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
+   if(UsefulBuf_IsNULLC(Bytes)) {
+      // Failed to get the bytes for this string item
+      nReturn = QCBOR_ERR_HIT_END;
+      goto Done;
+   }
+
+   if(pAlloc) {
+      // We are asked to use string allocator to make a copy
+      UsefulBuf NewMem = pAlloc->fAllocate(pAlloc->pAllocaterContext, NULL, uStrLen);
+      if(UsefulBuf_IsNULL(NewMem)) {
+         nReturn = QCBOR_ERR_STRING_ALLOCATE;
+         goto Done;
+      }
+      pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
+   } else {
+      // Normal case with no string allocator
+      pDecodedItem->val.string = Bytes;
+   }
+   pDecodedItem->uDataType  = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
+
+Done:
+   return nReturn;
+}
+
+
+/*
+ Mostly just assign the right data type for the date string.
+ */
+inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
+{
+   // Stack Use: UsefulBuf 1 16
+   if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
+      return QCBOR_ERR_BAD_OPT_TAG;
+   }
+
+   const UsefulBufC Temp        = pDecodedItem->val.string;
+   pDecodedItem->val.dateString = Temp;
+   pDecodedItem->uDataType      = QCBOR_TYPE_DATE_STRING;
+   return QCBOR_SUCCESS;
+}
+
+
+/*
+ Mostly just assign the right data type for the bignum.
+ */
+inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
+{
+   // Stack Use: UsefulBuf 1  -- 16
+   if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
+      return QCBOR_ERR_BAD_OPT_TAG;
+   }
+   const UsefulBufC Temp    = pDecodedItem->val.string;
+   pDecodedItem->val.bigNum = Temp;
+   pDecodedItem->uDataType  = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
+   return QCBOR_SUCCESS;
+}
+
+
+/*
+ The epoch formatted date. Turns lots of different forms of encoding date into uniform one
+ */
+static int DecodeDateEpoch(QCBORItem *pDecodedItem)
+{
+   // Stack usage: 1
+   QCBORError nReturn = QCBOR_SUCCESS;
+
+   pDecodedItem->val.epochDate.fSecondsFraction = 0;
+
+   switch (pDecodedItem->uDataType) {
+
+      case QCBOR_TYPE_INT64:
+         pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
+         break;
+
+      case QCBOR_TYPE_UINT64:
+         if(pDecodedItem->val.uint64 > INT64_MAX) {
+            nReturn = QCBOR_ERR_DATE_OVERFLOW;
+            goto Done;
+         }
+         pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64;
+         break;
+
+      case QCBOR_TYPE_DOUBLE:
+         {
+            const double d = pDecodedItem->val.dfnum;
+            if(d > INT64_MAX) {
+               nReturn = QCBOR_ERR_DATE_OVERFLOW;
+               goto Done;
+            }
+            pDecodedItem->val.epochDate.nSeconds = d; // Float to integer conversion happening here.
+            pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds;
+         }
+         break;
+
+      default:
+         nReturn = QCBOR_ERR_BAD_OPT_TAG;
+         goto Done;
+   }
+   pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
+
+Done:
+   return nReturn;
+}
+
+
+
+
+// Make sure the constants align as this is assumed by the GetAnItem() implementation
+#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
+#error QCBOR_TYPE_ARRAY value not lined up with major type
+#endif
+#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
+#error QCBOR_TYPE_MAP value not lined up with major type
+#endif
+
+/*
+ This gets a single data item and decodes it including preceding optional tagging. This does not
+ deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and
+ maps are handled at the next level up in GetNext().
+
+ Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly,
+    a few forms of invalid encoded CBOR
+ */
+static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem, const QCBORStringAllocator *pAlloc)
+{
+   // Stack usage: int/ptr 3 -- 24
+   QCBORError nReturn;
+
+   // Get the major type and the number. Number could be length of more bytes or the value depending on the major type
+   // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles
+   int      uMajorType;
+   uint64_t uNumber;
+   uint8_t  uAdditionalInfo;
+
+   nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
+
+   // Error out here if we got into trouble on the type and number.
+   // The code after this will not work if the type and number is not good.
+   if(nReturn)
+      goto Done;
+
+   memset(pDecodedItem, 0, sizeof(QCBORItem));
+
+   // At this point the major type and the value are valid. We've got the type and the number that
+   // starts every CBOR data item.
+   switch (uMajorType) {
+      case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
+      case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
+         nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
+         break;
+
+      case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
+      case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
+         if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+            pDecodedItem->uDataType  = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
+            pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
+         } else {
+            nReturn = DecodeBytes(pAlloc, uMajorType, uNumber, pUInBuf, pDecodedItem);
+         }
+         break;
+
+      case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
+      case CBOR_MAJOR_TYPE_MAP:   // Major type 5
+         // Record the number of items in the array or map
+         if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
+            nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
+            goto Done;
+         }
+         if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+            pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
+         } else {
+            pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above
+         }
+         pDecodedItem->uDataType  = uMajorType; // C preproc #if above makes sure constants align
+         break;
+
+      case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
+         pDecodedItem->val.uTagV = uNumber;
+         pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
+         break;
+
+      case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
+         nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem);
+         break;
+
+      default: // Should never happen because DecodeTypeAndNumber() should never return > 7
+         nReturn = QCBOR_ERR_UNSUPPORTED;
+         break;
+   }
+
+Done:
+   return nReturn;
+}
+
+
+
+/*
+ This layer deals with indefinite length strings. It pulls all the
+ individual chunk items together into one QCBORItem using the
+ string allocator.
+
+ Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
+ */
+static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
+{
+   // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem  -- 96
+   QCBORError nReturn;
+   QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)me->pStringAllocator;
+   UsefulBufC FullString = NULLUsefulBufC;
+
+   nReturn = GetNext_Item(&(me->InBuf), pDecodedItem, me->bStringAllocateAll ? pAlloc: NULL);
+   if(nReturn) {
+      goto Done;
+   }
+
+   // To reduce code size by removing support for indefinite length strings, the
+   // code in this function from here down can be eliminated. Run tests, except
+   // indefinite length string tests, to be sure all is OK if this is removed.
+
+   // Only do indefinite length processing on strings
+   if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
+      goto Done; // no need to do any work here on non-string types
+   }
+
+   // Is this a string with an indefinite length?
+   if(pDecodedItem->val.string.len != SIZE_MAX) {
+      goto Done; // length is not indefinite, so no work to do here
+   }
+
+   // Can't do indefinite length strings without a string allocator
+   if(pAlloc == NULL) {
+      nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
+      goto Done;
+   }
+
+   // There is an indefinite length string to work on...
+   // Track which type of string it is
+   const uint8_t uStringType = pDecodedItem->uDataType;
+
+   // Loop getting chunk of indefinite string
+   for(;;) {
+      // Get item for next chunk
+      QCBORItem StringChunkItem;
+      // NULL passed to never string alloc chunk of indefinite length strings
+      nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
+      if(nReturn) {
+         break;  // Error getting the next chunk
+      }
+
+      // See if it is a marker at end of indefinite length string
+      if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
+         // String is complete
+         pDecodedItem->val.string = FullString;
+         pDecodedItem->uDataAlloc = 1;
+         break;
+      }
+
+      // Match data type of chunk to type at beginning.
+      // Also catches error of other non-string types that don't belong.
+      if(StringChunkItem.uDataType != uStringType) {
+         nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
+         break;
+      }
+
+      // Alloc new buffer or expand previously allocated buffer so it can fit
+      UsefulBuf NewMem = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext,
+                                              UNCONST_POINTER(FullString.ptr),
+                                              FullString.len + StringChunkItem.val.string.len);
+      if(UsefulBuf_IsNULL(NewMem)) {
+         // Allocation of memory for the string failed
+         nReturn = QCBOR_ERR_STRING_ALLOCATE;
+         break;
+      }
+
+      // Copy new string chunk at the end of string so far.
+      FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
+   }
+
+Done:
+   if(pAlloc && nReturn && !UsefulBuf_IsNULLC(FullString)) {
+      // Getting item failed, clean up the allocated memory
+      (pAlloc->fFree)(pAlloc->pAllocaterContext, UNCONST_POINTER(FullString.ptr));
+   }
+
+   return nReturn;
+}
+
+
+/*
+ Returns an error if there was something wrong with the optional item or it couldn't
+ be handled.
+ */
+static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
+{
+   // Stack usage: int/ptr: 3 -- 24
+   QCBORError nReturn;
+   uint64_t  uTagBits = 0;
+   if(pTags) {
+      pTags->uNumUsed = 0;
+   }
+
+   for(;;) {
+      nReturn = GetNext_FullItem(me, pDecodedItem);
+      if(nReturn) {
+         goto Done; // Error out of the loop
+      }
+
+      if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
+         // Successful exit from loop; maybe got some tags, maybe not
+         pDecodedItem->uTagBits = uTagBits;
+         break;
+      }
+
+      uint8_t uTagBitIndex;
+      // Tag was mapped, tag was not mapped, error with tag list
+      switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
+
+         case QCBOR_SUCCESS:
+            // Successfully mapped the tag
+            uTagBits |= 0x01ULL << uTagBitIndex;
+            break;
+
+         case QCBOR_ERR_BAD_OPT_TAG:
+            // Tag is not recognized. Do nothing
+            break;
+
+         default:
+            // Error Condition
+            goto Done;
+      }
+
+      if(pTags) {
+         // Caller wants all tags recorded in the provided buffer
+         if(pTags->uNumUsed >= pTags->uNumAllocated) {
+            nReturn = QCBOR_ERR_TOO_MANY_TAGS;
+            goto Done;
+         }
+         pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV;
+         pTags->uNumUsed++;
+      }
+   }
+
+   switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) {
+      case 0:
+         // No tags at all or none we know about. Nothing to do.
+         // This is part of the pass-through path of this function
+         // that will mostly be taken when decoding any item.
+         break;
+
+      case QCBOR_TAGFLAG_DATE_STRING:
+         nReturn = DecodeDateString(pDecodedItem);
+         break;
+
+      case QCBOR_TAGFLAG_DATE_EPOCH:
+         nReturn = DecodeDateEpoch(pDecodedItem);
+         break;
+
+      case QCBOR_TAGFLAG_POS_BIGNUM:
+      case QCBOR_TAGFLAG_NEG_BIGNUM:
+         nReturn = DecodeBigNum(pDecodedItem);
+         break;
+
+      default:
+         // Encountering some mixed up CBOR like something that
+         // is tagged as both a string and integer date.
+         nReturn = QCBOR_ERR_BAD_OPT_TAG;
+   }
+
+Done:
+   return nReturn;
+}
+
+
+/*
+ This layer takes care of map entries. It combines the label and data items into one QCBORItem.
+ */
+static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
+{
+   // Stack use: int/ptr 1, QCBORItem  -- 56
+   QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
+   if(nReturn)
+      goto Done;
+
+   if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
+      // Break can't be a map entry
+      goto Done;
+   }
+
+   if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
+      // In a map and caller wants maps decoded, not treated as arrays
+
+      if(DecodeNesting_TypeIsMap(&(me->nesting))) {
+         // If in a map and the right decoding mode, get the label
+
+         // Get the next item which will be the real data; Item will be the label
+         QCBORItem LabelItem = *pDecodedItem;
+         nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
+         if(nReturn)
+            goto Done;
+
+         pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
+
+         if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
+            // strings are always good labels
+            pDecodedItem->label.string = LabelItem.val.string;
+            pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
+         } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
+            // It's not a string and we only want strings, probably for easy translation to JSON
+            nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
+            goto Done;
+         } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
+            pDecodedItem->label.int64 = LabelItem.val.int64;
+            pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
+         } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
+            pDecodedItem->label.uint64 = LabelItem.val.uint64;
+            pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
+         } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
+            pDecodedItem->label.string = LabelItem.val.string;
+            pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
+            pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
+         } else {
+            // label is not an int or a string. It is an arrray
+            // or a float or such and this implementation doesn't handle that.
+            // Also, tags on labels are ignored.
+            nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
+            goto Done;
+         }
+      }
+   } else {
+      if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
+         // Decoding a map as an array
+         pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
+         pDecodedItem->val.uCount *= 2;
+      }
+   }
+
+Done:
+   return nReturn;
+}
+
+
+/*
+ Public function, see header qcbor.h file
+ */
+QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
+{
+   // Stack ptr/int: 2, QCBORItem : 64
+
+   // The public entry point for fetching and parsing the next QCBORItem.
+   // All the CBOR parsing work is here and in subordinate calls.
+   QCBORError nReturn;
+
+   nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
+   if(nReturn) {
+      goto Done;
+   }
+
+   // Break ending arrays/maps are always processed at the end of this function.
+   // They should never show up here.
+   if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
+      nReturn = QCBOR_ERR_BAD_BREAK;
+      goto Done;
+   }
+
+   // Record the nesting level for this data item before processing any of
+   // decrementing and descending.
+   pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
+
+   // Process the item just received for descent or decrement, and
+   // ascent if decrements are enough to close out a definite length array/map
+   if(IsMapOrArray(pDecodedItem->uDataType)) {
+      // If the new item is array or map, the nesting level descends
+      nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem);
+      // Maps and arrays do count in as items in the map/array that encloses
+      // them so a decrement needs to be done for them too, but that is done
+      // only when all the items in them have been processed, not when they
+      // are opened.
+   } else {
+      // Decrement the count of items in the enclosing map/array
+      // If the count in the enclosing map/array goes to zero, that
+      // triggers a decrement in the map/array above that and
+      // an ascend in nesting level.
+      DecodeNesting_DecrementCount(&(me->nesting));
+   }
+   if(nReturn) {
+      goto Done;
+   }
+
+   // For indefinite length maps/arrays, looking at any and
+   // all breaks that might terminate them. The equivalent
+   // for definite length maps/arrays happens in
+   // DecodeNesting_DecrementCount().
+   if(DecodeNesting_IsNested(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
+      while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
+         // Peek forward one item to see if it is a break.
+         QCBORItem Peek;
+         size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
+         nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
+         if(nReturn) {
+            goto Done;
+         }
+         if(Peek.uDataType != QCBOR_TYPE_BREAK) {
+            // It is not a break, rewind so it can be processed normally.
+            UsefulInputBuf_Seek(&(me->InBuf), uPeek);
+            break;
+         }
+         // It is a break. Ascend one nesting level.
+         // The break is consumed.
+         nReturn = DecodeNesting_BreakAscend(&(me->nesting));
+         if(nReturn) {
+            // break occured outside of an indefinite length array/map
+            goto Done;
+         }
+      }
+   }
+
+   // Tell the caller what level is next. This tells them what maps/arrays
+   // were closed out and makes it possible for them to reconstruct
+   // the tree with just the information returned by GetNext
+   pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
+
+Done:
+   return nReturn;
+}
+
+
+QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
+{
+   return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
+}
+
+
+/*
+ Decoding items is done in 5 layered functions, one calling the
+ next one down. If a layer has no work to do for a particular item
+ it returns quickly.
+
+ - QCBORDecode_GetNext -- The top layer manages the beginnings and
+ ends of maps and arrays. It tracks descending into and ascending
+ out of maps/arrays. It processes all breaks that terminate
+ maps and arrays.
+
+ - GetNext_MapEntry -- This handles the combining of two
+ items, the label and the data, that make up a map entry.
+ It only does work on maps. It combines the label and data
+ items into one labeled item.
+
+ - GetNext_TaggedItem -- This handles the type 6 tagged items.
+ It accumulates all the tags and combines them with the following
+ non-tagged item. If the tagged item is something that is understood
+ like a date, the decoding of that item is invoked.
+
+ - GetNext_FullItem -- This assembles the sub items that make up
+ an indefinte length string into one string item. It uses the
+ string allocater to create contiguous space for the item. It
+ processes all breaks that are part of indefinite length strings.
+
+ - GetNext_Item -- This gets and decodes the most atomic
+ item in CBOR, the thing with an initial byte containing
+ the major type.
+
+ Roughly this takes 300 bytes of stack for vars. Need to
+ evaluate this more carefully and correctly.
+
+ */
+
+
+/*
+ Public function, see header qcbor.h file
+ */
+int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag)
+{
+   const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
+
+   uint8_t uTagBitIndex;
+   // Do not care about errors in pCallerConfiguredTagMap here. They are
+   // caught during GetNext() before this is called.
+   if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
+      return 0;
+   }
+
+   const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
+   return (uTagBit & pItem->uTagBits) != 0;
+}
+
+
+/*
+ Public function, see header qcbor.h file
+ */
+QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
+{
+   int nReturn = QCBOR_SUCCESS;
+
+   // Error out if all the maps/arrays are not closed out
+   if(DecodeNesting_IsNested(&(me->nesting))) {
+      nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
+      goto Done;
+   }
+
+   // Error out if not all the bytes are consumed
+   if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
+      nReturn = QCBOR_ERR_EXTRA_BYTES;
+   }
+
+Done:
+   // Call the destructor for the string allocator if there is one.
+   // Always called, even if there are errors; always have to clean up
+   if(me->pStringAllocator) {
+      QCBORStringAllocator *pAllocator = (QCBORStringAllocator *)me->pStringAllocator;
+      if(pAllocator->fDestructor) {
+         (pAllocator->fDestructor)(pAllocator->pAllocaterContext);
+      }
+   }
+
+   return nReturn;
+}
+
+
+
+/*
+
+Decoder errors handled in this file
+
+ - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END
+
+ - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
+
+ - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END
+
+ - Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED
+
+ - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG
+
+ - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
+
+ - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW
+
+ - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE
+
+ - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
+
+ */
+
+
+
+
+/*
+ This is a very primitive memory allocator. It does not track individual
+ allocations, only a high-water mark. A free or reallotcation must be of
+ the last chunk allocated.
+
+ All of this following code will get dead-stripped if QCBORDecode_SetMemPool()
+ is not called.
+ */
+
+typedef struct {
+   QCBORStringAllocator  StringAllocator;
+   uint8_t              *pStart;  // First byte that can be allocated
+   uint8_t              *pEnd;    // One past the last byte that can be allocated
+   uint8_t              *pFree;   // Where the next free chunk is
+} MemPool;
+
+
+/*
+ Internal function for an allocation
+
+ Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+static UsefulBuf MemPool_Alloc(void *ctx, void *pMem, size_t uNewSize)
+{
+   MemPool *me      = (MemPool *)ctx;
+   void    *pReturn = NULL;
+
+   if(pMem) {
+      // Realloc case
+      // This check will work even if uNewSize is a super-large value like UINT64_MAX
+      if((uNewSize <= (size_t)(me->pEnd - (uint8_t *)pMem)) && ((uint8_t *)pMem >= me->pStart)) {
+         me->pFree = (uint8_t *)pMem + uNewSize;
+         pReturn   = pMem;
+      }
+   } else {
+      // New chunk case
+      // This check will work even if uNewSize is a super large value like UINT64_MAX
+      if(uNewSize <= (size_t)(me->pEnd - me->pFree)) {
+         pReturn    = me->pFree;
+         me->pFree += uNewSize;
+      }
+   }
+
+   return (UsefulBuf){pReturn, uNewSize};
+}
+
+/*
+ Internal function to free memory
+ */
+static void MemPool_Free(void *ctx, void *pOldMem)
+{
+   MemPool *me = (MemPool *)ctx;
+   me->pFree   = pOldMem;
+}
+
+/*
+ Public function, see header qcbor.h file
+ */
+QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *me, UsefulBuf Pool, bool bAllStrings)
+{
+   // The idea behind QCBOR_MIN_MEM_POOL_SIZE is
+   // that the caller knows exactly what size to
+   // allocate and that the tests can run conclusively
+   // no matter what size MemPool is
+   // even though it wastes some memory. MemPool
+   // will vary depending on pointer size of the
+   // the machine. QCBOR_MIN_MEM_POOL_SIZE is
+   // set for pointers up to 64-bits. This
+   // wastes about 50 bytes on a 32-bit machine.
+   // This check makes sure things don't go
+   // horribly wrong. It should optimize out
+   // when there is no problem as the sizes are
+   // known at compile time.
+   if(sizeof(MemPool) > QCBOR_DECODE_MIN_MEM_POOL_SIZE) {
+      return QCBOR_ERR_MEM_POOL_INTERNAL;
+   }
+
+   // The first bytes of the Pool passed in are used
+   // as the context (vtable of sorts) for the memory pool
+   // allocator.
+   if(Pool.len < QCBOR_DECODE_MIN_MEM_POOL_SIZE) {
+      return QCBOR_ERR_BUFFER_TOO_SMALL;
+   }
+   MemPool *pMP = (MemPool *)Pool.ptr;
+
+   // Fill in the "vtable"
+   pMP->StringAllocator.fAllocate   = MemPool_Alloc;
+   pMP->StringAllocator.fFree       = MemPool_Free;
+   pMP->StringAllocator.fDestructor = NULL;
+
+   // Set up the pointers to the memory to be allocated
+   pMP->pStart = (uint8_t *)Pool.ptr + QCBOR_DECODE_MIN_MEM_POOL_SIZE;
+   pMP->pFree  = pMP->pStart;
+   pMP->pEnd   = (uint8_t *)Pool.ptr + Pool.len;
+
+   // More book keeping of context
+   pMP->StringAllocator.pAllocaterContext = pMP;
+   me->pStringAllocator   = pMP;
+
+   // The flag indicating when to use the allocator
+   me->bStringAllocateAll = bAllStrings;
+
+   return QCBOR_SUCCESS;
+}
+
+
+/*
+ Extra little hook to make MemPool testing work right
+ without adding any code size or overhead to non-test
+ uses. This will get dead-stripped for non-test use.
+
+ This is not a public function.
+ */
+size_t MemPoolTestHook_GetPoolSize(void *ctx)
+{
+   MemPool *me = (MemPool *)ctx;
+
+   return me->pEnd - me->pStart;
+}
+
diff --git a/lib/ext/qcbor/src/qcbor_encode.c b/lib/ext/qcbor/src/qcbor_encode.c
new file mode 100644
index 0000000..460dd85
--- /dev/null
+++ b/lib/ext/qcbor/src/qcbor_encode.c
@@ -0,0 +1,650 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+/*===================================================================================
+ FILE:  qcbor_encode.c
+
+ DESCRIPTION:  This file contains the implementation of QCBOR.
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when               who             what, where, why
+ --------           ----            ---------------------------------------------------
+ 12/30/18           llundblade      Small efficient clever encode of type & argument.
+ 11/29/18           llundblade      Rework to simpler handling of tags and labels.
+ 11/9/18            llundblade      Error codes are now enums.
+ 11/1/18            llundblade      Floating support.
+ 10/31/18           llundblade      Switch to one license that is almost BSD-3.
+ 09/28/18           llundblade      Added bstr wrapping feature for COSE implementation.
+ 02/05/18           llundbla        Works on CPUs which require integer alignment.
+                                    Requires new version of UsefulBuf.
+ 07/05/17           llundbla        Add bstr wrapping of maps/arrays for COSE
+ 03/01/17           llundbla        More data types
+ 11/13/16           llundbla        Integrate most TZ changes back into github version.
+ 09/30/16           gkanike         Porting to TZ.
+ 03/15/16           llundbla        Initial Version.
+
+ =====================================================================================*/
+
+#include "qcbor.h"
+#include "ieee754.h"
+
+
+/*...... This is a ruler that is 80 characters long...........................*/
+
+
+/*
+ CBOR's two nesting types, arrays and maps, are tracked here. There is a
+ limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
+ that can be nested in one encoding so the encoding context stays
+ small enough to fit on the stack.
+
+ When an array / map is opened, pCurrentNesting points to the element
+ in pArrays that records the type, start position and accumluates a
+ count of the number of items added. When closed the start position is
+ used to go back and fill in the type and number of items in the array
+ / map.
+
+ Encoded output be just items like ints and strings that are
+ not part of any array / map. That is, the first thing encoded
+ does not have to be an array or a map.
+ */
+inline static void Nesting_Init(QCBORTrackNesting *pNesting)
+{
+   // assumes pNesting has been zeroed
+   pNesting->pCurrentNesting = &pNesting->pArrays[0];
+   // Implied CBOR array at the top nesting level. This is never returned,
+   // but makes the item count work correctly.
+   pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
+}
+
+inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
+                                          uint8_t uMajorType,
+                                          uint32_t uPos)
+{
+   QCBORError nReturn = QCBOR_SUCCESS;
+
+   if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
+      // trying to open one too many
+      nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
+   } else {
+      pNesting->pCurrentNesting++;
+      pNesting->pCurrentNesting->uCount     = 0;
+      pNesting->pCurrentNesting->uStart     = uPos;
+      pNesting->pCurrentNesting->uMajorType = uMajorType;
+   }
+   return nReturn;
+}
+
+inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
+{
+   pNesting->pCurrentNesting--;
+}
+
+inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
+{
+   if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
+      return QCBOR_ERR_ARRAY_TOO_LONG;
+   }
+
+   pNesting->pCurrentNesting->uCount += 1;
+
+   return QCBOR_SUCCESS;
+}
+
+inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
+{
+   // The nesting count recorded is always the actual number of individiual
+   // data items in the array or map. For arrays CBOR uses the actual item
+   // count. For maps, CBOR uses the number of pairs.  This function returns
+   // the number needed for the CBOR encoding, so it divides the number of
+   // items by two for maps to get the number of pairs.  This implementation
+   // takes advantage of the map major type being one larger the array major
+   // type, hence uDivisor is either 1 or 2.
+   const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1;
+
+   return pNesting->pCurrentNesting->uCount / uDivisor;
+}
+
+inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
+{
+   return pNesting->pCurrentNesting->uStart;
+}
+
+inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
+{
+   return pNesting->pCurrentNesting->uMajorType;
+}
+
+inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
+{
+   return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
+}
+
+
+
+
+/*
+ Error tracking plan -- Errors are tracked internally and not returned
+ until Finish is called. The CBOR errors are in me->uError.
+ UsefulOutBuf also tracks whether the buffer is full or not in its
+ context.  Once either of these errors is set they are never
+ cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
+ never be cleared or we'll tell the caller all is good when it is not.
+
+ Only one error code is reported by QCBOREncode_Finish() even if there are
+ multiple errors. The last one set wins. The caller might have to fix
+ one error to reveal the next one they have to fix.  This is OK.
+
+ The buffer full error tracked by UsefulBuf is only pulled out of
+ UsefulBuf in Finish() so it is the one that usually wins.  UsefulBuf
+ will never go off the end of the buffer even if it is called again
+ and again when full.
+
+ It is really tempting to not check for overflow on the count in the
+ number of items in an array. It would save a lot of code, it is
+ extremely unlikely that any one will every put 65,000 items in an
+ array, and the only bad thing that would happen is the CBOR would be
+ bogus.
+
+ Since this does not parse any input, you could in theory remove all
+ error checks in this code if you knew the caller called it
+ correctly. Maybe someday CDDL or some such language will be able to
+ generate the code to call this and the calling code would always be
+ correct. This could also automatically size some of the data
+ structures like array/map nesting resulting in some stack memory
+ savings.
+
+ Errors returned here fall into two categories:
+
+ Sizes
+   QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
+   QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
+
+   QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Array/map nesting > QCBOR_MAX_ARRAY_NESTING1
+   QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
+
+ Nesting constructed incorrectly
+   QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
+   QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
+   QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
+ */
+
+
+
+
+/*
+ Public function for initialization. See header qcbor.h
+ */
+void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
+{
+   memset(me, 0, sizeof(QCBOREncodeContext));
+   UsefulOutBuf_Init(&(me->OutBuf), Storage);
+   Nesting_Init(&(me->nesting));
+}
+
+
+
+
+/*
+ All CBOR data items have a type and an "argument". The argument is
+ either the value of the item for integer types, the length of the
+ content for string, byte, array and map types, a tag for major type
+ 6, and has several uses for major type 7.
+
+ This function encodes the type and the argument. There are several
+ encodings for the argument depending on how large it is and how it is
+ used.
+
+ Every encoding of the type and argument has at least one byte, the
+ "initial byte".
+
+ The top three bits of the initial byte are the major type for the
+ CBOR data item.  The eight major types defined by the standard are
+ defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
+
+ The remaining five bits, known as "additional information", and
+ possibly more bytes encode the argument. If the argument is less than
+ 24, then it is encoded entirely in the five bits. This is neat
+ because it allows you to encode an entire CBOR data item in 1 byte
+ for many values and types (integers 0-23, true, false, and tags).
+
+ If the argument is larger than 24, then it is encoded in 1,2,4 or 8
+ additional bytes, with the number of these bytes indicated by the
+ values of the 5 bits 24, 25, 25 and 27.
+
+ It is possible to encode a particular argument in many ways with this
+ representation.  This implementation always uses the smallest
+ possible representation. This conforms with CBOR preferred encoding.
+
+ This function inserts them into the output buffer at the specified
+ position. AppendEncodedTypeAndNumber() appends to the end.
+
+ This function takes care of converting to network byte order.
+
+ This function is also used to insert floats and doubles. Before this
+ function is called the float or double must be copied into a
+ uint64_t. That is how they are passed in. They are then converted to
+ network byte order correctly. The uMinLen param makes sure that even
+
+ if all the digits of a half, float or double are 0 it is still
+ correctly encoded in 2, 4 or 8 bytes.
+ */
+
+static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
+                                       uint8_t uMajorType,
+                                       int nMinLen,
+                                       uint64_t uNumber,
+                                       size_t uPos)
+{
+   /*
+    This code does endian conversion without hton or knowing the
+    endianness of the machine using masks and shifts. This avoids the
+    dependency on hton and the mess of figuring out how to find the
+    machine's endianness.
+
+    This is a good efficient implementation on little-endian machines.
+    A faster and small implementation is possible on big-endian
+    machines because CBOR/network byte order is big endian. However
+    big endian machines are uncommon.
+
+    On x86, it is about 200 bytes instead of 500 bytes for the more
+    formal unoptimized code.
+
+    This also does the CBOR preferred shortest encoding for integers
+    and is called to do endian conversion for floats.
+
+    It works backwards from the LSB to the MSB as needed.
+
+    Code Reviewers: THIS FUNCTION DOES POINTER MATH
+    */
+   // Holds up to 9 bytes of type and argument
+   // plus one extra so pointer always points to
+   // valid bytes.
+   uint8_t bytes[sizeof(uint64_t)+2];
+   // Point to the last bytes and work backwards
+   uint8_t *pByte = &bytes[sizeof(bytes)-1];
+   // This is the 5 bits in the initial byte that is not the major type
+   uint8_t uAdditionalInfo;
+
+   if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
+      // Simple case where argument is < 24
+      uAdditionalInfo = uNumber;
+   } else  {
+      /*
+       Encode argument in 1,2,4 or 8 bytes. Outer loop
+       runs once for 1 byte and 4 times for 8 bytes.
+       Inner loop runs 1, 2 or 4 times depending on
+       outer loop counter. This works backwards taking
+       8 bits off the argument being encoded at a time
+       until all bits from uNumber have been encoded
+       and the minimum encoding size is reached.
+       Minimum encoding size is for floating point
+       numbers with zero bytes.
+       */
+      static const uint8_t aIterate[] = {1,1,2,4};
+      uint8_t i;
+      for(i = 0; uNumber || nMinLen > 0; i++) {
+         const uint8_t uIterations = aIterate[i];
+         for(int j = 0; j < uIterations; j++) {
+            *--pByte = uNumber & 0xff;
+            uNumber = uNumber >> 8;
+         }
+         nMinLen -= uIterations;
+      }
+      // Additional info is the encoding of the
+      // number of additional bytes to encode
+      // argument.
+      uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
+   }
+   *--pByte = (uMajorType << 5) + uAdditionalInfo;
+
+   UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
+}
+
+
+/*
+ Append the type and number info to the end of the buffer.
+
+ See InsertEncodedTypeAndNumber() function above for details
+*/
+inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
+                                              uint8_t uMajorType,
+                                              uint64_t uNumber)
+{
+   // An append is an insert at the end.
+   InsertEncodedTypeAndNumber(me,
+                              uMajorType,
+                              0,
+                              uNumber,
+                              UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+}
+
+
+
+
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
+{
+   if(me->uError == QCBOR_SUCCESS) {
+      AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
+      me->uError = Nesting_Increment(&(me->nesting));
+   }
+}
+
+
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
+{
+   if(me->uError == QCBOR_SUCCESS) {
+      uint8_t      uMajorType;
+      uint64_t     uValue;
+
+      if(nNum < 0) {
+         // In CBOR -1 encodes as 0x00 with major type negative int.
+         uValue = (uint64_t)(-nNum - 1);
+         uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
+      } else {
+         uValue = (uint64_t)nNum;
+         uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
+      }
+
+      AppendEncodedTypeAndNumber(me, uMajorType, uValue);
+      me->uError = Nesting_Increment(&(me->nesting));
+   }
+}
+
+
+/*
+ Semi-private function. It is exposed to user of the interface,
+ but they will usually call one of the inline wrappers rather than this.
+
+ See header qcbor.h
+
+ Does the work of adding some bytes to the CBOR output. Works for a
+ byte and text strings, which are the same in in CBOR though they have
+ different major types.  This is also used to insert raw
+ pre-encoded CBOR.
+ */
+void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
+{
+   if(me->uError == QCBOR_SUCCESS) {
+      // If it is not Raw CBOR, add the type and the length
+      if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
+         AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
+      }
+
+      // Actually add the bytes
+      UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
+
+      // Update the array counting if there is any nesting at all
+      me->uError = Nesting_Increment(&(me->nesting));
+   }
+}
+
+
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
+{
+   AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
+}
+
+
+/*
+ Semi-private function. It is exposed to user of the interface,
+ but they will usually call one of the inline wrappers rather than this.
+
+ See header qcbor.h
+ */
+void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
+{
+   if(me->uError == QCBOR_SUCCESS) {
+      // This function call takes care of endian swapping for the float / double
+      InsertEncodedTypeAndNumber(me,
+                                 // The major type for floats and doubles
+                                 CBOR_MAJOR_TYPE_SIMPLE,
+                                 // size makes sure floats with zeros encode correctly
+                                 (int)uSize,
+                                 // Bytes of the floating point number as a uint
+                                 uNum,
+                                 // end position because this is append
+                                 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+
+      me->uError = Nesting_Increment(&(me->nesting));
+   }
+}
+
+
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
+{
+   const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
+
+   QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
+}
+
+
+/*
+ Semi-public function. It is exposed to user of the interface,
+ but they will usually call one of the inline wrappers rather than this.
+
+ See header qcbor.h
+*/
+void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
+{
+   // Add one item to the nesting level we are in for the new map or array
+   me->uError = Nesting_Increment(&(me->nesting));
+   if(me->uError == QCBOR_SUCCESS) {
+      // The offset where the length of an array or map will get written
+      // is stored in a uint32_t, not a size_t to keep stack usage smaller. This
+      // checks to be sure there is no wrap around when recording the offset.
+      // Note that on 64-bit machines CBOR larger than 4GB can be encoded as long as no
+      // array / map offsets occur past the 4GB mark, but the public interface
+      // says that the maximum is 4GB to keep the discussion simpler.
+      size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
+
+      // QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
+      // code can run on a 32-bit machine and tests can pass on a 32-bit
+      // machine. If it was exactly UINT32_MAX, then this code would
+      // not compile or run on a 32-bit machine and an #ifdef or some
+      // machine size detection would be needed reducing portability.
+      if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
+         me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
+
+      } else {
+         // Increase nesting level because this is a map or array.
+         // Cast from size_t to uin32_t is safe because of check above
+         me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
+      }
+   }
+}
+
+
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
+                                 uint8_t uMajorType,
+                                 UsefulBufC *pWrappedCBOR)
+{
+   if(me->uError == QCBOR_SUCCESS) {
+      if(!Nesting_IsInNest(&(me->nesting))) {
+         me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
+      } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
+         me->uError = QCBOR_ERR_CLOSE_MISMATCH;
+      } else {
+         // When the array, map or bstr wrap was started, nothing was done
+         // except note the position of the start of it. This code goes back
+         // and inserts the actual CBOR array, map or bstr and its length.
+         // That means all the data that is in the array, map or wrapped
+         // needs to be slid to the right. This is done by UsefulOutBuf's
+         // insert function that is called from inside
+         // InsertEncodedTypeAndNumber()
+         const size_t uInsertPosition         = Nesting_GetStartPos(&(me->nesting));
+         const size_t uEndPosition            = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
+         // This can't go negative because the UsefulOutBuf always only grows
+         // and never shrinks. UsefulOutBut itself also has defenses such that
+         // it won't write were it should not even if given hostile input lengths
+         const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
+
+         // Length is number of bytes for a bstr and number of items a for map & array
+         const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
+                                    uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
+
+         // Actually insert
+         InsertEncodedTypeAndNumber(me,
+                                    uMajorType,       // major type bstr, array or map
+                                    0,                // no minimum length for encoding
+                                    uLength,          // either len of bstr or num map / array items
+                                    uInsertPosition); // position in out buffer
+
+         // Return pointer and length to the enclosed encoded CBOR. The intended
+         // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
+         // This must be used right away, as the pointer and length go invalid
+         // on any subsequent calls to this function because of the
+         // InsertEncodedTypeAndNumber() call that slides data to the right.
+         if(pWrappedCBOR) {
+            const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
+            const size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
+            *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
+         }
+         Nesting_Decrease(&(me->nesting));
+      }
+   }
+}
+
+
+
+
+/*
+ Public functions to finish and get the encoded result. See header qcbor.h
+ */
+QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
+{
+   QCBORError uReturn = me->uError;
+
+   if(uReturn != QCBOR_SUCCESS) {
+      goto Done;
+   }
+
+   if (Nesting_IsInNest(&(me->nesting))) {
+      uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
+      goto Done;
+   }
+
+   if(UsefulOutBuf_GetError(&(me->OutBuf))) {
+      // Stuff 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.
+      uReturn = QCBOR_ERR_BUFFER_TOO_SMALL;
+      goto Done;
+   }
+
+   *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
+
+Done:
+   return uReturn;
+}
+
+
+/*
+ Public functions to finish and get the encoded result. See header qcbor.h
+ */
+QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
+{
+   UsefulBufC Enc;
+
+   QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
+
+   if(nReturn == QCBOR_SUCCESS) {
+      *puEncodedLen = Enc.len;
+   }
+
+   return nReturn;
+}
+
+
+
+
+/*
+ Notes on the code
+
+ CBOR Major Type     Public Function
+ 0                   QCBOREncode_AddUInt64
+ 0, 1                QCBOREncode_AddUInt64, QCBOREncode_AddInt64
+ 2, 3                QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray
+ 4, 5                QCBOREncode_OpenMapOrArray
+ 6                   QCBOREncode_AddTag
+ 7                   QCBOREncode_AddDouble, QCBOREncode_AddType7
+
+ Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
+
+ _QCBOREncode_Init   69
+ _QCBOREncode_AddUInt64   76
+ _QCBOREncode_AddInt64   87
+ _QCBOREncode_AddBuffer   113
+ _QCBOREncode_AddTag 27
+ _QCBOREncode_AddType7   87
+ _QCBOREncode_AddDouble 36
+ _QCBOREncode_OpenMapOrArray   103
+ _QCBOREncode_CloseMapOrArray   181
+ _InsertEncodedTypeAndNumber   190
+ _QCBOREncode_Finish   72
+ _QCBOREncode_FinishGetSize  70
+
+ Total is about 1.1KB
+
+ _QCBOREncode_CloseMapOrArray is larger because it has a lot
+ of nesting tracking to do and much of Nesting_ inlines
+ into it. It probably can't be reduced much.
+
+ If the error returned by Nesting_Increment() can be ignored
+ because the limit is so high and the consequence of exceeding
+ is proved to be inconsequential, then a lot of if(me->uError)
+ instance can be removed, saving some code.
+
+ */
+
diff --git a/lib/ext/qcbor/test/UsefulBuf_Tests.c b/lib/ext/qcbor/test/UsefulBuf_Tests.c
new file mode 100644
index 0000000..cfa1262
--- /dev/null
+++ b/lib/ext/qcbor/test/UsefulBuf_Tests.c
@@ -0,0 +1,700 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#include "UsefulBuf.h"
+
+
+/* Basic exercise...
+
+   Call all the main public functions.
+
+   Binary compare the result to the expected.
+
+   There is nothing adversarial in this test
+ */
+const char * UOBTest_NonAdversarial()
+{
+   const char *szReturn = NULL;
+
+   UsefulBuf_MAKE_STACK_UB(outbuf,50);
+
+   UsefulOutBuf UOB;
+
+   UsefulOutBuf_Init(&UOB, outbuf);
+
+   if(!UsefulOutBuf_AtStart(&UOB)) {
+      szReturn = "Not at start";
+      goto Done;
+   }
+
+   // Put 7 bytes at beginning of buf
+   UsefulOutBuf_AppendData(&UOB, "bluster", 7);
+
+   if(UsefulOutBuf_AtStart(&UOB)) {
+      szReturn = "At start";
+      goto Done;
+   }
+
+   // add a space to end
+   UsefulOutBuf_AppendByte(&UOB, ' ');
+
+   // Add 5 bytes to the end
+   UsefulBufC UBC = {"hunny", 5};
+   UsefulOutBuf_AppendUsefulBuf(&UOB, UBC);
+
+   // Insert 9 bytes at the beginning, slide the previous stuff right
+   UsefulOutBuf_InsertData(&UOB, "heffalump", 9, 0);
+   UsefulOutBuf_InsertByte(&UOB, ' ', 9);
+
+   // Put 9 bytes in at position 10 -- just after "heffalump "
+   UsefulBufC UBC2 = {"unbounce ", 9};
+   UsefulOutBuf_InsertUsefulBuf(&UOB, UBC2, 10);
+
+   // Make it a null terminated string (because all the appends and inserts above not strcpy !)
+   UsefulOutBuf_AppendByte(&UOB, '\0');
+
+
+   UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB);
+
+   const char *expected = "heffalump unbounce bluster hunny";
+
+   if(UsefulBuf_IsNULLC(U) || U.len-1 != strlen(expected) || strcmp(expected, U.ptr) || UsefulOutBuf_GetError(&UOB)) {
+      szReturn = "OutUBuf";
+   }
+
+   UsefulBuf_MAKE_STACK_UB(buf, 50);
+   UsefulBufC Out =  UsefulOutBuf_CopyOut(&UOB, buf);
+
+   if(UsefulBuf_IsNULLC(Out) || Out.len-1 != strlen(expected) || strcmp(expected, Out.ptr)) {
+      szReturn = "CopyOut";
+   }
+
+Done:
+   return szReturn;
+}
+
+
+/*
+  Append test utility.
+    pUOB is the buffer to append too
+    num is the amount to append
+    expected is the expected return code, 0 or 1
+
+ returns 0 if test passed
+
+ */
+static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected)
+{
+   //reset
+   UsefulOutBuf_Reset(pUOB);
+
+   // check status first
+   if(UsefulOutBuf_GetError(pUOB))
+      return 1;
+
+   // append the bytes
+   UsefulOutBuf_AppendData(pUOB, (const uint8_t *)"bluster", num);
+
+   // check error status after
+   if(UsefulOutBuf_GetError(pUOB) != expected)
+      return 1;
+
+   return 0;
+}
+
+
+/*
+ Same as append, but takes a position param too
+ */
+static int InsertTest(UsefulOutBuf *pUOB,  size_t num, size_t pos, int expected)
+{
+   // reset
+   UsefulOutBuf_Reset(pUOB);
+
+   // check
+   if(UsefulOutBuf_GetError(pUOB))
+      return 1;
+
+   UsefulOutBuf_InsertData(pUOB, (const uint8_t *)"bluster", num, pos);
+
+   if(UsefulOutBuf_GetError(pUOB) != expected)
+      return 1;
+
+   return 0;
+}
+
+
+/*
+ Boundary conditions to test
+   - around 0
+   - around the buffer size
+   - around MAX size_t
+
+
+ Test these for the buffer size and the cursor, the insert amount, the append amount and the insert position
+
+ */
+
+const char *UOBTest_BoundaryConditionsTest()
+{
+   UsefulBuf_MAKE_STACK_UB(outbuf,2);
+
+   UsefulOutBuf UOB;
+
+   UsefulOutBuf_Init(&UOB, outbuf);
+
+   // append 0 byte to a 2 byte buffer --> success
+   if(AppendTest(&UOB, 0, 0))
+      return "Append 0 bytes failed";
+
+   // append 1 byte to a 2 byte buffer --> success
+   if(AppendTest(&UOB, 1, 0))
+      return "Append of 1 byte failed";
+
+   // append 2 byte to a 2 byte buffer --> success
+   if(AppendTest(&UOB, 2, 0))
+      return "Append to fill buffer failed";
+
+   // append 3 bytes to a 2 byte buffer --> failure
+   if(AppendTest(&UOB, 3, 1))
+      return "Overflow of buffer not caught";
+
+   // append max size_t to a 2 byte buffer --> failure
+   if(AppendTest(&UOB, SIZE_MAX, 1))
+      return "Append of SIZE_MAX error not caught";
+
+   if(InsertTest(&UOB, 1, 0, 0))
+      return "Insert 1 byte at start failed";
+
+   if(InsertTest(&UOB, 2, 0, 0))
+      return "Insert 2 bytes at start failed";
+
+   if(InsertTest(&UOB, 3, 0, 1))
+      return "Insert overflow not caught";
+
+   if(InsertTest(&UOB, 1, 1, 1))
+      return "Bad insertion point not caught";
+
+
+   UsefulBuf_MAKE_STACK_UB(outBuf2,10);
+
+   UsefulOutBuf_Init(&UOB, outBuf2);
+
+   UsefulOutBuf_Reset(&UOB);
+   // put data in the buffer
+   UsefulOutBuf_AppendString(&UOB, "abc123");
+
+   UsefulOutBuf_InsertString(&UOB, "xyz*&^", 0);
+
+   if(!UsefulOutBuf_GetError(&UOB)) {
+      return "insert with data should have failed";
+   }
+
+
+   UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
+   UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6);
+   if(UsefulOutBuf_GetError(&UOB)) {
+      return "insert in huge should have succeeded";
+   }
+
+   UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
+   UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -5);
+   if(UsefulOutBuf_GetError(&UOB)) {
+      return "insert in huge should have succeeded";
+   }
+
+   UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
+   UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX - 4);
+   if(!UsefulOutBuf_GetError(&UOB)) {
+      return "lengths near max size";
+   }
+
+   return NULL;
+}
+
+
+
+
+
+// Test function to get size and magic number check
+
+const char *TestBasicSanity()
+{
+   UsefulBuf_MAKE_STACK_UB(outbuf,10);
+
+   UsefulOutBuf UOB;
+
+   // First -- make sure that the room left function returns the right amount
+   UsefulOutBuf_Init(&UOB, outbuf);
+
+   if(UsefulOutBuf_RoomLeft(&UOB) != 10)
+      return "room left failed";
+
+   if(!UsefulOutBuf_WillItFit(&UOB, 9)) {
+      return "it did not fit";
+   }
+
+   if(UsefulOutBuf_WillItFit(&UOB, 11)) {
+      return "it should have not fit";
+   }
+
+
+   // Next -- make sure that the magic number checking is working right
+   UOB.magic = 8888; // make magic bogus
+
+   UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7);
+
+   if(!UsefulOutBuf_GetError(&UOB))
+      return "magic corruption check failed";
+
+
+
+   // Next make sure that the valid data length check is working right
+   UsefulOutBuf_Init(&UOB, outbuf);
+
+   UOB.data_len = UOB.UB.len+1; // make size bogus
+
+   UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7);
+   if(!UsefulOutBuf_GetError(&UOB))
+      return "valid data check failed";
+
+   return NULL;
+}
+
+
+
+const char *UBMacroConversionsTest()
+{
+   char *szFoo = "foo";
+
+   UsefulBufC Foo = UsefulBuf_FromSZ(szFoo);
+   if(Foo.len != 3 || strncmp(Foo.ptr, szFoo, 3))
+      return "SZToUsefulBufC failed";
+
+   UsefulBufC Too = UsefulBuf_FROM_SZ_LITERAL("Toooo");
+   if(Too.len != 5 || strncmp(Too.ptr, "Toooo", 5))
+      return "UsefulBuf_FROM_SZ_LITERAL failed";
+
+   uint8_t pB[] = {0x42, 0x6f, 0x6f};
+   UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
+   if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3))
+     return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed";
+
+   char *sz = "not const"; // some data for the test
+   UsefulBuf B = (UsefulBuf){sz, sizeof(sz)};
+   UsefulBufC BC = UsefulBuf_Const(B);
+   if(BC.len != sizeof(sz) || BC.ptr != sz)
+      return "UsefulBufConst failed";
+
+   return NULL;
+}
+
+
+const char *UBUtilTests()
+{
+   UsefulBuf UB = NULLUsefulBuf;
+
+   if(!UsefulBuf_IsNULL(UB)){
+      return "IsNull failed";
+   }
+
+   if(!UsefulBuf_IsEmpty(UB)){
+      return "IsEmpty failed";
+   }
+
+   if(!UsefulBuf_IsNULLOrEmpty(UB)) {
+      return "IsNULLOrEmpty failed";
+   }
+
+   const UsefulBufC UBC = UsefulBuf_Const(UB);
+
+   if(!UsefulBuf_IsNULLC(UBC)){
+      return "IsNull const failed";
+   }
+
+   if(!UsefulBuf_IsEmptyC(UBC)){
+      return "IsEmptyC failed";
+   }
+
+   if(!UsefulBuf_IsNULLOrEmptyC(UBC)){
+      return "IsNULLOrEmptyC failed";
+   }
+
+   const UsefulBuf UB2 = UsefulBuf_Unconst(UBC);
+   if(!UsefulBuf_IsEmpty(UB2)) {
+      return "Back to UB is Empty failed";
+   }
+
+   UB.ptr = "x"; // just some valid pointer
+
+   if(UsefulBuf_IsNULL(UB)){
+      return "IsNull failed";
+   }
+
+   if(!UsefulBuf_IsEmptyC(UBC)){
+      return "IsEmpty failed";
+   }
+
+   // test the Unconst.
+   if(UsefulBuf_Unconst(UBC).ptr != NULL) {
+      return "Unconst failed";
+   }
+
+   // Set 100 bytes of '+'; validated a few tests later
+   UsefulBuf_MAKE_STACK_UB(Temp, 100);
+   const UsefulBufC TempC = UsefulBuf_Set(Temp, '+');
+
+   // Try to copy into a buf that is too small and see failure
+   UsefulBuf_MAKE_STACK_UB(Temp2, 99);
+   if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp2, TempC))) {
+      return "Copy should have failed";
+   }
+
+   if(UsefulBuf_IsNULLC(UsefulBuf_CopyPtr(Temp2, "xx", 2))) {
+      return "CopyPtr failed";
+   }
+
+   UsefulBufC xxyy = UsefulBuf_CopyOffset(Temp2, 2, UsefulBuf_FROM_SZ_LITERAL("yy"));
+   if(UsefulBuf_IsNULLC(xxyy)) {
+      return "CopyOffset Failed";
+   }
+
+   if(UsefulBuf_Compare(UsefulBuf_Head(xxyy, 3), UsefulBuf_FROM_SZ_LITERAL("xxy"))) {
+      return "head failed";
+   }
+
+   if(UsefulBuf_Compare(UsefulBuf_Tail(xxyy, 1), UsefulBuf_FROM_SZ_LITERAL("xyy"))) {
+      return "tail failed";
+   }
+
+   if(!UsefulBuf_IsNULLC(UsefulBuf_Head(xxyy, 5))) {
+      return "head should have failed";
+   }
+
+   if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(xxyy, 5))) {
+      return "tail should have failed";
+   }
+
+   if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(NULLUsefulBufC, 0))) {
+      return "tail of NULLUsefulBufC is not NULLUsefulBufC";
+   }
+
+   const UsefulBufC TailResult = UsefulBuf_Tail((UsefulBufC){NULL, 100}, 99);
+   if(TailResult.ptr != NULL || TailResult.len != 1) {
+      return "tail of NULL and length incorrect";
+   }
+
+   if(!UsefulBuf_IsNULLC(UsefulBuf_CopyOffset(Temp2, 100, UsefulBuf_FROM_SZ_LITERAL("yy")))) {
+      return "Copy Offset should have failed";
+   }
+
+   // Try to copy into a NULL/empty buf and see failure
+   const UsefulBuf UBNull = NULLUsefulBuf;
+   if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(UBNull, TempC))) {
+      return "Copy to NULL should have failed";
+   }
+
+
+   // Try to set a NULL/empty buf; nothing should happen
+   UsefulBuf_Set(UBNull, '+'); // This will crash on failure
+
+   // Copy successfully to a buffer
+   UsefulBuf_MAKE_STACK_UB(Temp3, 101);
+   if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp3, TempC))) {
+      return "Copy should not have failed";
+   }
+
+   static const uint8_t pExpected[] = {
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+   };
+   UsefulBufC Expected = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpected);
+   // This validates comparison for equality and the UsefulBuf_Set
+   if(UsefulBuf_Compare(Expected, TempC)) {
+      return "Set / Copy / Compare failed";
+   }
+
+   // Compare two empties and expect success
+   if(UsefulBuf_Compare(NULLUsefulBufC, NULLUsefulBufC)){
+      return "Compare Empties failed";
+   }
+
+   // Compare with empty and expect the first to be larger
+   if(UsefulBuf_Compare(Expected, NULLUsefulBufC) <= 0){
+      return "Compare with empty failed";
+   }
+
+
+   static const uint8_t pExpectedBigger[] = {
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  ',',
+   };
+   const UsefulBufC ExpectedBigger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedBigger);
+
+   // Expect -1 when the first arg is smaller
+   if(UsefulBuf_Compare(Expected, ExpectedBigger) >= 0){
+      return "Compare with bigger";
+   }
+
+
+   static const uint8_t pExpectedSmaller[] = {
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '*',
+   };
+   const UsefulBufC ExpectedSmaller = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedSmaller);
+   // Expect +1 when the first arg is larger
+   if(UsefulBuf_Compare(Expected, ExpectedSmaller) <= 0){
+      return "Compare with smaller";
+   }
+
+
+   static const uint8_t pExpectedLonger[] = {
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+', '+'
+   };
+   const UsefulBufC ExpectedLonger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedLonger);
+
+   // Expect -1 when the first arg is smaller
+   if(UsefulBuf_Compare(Expected, ExpectedLonger) >= 0){
+      return "Compare with longer";
+   }
+
+
+   static const uint8_t pExpectedShorter[] = {
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',  '+',
+      '+',  '+',  '+',  '+', '+',  '+',  '+', '+',  '+',
+   };
+   const UsefulBufC ExpectedShorter = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedShorter);
+   // Expect +1 with the first arg is larger
+   if(UsefulBuf_Compare(Expected, ExpectedShorter) <= 0){
+      return "Compare with shorter";
+   }
+
+
+   if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp, NULLUsefulBufC))) {
+      return "Copy null/empty failed";
+   }
+
+   // Look for +++++... in +++++... and find it at the beginning
+   if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedShorter)){
+      return "Failed to find";
+   }
+
+   // look for ++* in ....++* and find it at the end
+   static const uint8_t pToFind[] = {'+', '+', '*'};
+   const UsefulBufC ToBeFound = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pToFind);
+
+   if(97 != UsefulBuf_FindBytes(ExpectedSmaller, ToBeFound)){
+      return "Failed to find 2";
+   }
+
+   // look for ++* in ....++, and find it near the end
+   if(SIZE_MAX != UsefulBuf_FindBytes(ExpectedBigger, ToBeFound)){
+      return "Failed to not find";
+   }
+
+   // Look for the whole buffer in itself and succeed.
+   if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedLonger)){
+      return "Failed to find 3";
+   }
+
+   return NULL;
+}
+
+
+const char *  UIBTest_IntegerFormat()
+{
+   UsefulOutBuf_MakeOnStack(UOB,100);
+
+   const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness
+   const uint64_t u64 = 1984738472938472;
+   const uint16_t u16 = 40000;
+   const uint8_t  u8 = 9;
+   const float    f  = (float)314.15;
+   const double   d  = 2.1e10;
+
+
+   UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition
+   UsefulOutBuf_AppendUint64(&UOB, u64); // Also tests UsefulOutBuf_InsertUint32
+   UsefulOutBuf_AppendUint16(&UOB, u16); // Also tests UsefulOutBuf_InsertUint16
+   UsefulOutBuf_AppendByte(&UOB, u8);
+   UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat
+   UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble
+
+   const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_IsNULLC(O))
+      return "Couldn't output integers";
+
+   // from https://en.wikipedia.org/wiki/Endianness
+   const uint8_t pExpectedNetworkOrder[4] = {0x0A, 0x0B, 0x0C, 0x0D};
+   if(memcmp(O.ptr, pExpectedNetworkOrder, 4)) {
+      return "not in network order";
+   }
+
+   UsefulInputBuf UIB;
+
+   UsefulInputBuf_Init(&UIB, O);
+
+   if(UsefulInputBuf_Tell(&UIB) != 0) {
+      return "UsefulInputBuf_Tell failed";
+   }
+
+   if(UsefulInputBuf_GetUint32(&UIB) != u32) {
+      return "u32 out then in failed";
+   }
+   if(UsefulInputBuf_GetUint64(&UIB) != u64) {
+      return "u64 out then in failed";
+   }
+   if(UsefulInputBuf_GetUint16(&UIB) != u16) {
+      return "u16 out then in failed";
+   }
+   if(UsefulInputBuf_GetByte(&UIB) != u8) {
+      return "u8 out then in failed";
+   }
+   if(UsefulInputBuf_GetFloat(&UIB) != f) {
+      return "float out then in failed";
+   }
+   if(UsefulInputBuf_GetDouble(&UIB) != d) {
+      return "double out then in failed";
+   }
+
+   // Reset and go again for a few more tests
+   UsefulInputBuf_Init(&UIB, O);
+
+   const UsefulBufC Four = UsefulInputBuf_GetUsefulBuf(&UIB, 4);
+   if(UsefulBuf_IsNULLC(Four)) {
+      return "Four is NULL";
+   }
+   if(UsefulBuf_Compare(Four, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedNetworkOrder))) {
+      return "Four compare failed";
+   }
+
+   if(UsefulInputBuf_BytesUnconsumed(&UIB) != 23){
+      return "Wrong number of unconsumed bytes";
+   }
+
+   if(!UsefulInputBuf_BytesAvailable(&UIB, 23)){
+      return "Wrong number of bytes available I";
+   }
+
+   if(UsefulInputBuf_BytesAvailable(&UIB, 24)){
+      return "Wrong number of bytes available II";
+   }
+
+   UsefulInputBuf_Seek(&UIB, 0);
+
+   if(UsefulInputBuf_GetError(&UIB)) {
+      return "unexpected error after seek";
+   }
+
+   const uint8_t *pGetBytes = (const uint8_t *)UsefulInputBuf_GetBytes(&UIB, 4);
+   if(pGetBytes == NULL) {
+      return "GetBytes returns NULL";
+   }
+
+   if(memcmp(pGetBytes, pExpectedNetworkOrder, 4)) {
+      return "Got wrong bytes";
+   }
+
+   UsefulInputBuf_Seek(&UIB, 28);
+
+   if(!UsefulInputBuf_GetError(&UIB)) {
+      return "expected error after seek";
+   }
+
+   return NULL;
+}
+
+
+const char *UBUTest_CopyUtil()
+{
+   if(UsefulBufUtil_CopyFloatToUint32(65536.0F) != 0x47800000) {
+      return "CopyFloatToUint32 failed";
+   }
+
+   if(UsefulBufUtil_CopyDoubleToUint64(4e-40F) != 0X37C16C2800000000ULL) {
+      return "CopyDoubleToUint64 failed";
+   }
+
+   if(UsefulBufUtil_CopyUint64ToDouble(0X37C16C2800000000ULL) != 4e-40F) {
+      return "CopyUint64ToDouble failed";
+   }
+
+   if(UsefulBufUtil_CopyUint32ToFloat(0x47800000) != 65536.0F) {
+      return "CopyUint32ToFloat failed";
+   }
+
+   return NULL;
+}
+
+
+
diff --git a/lib/ext/qcbor/test/UsefulBuf_Tests.h b/lib/ext/qcbor/test/UsefulBuf_Tests.h
new file mode 100644
index 0000000..976de62
--- /dev/null
+++ b/lib/ext/qcbor/test/UsefulBuf_Tests.h
@@ -0,0 +1,50 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#ifndef UsefulBuf_UsefulBuf_Tests_h
+#define UsefulBuf_UsefulBuf_Tests_h
+
+const char * UOBTest_NonAdversarial(void);
+
+const char *  TestBasicSanity(void);
+
+const char *  UOBTest_BoundaryConditionsTest(void);
+
+const char *  UBMacroConversionsTest(void);
+
+const char *  UBUtilTests(void);
+
+const char *  UIBTest_IntegerFormat(void);
+
+const char *  UBUTest_CopyUtil(void);
+
+#endif
diff --git a/lib/ext/qcbor/test/float_tests.c b/lib/ext/qcbor/test/float_tests.c
new file mode 100644
index 0000000..eaf75aa
--- /dev/null
+++ b/lib/ext/qcbor/test/float_tests.c
@@ -0,0 +1,474 @@
+/*==============================================================================
+ float_tests.c -- tests for float and conversion to/from half-precision
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 9/19/18
+ ==============================================================================*/
+
+#include "float_tests.h"
+#include "qcbor.h"
+#include "half_to_double_from_rfc7049.h"
+#include <math.h> // For INFINITY and NAN and isnan()
+
+
+
+static const uint8_t spExpectedHalf[] = {
+    0xB1,
+        0x64,
+            0x7A, 0x65, 0x72, 0x6F,
+        0xF9, 0x00, 0x00,   // 0.000
+        0x6A,
+            0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
+        0xF9, 0x7C, 0x00,   // Infinity
+        0x73,
+            0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
+        0xF9, 0xFC, 0x00,   // -Inifinity
+        0x63,
+            0x4E, 0x61, 0x4E,
+        0xF9, 0x7E, 0x00,   // NaN
+        0x63,
+            0x6F, 0x6E, 0x65,
+        0xF9, 0x3C, 0x00,   // 1.0
+        0x69,
+            0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
+        0xF9, 0x35, 0x55,   // 0.333251953125
+        0x76,
+            0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
+        0xF9, 0x7B, 0xFF,   // 65504.0
+        0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
+        0xF9, 0x7C, 0x00,   // Infinity
+        0x72,
+            0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+        0xF9, 0x00, 0x01,   // 0.000000059604
+        0x6F,
+            0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+        0xF9, 0x03, 0xFF,   // 0.0000609755516
+        0x71,
+            0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+        0xF9, 0x04, 0x00,   // 0.000061988
+        0x70,
+            0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65,
+        0xF9, 0x00, 0x00,
+        0x03,
+        0xF9, 0xC0, 0x00,    // -2
+        0x04,
+        0xF9, 0x7E, 0x00,    // qNaN
+        0x05,
+        0xF9, 0x7C, 0x01,    // sNaN
+        0x06,
+        0xF9, 0x7E, 0x0F,    // qNaN with payload 0x0f
+        0x07,
+        0xF9, 0x7C, 0x0F,    // sNaN with payload 0x0f
+
+};
+
+
+int HalfPrecisionDecodeBasicTests()
+{
+    UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
+
+    QCBORDecodeContext DC;
+    QCBORDecode_Init(&DC, HalfPrecision, 0);
+
+    QCBORItem Item;
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_MAP) {
+        return -1;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0F) {
+        return -2;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
+        return -3;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) {
+        return -4;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO, is this really converting right? It is carrying payload, but this confuses things.
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
+        return -5;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0F) {
+        return -6;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125F) {
+        return -7;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0F) {
+        return -8;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
+        return -9;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO: check this
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000000596046448F) {
+        return -10;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO: check this
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000609755516F) {
+        return -11;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO check this
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000610351563F) {
+        return -12;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0) {
+        return -13;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) {
+        return -14;
+    }
+
+    // TODO: double check these four tests
+    QCBORDecode_GetNext(&DC, &Item); // qNaN
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
+        return -15;
+    }
+    QCBORDecode_GetNext(&DC, &Item); // sNaN
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
+        return -16;
+    }
+    QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
+        return -17;
+    }
+    QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
+    if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
+        return -18;
+    }
+
+    if(QCBORDecode_Finish(&DC)) {
+        return -19;
+    }
+
+    return 0;
+}
+
+
+
+
+int HalfPrecisionAgainstRFCCodeTest()
+{
+    for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
+        unsigned char x[2];
+        x[1] = uHalfP & 0xff;
+        x[0] = uHalfP >> 8;
+        double d = decode_half(x);
+
+        // Contruct the CBOR for the half-precision float by hand
+        UsefulBuf_MAKE_STACK_UB(__xx, 3);
+        UsefulOutBuf UOB;
+        UsefulOutBuf_Init(&UOB, __xx);
+
+        const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
+        UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
+        UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
+
+        // Now parse the hand-constructed CBOR. This will invoke the conversion to a float
+        QCBORDecodeContext DC;
+        QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
+
+        QCBORItem Item;
+
+        QCBORDecode_GetNext(&DC, &Item);
+        if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
+            return -1;
+        }
+
+        //printf("%04x  QCBOR:%15.15f  RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
+
+        if(isnan(d)) {
+            // The RFC code uses the native instructions which may or may not
+            // handle sNaN, qNaN and NaN payloads correctly. This test just
+            // makes sure it is a NaN and doesn't worry about the type of NaN
+            if(!isnan(Item.val.dfnum)) {
+                return -3;
+            }
+        } else {
+            if(Item.val.dfnum != d) {
+                return -2;
+            }
+        }
+    }
+    return 0;
+}
+
+
+/*
+ {"zero": 0.0,
+  "negative zero": -0.0,
+  "infinitity": Infinity,
+  "negative infinitity": -Infinity,
+  "NaN": NaN,
+  "one": 1.0,
+  "one third": 0.333251953125,
+  "largest half-precision": 65504.0,
+  "largest half-precision point one": 65504.1,
+  "too-large half-precision": 65536.0,
+  "smallest subnormal": 5.96046448e-8,
+  "smallest normal": 0.00006103515261202119,
+  "biggest subnormal": 0.00006103515625,
+  "subnormal single": 4.00000646641519e-40,
+  3: -2.0,
+  "large single exp": 2.5521177519070385e+38,
+  "too-large single exp": 5.104235503814077e+38,
+  "biggest single with prec": 16777216.0,
+  "first single with prec loss": 16777217.0,
+  1: "fin"}
+ */
+static const uint8_t spExpectedSmallest[] = {
+    0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D,
+    0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
+    0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66,
+    0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00,
+    0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
+    0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
+    0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00,
+    0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E,
+    0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55,
+    0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
+    0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
+    0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61,
+    0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66,
+    0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
+    0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65,
+    0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78,
+    0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65,
+    0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63,
+    0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00,
+    0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
+    0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB,
+    0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73,
+    0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
+    0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71,
+    0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
+    0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00,
+    0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+    0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1,
+    0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00,
+    0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E,
+    0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40,
+    0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72,
+    0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
+    0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73,
+    0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77,
+    0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B,
+    0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74,
+    0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
+    0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F,
+    0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00,
+    0x00, 0x01, 0x63, 0x66, 0x69, 0x6E
+};
+
+
+int DoubleAsSmallestTest()
+{
+    UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
+
+#define QCBOREncode_AddDoubleAsSmallestToMap QCBOREncode_AddDoubleToMap
+#define QCBOREncode_AddDoubleAsSmallestToMapN QCBOREncode_AddDoubleToMapN
+
+
+    QCBOREncodeContext EC;
+    QCBOREncode_Init(&EC, EncodedHalfsMem);
+    // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+    QCBOREncode_OpenMap(&EC);
+    // 64                                   # text(4)
+    //    7A65726F                          # "zero"
+    // F9 0000                              # primitive(0)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "zero", 0.00);
+
+    // 64                                   # text(4)
+    //    7A65726F                          # "negative zero"
+    // F9 8000                              # primitive(0)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00);
+
+    // 6A                                   # text(10)
+    //    696E66696E6974697479              # "infinitity"
+    // F9 7C00                              # primitive(31744)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
+
+    // 73                                   # text(19)
+    //    6E6567617469766520696E66696E6974697479 # "negative infinitity"
+    // F9 FC00                              # primitive(64512)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
+
+    // 63                                   # text(3)
+    //    4E614E                            # "NaN"
+    // F9 7E00                              # primitive(32256)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
+
+    // TODO: test a few NaN variants
+
+    // 63                                   # text(3)
+    //    6F6E65                            # "one"
+    // F9 3C00                              # primitive(15360)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
+
+    // 69                                   # text(9)
+    //    6F6E65207468697264                # "one third"
+    // F9 3555                              # primitive(13653)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
+
+    // 76                                   # text(22)
+    //    6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
+    // F9 7BFF                              # primitive(31743)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
+
+    // 76                                   # text(22)
+    //    6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
+    // F9 7BFF                              # primitive(31743)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
+
+    // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
+    // 78 18                                # text(24)
+    //    746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
+    // FA 47800000                          # primitive(31743)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0);
+
+    // The smallest possible half-precision subnormal, but digitis are lost converting
+    // to half, so this turns into a double
+    // 72                                   # text(18)
+    //    736D616C6C657374207375626E6F726D616C # "smallest subnormal"
+    // FB 3E700000001C5F68                  # primitive(4499096027744984936)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448);
+
+    // The smallest possible half-precision snormal, but digitis are lost converting
+    // to half, so this turns into a single TODO: confirm this is right
+    // 6F                                   # text(15)
+    //    736D616C6C657374206E6F726D616C    # "smallest normal"
+    // FA 387FFFFF                          # primitive(947912703)
+    // in hex single is 0x387fffff, exponent -15, significand 7fffff
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest normal",    0.0000610351526F);
+
+    // 71                                   # text(17)
+    //    62696767657374207375626E6F726D616C # "biggest subnormal"
+    // F9 0400                              # primitive(1024)
+    // in hex single is 0x38800000, exponent -14, significand 0
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal",  0.0000610351563F);
+
+    // 70                                   # text(16)
+    //    7375626E6F726D616C2073696E676C65  # "subnormal single"
+    // FB 37C16C2800000000                  # primitive(4017611261645684736)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40F);
+
+    // 03                                   # unsigned(3)
+    // F9 C000                              # primitive(49152)
+    QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
+
+    // 70                                   # text(16)
+    //    6C617267652073696E676C6520657870  # "large single exp"
+    // FA 7F400000                          # primitive(2134900736)
+    // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits  single
+
+    // 74                                   # text(20)
+    //    746F6F2D6C617267652073696E676C6520657870 # "too-large single exp"
+    // FB 47F8000000000000                  # primitive(5185894970917126144)
+    // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single
+
+    // 66                                   # text(6)
+    //    646664666465                      # "dfdfde"
+    // FA 4B800000                          # primitive(1266679808)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss
+
+    // 78 18                                # text(24)
+    //    626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
+    // FA 4B800000                          # primitive(1266679808)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss
+
+    // Just a convenient marker when cutting and pasting encoded CBOR
+    QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
+
+    QCBOREncode_CloseMap(&EC);
+
+    UsefulBufC EncodedHalfs;
+    int nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs);
+    if(nReturn) {
+        return -1;
+    }
+
+    if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
+        return -3;
+    }
+
+    return 0;
+}
+
+
+
+#ifdef NAN_EXPERIMENT
+/*
+ Code for checking what the double to float cast does with
+ NaNs.  Not run as part of tests. Keep it around to
+ be able to check various platforms and CPUs.
+ */
+
+#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
+#define DOUBLE_NUM_EXPONENT_BITS    (11)
+#define DOUBLE_NUM_SIGN_BITS        (1)
+
+#define DOUBLE_SIGNIFICAND_SHIFT    (0)
+#define DOUBLE_EXPONENT_SHIFT       (DOUBLE_NUM_SIGNIFICAND_BITS)
+#define DOUBLE_SIGN_SHIFT           (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
+
+#define DOUBLE_SIGNIFICAND_MASK     (0xfffffffffffffULL) // The lower 52 bits
+#define DOUBLE_EXPONENT_MASK        (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
+#define DOUBLE_SIGN_MASK            (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
+#define DOUBLE_QUIET_NAN_BIT        (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
+
+
+static int NaNExperiments() {
+    double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
+    double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
+    double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
+
+    float f1 = (float)dqNaN;
+    float f2 = (float)dsNaN;
+    float f3 = (float)dqNaNPayload;
+
+
+    uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
+    uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
+    uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
+
+    // Result of this on x86 is that every NaN is a qNaN. The intel
+    // CVTSD2SS instruction ignores the NaN payload and even converts
+    // a sNaN to a qNaN.
+
+    return 0;
+}
+#endif
+
+
+
diff --git a/lib/ext/qcbor/test/float_tests.h b/lib/ext/qcbor/test/float_tests.h
new file mode 100644
index 0000000..b7174c8
--- /dev/null
+++ b/lib/ext/qcbor/test/float_tests.h
@@ -0,0 +1,23 @@
+/*==============================================================================
+ float_tests.h -- tests for float and conversion to/from half-precision
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 9/19/18
+ ==============================================================================*/
+
+#ifndef float_tests_h
+#define float_tests_h
+
+int HalfPrecisionDecodeBasicTests(void);
+
+int DoubleAsSmallestTest(void);
+
+int HalfPrecisionAgainstRFCCodeTest(void);
+
+
+#endif /* float_tests_h */
diff --git a/lib/ext/qcbor/test/half_to_double_from_rfc7049.c b/lib/ext/qcbor/test/half_to_double_from_rfc7049.c
new file mode 100644
index 0000000..6380e51
--- /dev/null
+++ b/lib/ext/qcbor/test/half_to_double_from_rfc7049.c
@@ -0,0 +1,45 @@
+/*
+
+ Copyright (c) 2013 IETF Trust and the persons identified as the
+ document authors.  All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document.  Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document.  Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+ */
+
+/*
+ This code is from RFC 7049. It is not used in the main implementation
+ because:
+   a) it adds a dependency on <math.h> and ldexp().
+   b) the license may be an issue
+
+ QCBOR does support half-precision, but rather than using
+ floating point math like this, it does it with bit shifting
+ and masking.
+
+ This code is here to test that code.
+
+ */
+
+#include "half_to_double_from_rfc7049.h"
+
+#include <math.h>
+
+double decode_half(unsigned char *halfp) {
+    int half = (halfp[0] << 8) + halfp[1];
+    int exp = (half >> 10) & 0x1f;
+    int mant = half & 0x3ff;
+    double val;
+    if (exp == 0) val = ldexp(mant, -24);
+    else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
+    else val = mant == 0 ? INFINITY : NAN;
+    return half & 0x8000 ? -val : val;
+}
diff --git a/lib/ext/qcbor/test/half_to_double_from_rfc7049.h b/lib/ext/qcbor/test/half_to_double_from_rfc7049.h
new file mode 100644
index 0000000..9f69e35
--- /dev/null
+++ b/lib/ext/qcbor/test/half_to_double_from_rfc7049.h
@@ -0,0 +1,18 @@
+/*==============================================================================
+ half_to_double_from_rfc7049.h -- interface to IETF float conversion code.
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 9/23/18
+  ==============================================================================*/
+
+#ifndef half_to_double_from_rfc7049_h
+#define half_to_double_from_rfc7049_h
+
+double decode_half(unsigned char *halfp);
+
+#endif /* half_to_double_from_rfc7049_h */
diff --git a/lib/ext/qcbor/test/qcbor_decode_tests.c b/lib/ext/qcbor/test/qcbor_decode_tests.c
new file mode 100644
index 0000000..38005c0
--- /dev/null
+++ b/lib/ext/qcbor/test/qcbor_decode_tests.c
@@ -0,0 +1,2836 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#include "qcbor_decode_tests.h"
+#include "qcbor.h"
+#include <string.h>
+#include <math.h> // for fabs()
+
+
+#ifdef  PRINT_FUNCTIONS_FOR_DEBUGGING
+#include <stdio.h>
+
+static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf)
+{
+   if(szLabel) {
+      printf("%s ", szLabel);
+   }
+
+   size_t i;
+   for(i = 0; i < Buf.len; i++) {
+      uint8_t Z = ((uint8_t *)Buf.ptr)[i];
+      printf("%02x ", Z);
+   }
+   printf("\n");
+
+   fflush(stdout);
+}
+
+/*static void printencoded(const char *szLabel, const uint8_t *pEncoded, size_t nLen)
+{
+   PrintUsefulBufC(szLabel, (UsefulBufC){pEncoded, nLen});
+}*/
+#endif
+
+
+static const uint8_t spExpectedEncodedInts[] = {
+   0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01,
+   0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff,
+   0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff,
+   0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff,
+   0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01,
+   0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39,
+   0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd,
+   0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38,
+   0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00,
+   0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18,
+   0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00,
+   0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff,
+   0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00,
+   0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02,
+   0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff,
+   0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a,
+   0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff,
+   0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00,
+   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b,
+   0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+   0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff};
+
+
+// return CBOR error or -1 if type of value doesn't match
+
+static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
+{
+   QCBORItem          Item;
+   int nCBORError;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_ARRAY)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 || // Todo; fix this for 32-bit machines
+      Item.val.int64 != -9223372036854775807LL - 1)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -4294967297)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -4294967296)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -4294967295)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -4294967294)
+      return -1;
+
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -2147483648)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -2147483647)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -65538)
+      return  -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -65537)
+      return  -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -65536)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -65535)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -65534)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -257)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -256)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -255)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -254)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -25)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -24)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -23)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -1)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 0)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 0)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 1)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 22)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 23)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 24)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 25)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 26)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 254)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 255)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 256)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 257)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 65534)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 65535)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 65536)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 65537)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 65538)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 2147483647)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 2147483647)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 2147483648)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 2147483649)
+      return  -1;
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 4294967294)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 4294967295)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 4294967296)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 4294967297)
+      return  -1;
+
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 9223372036854775807LL)
+      return  -1;
+
+
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_UINT64 ||
+      Item.val.uint64 != 18446744073709551615ULL)
+      return  -1;
+
+
+   if(QCBORDecode_Finish(pDCtx) != QCBOR_SUCCESS) {
+      return -1;
+   }
+
+   return 0;
+}
+
+
+/*
+   Tests the decoding of lots of different integers sizes
+   and values.
+ */
+
+int IntegerValuesParseTest()
+{
+   int n;
+   QCBORDecodeContext DCtx;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts), QCBOR_DECODE_MODE_NORMAL);
+
+   n = IntegerValuesParseTestInternal(&DCtx);
+
+   return(n);
+}
+
+
+/*
+   Creates a simple CBOR array and returns it in *pEncoded. The array is malloced
+   and needs to be freed. This is used by several tests.
+
+   Two of the inputs can be set. Two other items in the array are fixed.
+
+ */
+
+static uint8_t spSimpleArrayBuffer[50];
+
+static int CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen)
+{
+   QCBOREncodeContext ECtx;
+   int nReturn = -1;
+
+   *pEncoded = NULL;
+   *pEncodedLen = INT32_MAX;
+
+   // loop runs CBOR encoding twice. First with no buffer to
+   // calculate the length so buffer can be allocated correctly,
+   // and last with the buffer to do the actual encoding
+   do {
+      QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen});
+      QCBOREncode_OpenArray(&ECtx);
+      QCBOREncode_AddInt64(&ECtx, nInt1);
+      QCBOREncode_AddInt64(&ECtx, nInt2);
+      QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"galactic", 8}));
+      QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"haven token", 11}));
+      QCBOREncode_CloseArray(&ECtx);
+
+      if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen))
+         goto Done;
+
+      if(*pEncoded != NULL) {
+         nReturn = 0;
+         goto Done;
+      }
+
+      // Use static buffer to avoid dependency on malloc()
+      if(*pEncodedLen > sizeof(spSimpleArrayBuffer)) {
+         goto Done;
+      }
+      *pEncoded = spSimpleArrayBuffer;
+
+   } while(1);
+
+Done:
+   return nReturn;
+}
+
+
+/*
+ {"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"
+   }
+  }
+ */
+
+static uint8_t pValidMapEncoded[] = {
+   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 } ;
+
+static int ParseOrderedArray(const uint8_t *pEncoded, size_t nLen, int64_t *pInt1, int64_t *pInt2,  const uint8_t **pBuf3, size_t *pBuf3Len,  const uint8_t **pBuf4, size_t *pBuf4Len)
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem          Item;
+   int                nReturn = -1; // assume error until success
+
+   QCBORDecode_Init(&DCtx, (UsefulBufC){pEncoded, nLen}, QCBOR_DECODE_MODE_NORMAL);
+
+   // Make sure the first thing is a map
+   if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY)
+      goto Done;
+
+   // First integer
+   if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64)
+      goto Done;
+   *pInt1 = Item.val.int64;
+
+   // Second integer
+   if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64)
+      goto Done;
+   *pInt2 = Item.val.int64;
+
+   // First string
+   if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING)
+      goto Done;
+   *pBuf3 = Item.val.string.ptr;
+   *pBuf3Len = Item.val.string.len;
+
+   // Second string
+   if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING)
+      goto Done;
+   *pBuf4 = Item.val.string.ptr;
+   *pBuf4Len = Item.val.string.len;
+
+   nReturn = 0;
+
+Done:
+   return(nReturn);
+}
+
+
+
+
+int SimpleArrayTest()
+{
+   uint8_t *pEncoded;
+   size_t  nEncodedLen;
+
+   int64_t i1=0, i2=0;
+   size_t i3=0, i4=0;
+   const uint8_t *s3= (uint8_t *)"";
+   const uint8_t *s4= (uint8_t *)"";
+
+
+   if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) {
+      return(-1);
+   }
+
+   ParseOrderedArray(pEncoded, nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4);
+
+   if(i1 != 23 ||
+      i2 != 6000 ||
+      i3 != 8 ||
+      i4 != 11 ||
+      memcmp("galactic", s3, 8) !=0 ||
+      memcmp("haven token", s4, 11) !=0) {
+      return(-1);
+   }
+
+   return(0);
+}
+
+
+
+static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80};
+
+int ParseDeepArrayTest()
+{
+   QCBORDecodeContext DCtx;
+   int nReturn = 0;
+   int i;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays), QCBOR_DECODE_MODE_NORMAL);
+
+   for(i = 0; i < 10; i++) {
+      QCBORItem Item;
+
+      if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+         Item.uDataType != QCBOR_TYPE_ARRAY ||
+         Item.uNestingLevel != i) {
+         nReturn = -1;
+         break;
+      }
+   }
+
+   return(nReturn);
+}
+
+// Big enough to test nesting to the depth of 24
+static uint8_t spTooDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+                                    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+                                    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+                                    0x80};
+
+int ParseTooDeepArrayTest()
+{
+   QCBORDecodeContext DCtx;
+   int nReturn = 0;
+   int i;
+   QCBORItem Item;
+
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL);
+
+   for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) {
+
+      if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
+         Item.uDataType != QCBOR_TYPE_ARRAY ||
+         Item.uNestingLevel != i) {
+         nReturn = -1;
+         break;
+      }
+   }
+
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP)
+      nReturn = -1;
+
+   return(nReturn);
+}
+
+
+
+
+int ShortBufferParseTest()
+{
+   int nResult  = 0;
+   QCBORDecodeContext DCtx;
+   int num;
+
+   for(num = sizeof(spExpectedEncodedInts)-1; num; num--) {
+      int n;
+
+      QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, num}, QCBOR_DECODE_MODE_NORMAL);
+
+      n = IntegerValuesParseTestInternal(&DCtx);
+
+      //printf("Len %d, result: %d\n", num, n);
+
+      if(n != QCBOR_ERR_HIT_END) {
+         nResult = -1;
+         goto Done;
+      }
+   }
+Done:
+   return nResult;
+}
+
+
+
+int ShortBufferParseTest2()
+{
+   uint8_t *pEncoded;
+   int      nReturn;
+   size_t   nEncodedLen;
+
+   int64_t i1, i2;
+   size_t i3, i4;
+   const uint8_t *s3, *s4;
+
+   nReturn = 0;
+
+   if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) {
+      return(-1);
+   }
+
+   for(nEncodedLen--; nEncodedLen; nEncodedLen--) {
+      int nResult = ParseOrderedArray(pEncoded, (uint32_t)nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4);
+      if(nResult == 0) {
+         nReturn = -1;
+      }
+   }
+
+   return(nReturn);
+}
+
+/*
+ Decode and thoroughly check a moderately complex
+ set of maps
+ */
+static int ParseMapTest1(QCBORDecodeMode nMode)
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+   int nCBORError;
+
+   QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, nMode);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      Item.val.uCount != 3)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 42 ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      Item.val.uCount != 2)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) ||
+      Item.uDataType != QCBOR_TYPE_MAP ||
+      Item.val.uCount != 4) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 98)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
+      return -1;
+   }
+
+   return 0;
+}
+
+
+/*
+ Decode and thoroughly check a moderately complex
+ set of maps
+ */
+int ParseMapAsArrayTest()
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+   int nCBORError;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY);
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY ||
+      Item.val.uCount != 6) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      Item.uLabelType != QCBOR_TYPE_NONE ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("first integer"))) {
+      return -2;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 42 ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc) {
+      return -3;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("an array of two strings")) ||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+      return -4;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      Item.val.uCount != 2) {
+      return -5;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.val.string.len != 7 ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) {
+      return -6;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) {
+      return -7;
+   }
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("map in a map"))) {
+      return -8;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY ||
+      Item.val.uCount != 8) {
+      return -9;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 1"))||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc) {
+      return -10;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) {
+      return -11;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 2")) ||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc) {
+      return -12;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) {
+      return -13;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("another int")) ||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+      return -14;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 98) {
+      return -15;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("text 2"))||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc) {
+      return -16;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_NONE ||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataAlloc ||
+      Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
+      return -17;
+   }
+
+   return 0;
+}
+
+
+/*
+ Fully or partially decode pValidMapEncoded. When
+ partially decoding check for the right error code.
+ How much partial decoding depends on nLevel.
+
+ The partial decodes test error conditions of
+ incomplete encoded input.
+
+ This could be combined with the above test
+ and made prettier and maybe a little more
+ thorough.
+ */
+static int ExtraBytesTest(int nLevel)
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+   int nCBORError;
+
+   QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, QCBOR_DECODE_MODE_NORMAL);
+
+   if(nLevel < 1) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      Item.val.uCount != 3)
+      return -1;
+
+   if(nLevel < 2) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.uCount != 42 ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) {
+      return -1;
+   }
+
+   if(nLevel < 3) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      Item.val.uCount != 2) {
+      return -1;
+   }
+
+
+   if(nLevel < 4) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) {
+      return -1;
+   }
+
+   if(nLevel < 5) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) {
+      return -1;
+   }
+
+   if(nLevel < 6) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) ||
+      Item.uDataType != QCBOR_TYPE_MAP ||
+      Item.val.uCount != 4)
+      return -1;
+
+   if(nLevel < 7) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1")) ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) {
+      return -1;
+   }
+
+   if(nLevel < 8) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) ||
+      Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) {
+      return -1;
+   }
+
+   if(nLevel < 9) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) ||
+      Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != 98)
+      return -1;
+
+   if(nLevel < 10) {
+      if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+         return -1;
+      } else {
+         return 0;
+      }
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+      return nCBORError;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))||
+      Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
+      return -1;
+   }
+
+   if(QCBORDecode_Finish(&DCtx)) {
+      return -1;
+   }
+
+   return 0;
+}
+
+
+
+
+int ParseMapTest()
+{
+   // Parse a moderatly complex map structure very thoroughl
+   int n = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL);
+
+   n = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+
+   if(!n) {
+      for(int i = 0; i < 10; i++) {
+         n = ExtraBytesTest(i);
+         if(n) {
+            break;
+         }
+      }
+   }
+
+   return(n);
+}
+
+
+static uint8_t spSimpleValues[] = {0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, 0xf8, 0xff};
+
+int ParseSimpleTest()
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+   int nCBORError;
+
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL);
+
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+      Item.val.uCount != 10)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_FALSE)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_TRUE)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_NULL)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_UNDEF)
+      return -1;
+
+   // A break
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19)
+      return -1;
+
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR)
+      return -1;
+
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR)
+      return -1;
+
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255)
+      return -1;
+
+   return 0;
+
+}
+
+
+struct FailInput {
+   UsefulBufC Input;
+   int nError;
+};
+
+
+struct FailInput  Failures[] = {
+   { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END },     // 1 byte integer missing the byte
+   { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28
+   { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 29
+   { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 30
+   { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length integer
+   { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte
+   { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte
+   { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte
+   { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length negative integer
+   { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END },     // Short byte string
+   { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28
+   { {(uint8_t[]){0x5f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length byte string
+   { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END },     // Short UTF-8 string
+   { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28
+   { {(uint8_t[]){0x7f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length UTF-8 string
+   { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_UNSUPPORTED } , // break
+   { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_INVALID_CBOR }, // An invalid encoding of a simple type
+   { {(uint8_t[]){0xf8, 0x1f}, 2}, QCBOR_ERR_INVALID_CBOR },  // An invalid encoding of a simple type
+   { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG },  // Text-based date, with an integer
+   { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG },   // Epoch date, with an byte string
+   { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG },   // tagged as both epoch and string dates
+   { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }  // big num tagged an int, not a byte string
+
+};
+
+
+int FailureTests()
+{
+   int nResult = 0;
+
+   struct FailInput *pFEnd = &Failures[0] + sizeof(Failures)/sizeof(struct FailInput);
+
+   for(struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) {
+      QCBORDecodeContext DCtx;
+      QCBORItem Item;
+      int nCBORError;
+
+      QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL);
+
+      while(1) {
+         nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+         if(QCBOR_ERR_HIT_END == nCBORError) {
+            break;
+         }
+         if(nCBORError != pF->nError) {
+            nResult = 1;
+            break;
+         }
+      }
+   }
+
+   {
+      QCBORDecodeContext DCtx;
+      QCBORItem Item;
+      int nCBORError;
+
+      QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL);
+
+      if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+         return nCBORError;
+      if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+         Item.val.uCount != 10)
+         return -1;
+
+      DCtx.InBuf.magic = 0; // Corrupt the UsefulInputBuf
+
+      nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+      if(nCBORError != QCBOR_ERR_HIT_END)
+         return -1;
+   }
+
+
+   return nResult;
+}
+
+
+/* Try all 256 values of the byte at nLen including recursing for
+ each of the values to try values at nLen+1 ... up to nLenMax
+ */
+static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax)
+{
+   if(nLen >= nLenMax) {
+      return;
+   }
+
+   for(int inputByte = 0; inputByte < 256; inputByte++) {
+      // Set up the input
+      pBuf[nLen] = inputByte;
+      const UsefulBufC Input = {pBuf, nLen+1};
+
+      // Get ready to parse
+      QCBORDecodeContext DCtx;
+      QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL);
+
+      // Parse by getting the next item until an error occurs
+      // Just about every possible decoder error can occur here
+      // The goal of this test is not to check for the correct
+      // error since that is not really possible. It is to
+      // see that there is no crash on hostile input.
+      while(1) {
+         QCBORItem Item;
+         QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+         if(nCBORError != QCBOR_SUCCESS) {
+            break;
+         }
+      }
+
+      ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax);
+   }
+}
+
+
+/*
+ Public function for initialization. See header qcbor.h
+ */
+int ComprehensiveInputTest()
+{
+   // Size 2 tests 64K inputs and runs quickly
+   uint8_t pBuf[2];
+
+   ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf));
+
+   return 0;
+}
+
+
+/*
+ Public function for initialization. See header qcbor.h
+ */
+int BigComprehensiveInputTest()
+{
+   // size 3 tests 16 million inputs and runs OK
+   // in seconds on fast machines. Size 4 takes
+   // 10+ minutes and 5 half a day on fast
+   // machines. This test is kept separate from
+   // the others so as to no slow down the use
+   // of them as a very frequent regression.
+   uint8_t pBuf[3]; //
+
+   ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf));
+
+   return 0;
+}
+
+
+static uint8_t spDateTestInput[] = {
+   0xc0, // tag for string date
+   0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string
+
+   0xc1, // tag for epoch date
+   0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
+
+   // CBOR_TAG_B64
+   0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags TODO: fix this test
+   0x1a, 0x53, 0x72, 0x4E, 0x01,
+
+   0xc1, // tag for epoch date
+   0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer
+
+   0xc1, // tag for epoch date
+   0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1
+
+   0xc1, // tag for epoch date
+   0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large
+
+};
+
+
+// have to check float expected only to within an epsilon
+int CHECK_EXPECTED_DOUBLE(double val, double expected) {
+
+   double diff = val - expected;
+
+   diff = fabs(diff);
+
+   return diff > 0.0000001;
+}
+
+
+int DateParseTest()
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+   int nCBORError;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), QCBOR_DECODE_MODE_NORMAL);
+
+   const uint64_t uTags[] = {15};
+   QCBORTagListIn TagList = {1, uTags};
+
+   QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList);
+
+   // String date
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_DATE_STRING ||
+      UsefulBuf_Compare(Item.val.dateString, UsefulBuf_FromSZ("1985-04-12"))){
+      return -2;
+   }
+
+   // Epoch date
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -3;
+   if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
+      Item.val.epochDate.nSeconds != 1400000000 ||
+      Item.val.epochDate.fSecondsFraction != 0 ) {
+      return -4;
+   }
+
+   // Epoch date with extra CBOR_TAG_B64 tag that doesn't really mean anything
+   // but want to be sure extra tag doesn't cause a problem
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -5;
+   if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
+      Item.val.epochDate.nSeconds != 1400000001 ||
+      Item.val.epochDate.fSecondsFraction != 0 ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_B64)) {
+      return -6;
+   }
+
+   // Epoch date that is too large for our representation
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
+      return -7;
+   }
+
+   // Epoch date in float format with fractional seconds
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -8;
+   if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
+      Item.val.epochDate.nSeconds != 1 ||
+      CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) {
+      return -9;
+   }
+
+   // Epoch date float that is too large for our representation
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
+      return -10;
+   }
+
+   // TODO: could use a few more tests with float, double, and half precsion and negative (but coverage is still pretty good)
+
+   return 0;
+}
+
+// Really simple basic input for tagging test
+static uint8_t spOptTestInput[] = {
+   0xd9, 0xd9, 0xf7, // CBOR magic number
+   0x81, // Array of one
+   0xd8, 0x04, // non-preferred serialization of tag 4
+   0x82, 0x01, 0x03}; // fraction 1/3
+
+static uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x80};
+
+// 0x9192939495969798, 0x88, 0x01, 0x04
+static uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0xd8, 0x88, 0xc5, 0xc4, 0x80};
+
+/*
+ The cbor.me parse of this.
+ 55799(55799(55799({6(7(-23)): 5859837686836516696(7({7(-20): 11({17(-18): 17(17(17("Organization"))),
+ 9(-17): 773("SSG"), -15: 4(5(6(7(8(9(10(11(12(13(14(15("Confusion")))))))))))), 17(-16): 17("San Diego"),
+ 17(-14): 17("US")}), 23(-19): 19({-11: 9({-9: -7}),
+ 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A')})})),
+ 16(-22): 23({11(8(7(-5))): 8(-3)})})))
+ */
+static uint8_t spCSRWithTags[] = {
+   0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2,
+      0xc6, 0xc7, 0x36,
+      0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2,
+         0xda, 0x00, 0x00, 0x00, 0x07, 0x33,
+         0xcb, 0xa5,
+            0xd1, 0x31,
+            0xd1, 0xd1, 0xd1, 0x6c,
+               0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+            0xc9, 0x30,
+            0xd9, 0x03, 0x05, 0x63,
+               0x53, 0x53, 0x47,
+            0x2e,
+            0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x69,
+               0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e,
+            0xd1, 0x2f,
+            0xd1, 0x69,
+               0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f,
+            0xd1, 0x2d,
+            0xd1, 0x62,
+               0x55, 0x53,
+         0xd7, 0x32,
+         0xd3, 0xa2,
+            0x2a,
+            0xc9, 0xa1,
+               0x28,
+               0x26,
+            0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29,
+            0xcc, 0x4a,
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a,
+   0xd0, 0x35,
+   0xd7, 0xa1,
+      0xcb, 0xc8, 0xc7, 0x24,
+      0xc8, 0x22};
+
+static int CheckCSRMaps(QCBORDecodeContext *pDC);
+
+
+int OptTagParseTest()
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput), QCBOR_DECODE_MODE_NORMAL);
+
+   //-------------------------
+   // This text matches the magic number tag and the fraction tag
+   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+      return -2;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) {
+      return -3;
+   }
+
+   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+      return -4;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_FRACTION) ||
+      Item.val.uCount != 2) {
+      return -5;
+   }
+
+   // --------------------------------
+   // This test decodes the very large tag, but it is not in
+   // any list so it is ignored.
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
+   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+      return -6;
+   }
+   if(Item.uTagBits) {
+      return -7;
+   }
+
+   // ----------------------------------
+   // This test sets up a caller-config list that includes the very large tage and then matches it.
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
+   const uint64_t puList[] = {0x9192939495969798, 257};
+   const QCBORTagListIn TL = {2, puList};
+   QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL);
+
+   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+      return -8;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 257) ||
+      QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) ||
+      Item.val.uCount != 0) {
+      return -9;
+   }
+
+   //------------------------
+   // This test sets up a caller-configured list, and looks up something not in it
+   const uint64_t puLongList[17] = {1,2,1};
+   const QCBORTagListIn TLLong = {17, puLongList};
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong);
+   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+      return -11;
+   }
+
+   // -----------------------
+   // This tests retrievel of the full tag list
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL);
+   uint64_t puTags[16];
+   QCBORTagListOut Out = {0, 4, puTags};
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -12;
+   }
+   if(puTags[0] != 0x9192939495969798 ||
+      puTags[1] != 0x88 ||
+      puTags[2] != 0x05 ||
+      puTags[3] != 0x04) {
+      return -13;
+   }
+
+   // ----------------------
+   // This text if too small of an out list
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL);
+   QCBORTagListOut OutSmall = {0, 3, puTags};
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) {
+      return -14;
+   }
+
+   // ---------------
+   // Parse a version of the "CSR" that has had a ton of tags randomly inserted
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL);
+   int n = CheckCSRMaps(&DCtx);
+   if(n) {
+      return n-2000;
+   }
+
+   Out = (QCBORTagListOut){0,16, puTags};
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL);
+
+   const uint64_t puTagList[] = {773, 1, 90599561};
+   const QCBORTagListIn TagList = {3, puTagList};
+   QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList);
+
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -100;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 90599561) ||
+      QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) ||
+      Item.val.uCount != 2 ||
+      puTags[0] != CBOR_TAG_CBOR_MAGIC ||
+      puTags[1] != CBOR_TAG_CBOR_MAGIC ||
+      puTags[2] != CBOR_TAG_CBOR_MAGIC ||
+      Out.uNumUsed != 3) {
+      return -101;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -102;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 6) ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 7) || // item is tagged 7, but 7 is not configured to be recognized
+      Item.val.uCount != 2 ||
+      puTags[0] != 5859837686836516696 ||
+      puTags[1] != 7 ||
+      Out.uNumUsed != 2) {
+      return -103;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -104;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      Item.uTagBits ||
+      Item.val.uCount != 5 ||
+      puTags[0] != 0x0b ||
+      Out.uNumUsed != 1) {
+      return -105;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -106;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) ||
+      Item.val.string.len != 12 ||
+      puTags[0] != CBOR_TAG_COSE_MAC0 ||
+      puTags[1] != CBOR_TAG_COSE_MAC0 ||
+      puTags[2] != CBOR_TAG_COSE_MAC0 ||
+      Out.uNumUsed != 3) {
+      return -105;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -107;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, 773) ||
+      Item.val.string.len != 3 ||
+      puTags[0] != 773 ||
+      Out.uNumUsed != 1) {
+      return -108;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -109;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, 4) ||
+      Item.val.string.len != 9 ||
+      puTags[0] != 4 ||
+      puTags[11] != 0x0f ||
+      Out.uNumUsed != 12) {
+      return -110;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -111;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, 17) ||
+      Item.val.string.len != 9 ||
+      puTags[0] != 17 ||
+      Out.uNumUsed != 1) {
+      return -112;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -111;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, 17) ||
+      Item.val.string.len != 2 ||
+      puTags[0] != 17 ||
+      Out.uNumUsed != 1) {
+      return -112;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -113;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 19) ||
+      Item.val.uCount != 2 ||
+      puTags[0] != 19 ||
+      Out.uNumUsed != 1) {
+      return -114;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -115;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 9) ||
+      Item.uTagBits ||
+      Item.val.uCount != 1 ||
+      puTags[0] != 9 ||
+      Out.uNumUsed != 1) {
+      return -116;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -116;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.val.int64 != -7 ||
+      Item.uTagBits ||
+      Out.uNumUsed != 0) {
+      return -117;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -118;
+   }
+   if(Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+      Item.val.string.len != 10 ||
+      Item.uTagBits ||
+      puTags[0] != 12 ||
+      Out.uNumUsed != 1) {
+      return -119;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -120;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP ||
+      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) ||
+      Item.val.uCount != 1 ||
+      puTags[0] != 0x17 ||
+      Out.uNumUsed != 1) {
+      return -121;
+   }
+
+   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
+      return -122;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64 ||
+      QCBORDecode_IsTagged(&DCtx, &Item, 8) ||
+      Item.val.int64 != -3 ||
+      puTags[0] != 8 ||
+      Out.uNumUsed != 1) {
+      return -123;
+   }
+
+   if(QCBORDecode_Finish(&DCtx)) {
+      return -124;
+   }
+
+   return 0;
+}
+
+
+
+
+static uint8_t spBigNumInput[] = {
+ 0x83,
+   0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xA4,
+     0x63, 0x42, 0x4E, 0x2B,
+       0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x18, 0x40,
+       0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x63, 0x42, 0x4E, 0x2D,
+       0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x38, 0x3F,
+       0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+static uint8_t spBigNum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+int BignumParseTest()
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem Item;
+   int nCBORError;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL);
+
+
+   //
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -1;
+   }
+
+   //
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_POSBIGNUM ||
+      UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
+      return -1;
+   }
+
+   //
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM ||
+      UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
+      return -1;
+   }
+
+   //
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_MAP) {
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_POSBIGNUM ||
+      Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_POSBIGNUM ||
+      Item.uLabelType != QCBOR_TYPE_INT64 ||
+      Item.label.int64 != 64 ||
+      UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM ||
+      Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
+      return -1;
+   }
+
+   if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+      return -1;
+   if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM ||
+      Item.uLabelType != QCBOR_TYPE_INT64 ||
+      Item.label.int64 != -64 ||
+      UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
+      return -1;
+   }
+
+   return 0;
+}
+
+
+
+static int CheckItemWithIntLabel(QCBORDecodeContext *pCtx, uint8_t uDataType, uint8_t uNestingLevel, uint8_t uNextNest, int64_t nLabel, QCBORItem *pItem)
+{
+   QCBORItem Item;
+   int nCBORError;
+
+   if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1;
+   if(Item.uDataType != uDataType) return -1;
+   if(uNestingLevel > 0) {
+      if(Item.uLabelType != QCBOR_TYPE_INT64 &&  Item.uLabelType != QCBOR_TYPE_UINT64) return -1;
+      if(Item.uLabelType == QCBOR_TYPE_INT64) {
+         if(Item.label.int64 != nLabel) return -1;
+      } else  {
+         if(Item.label.uint64 != (uint64_t)nLabel) return -1;
+      }
+   }
+   if(Item.uNestingLevel != uNestingLevel) return -1;
+   if(Item.uNextNestLevel != uNextNest) return -1;
+
+   if(pItem) {
+      *pItem = Item;
+   }
+   return 0;
+}
+
+
+// Same code checks definite and indefinite length versions of the map
+static int CheckCSRMaps(QCBORDecodeContext *pDC)
+{
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1;
+
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -1;
+
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -1;
+
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -1;
+
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -1;
+
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -1;
+
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -1;
+   if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -1;
+
+   if(QCBORDecode_Finish(pDC)) return -2;
+
+   return 0;
+}
+
+
+/*
+// cbor.me decoded output
+{
+    -23: {
+        -20: {
+            -18: "Organization",
+            -17: "SSG",
+            -15: "Confusion",
+            -16: "San Diego",
+            -14: "US"
+        },
+        -19: {
+            -11: {
+                -9: -7
+            },
+            -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n'
+        }
+    },
+    -22: {
+        -5: -3
+    }
+}
+ */
+
+
+static uint8_t spCSRInput[] = {
+   0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f,
+   0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74,
+   0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47,
+   0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73,
+   0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e,
+   0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62,
+   0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26,
+   0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+   0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22};
+
+int NestedMapTest()
+{
+   QCBORDecodeContext DCtx;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL);
+
+   return CheckCSRMaps(&DCtx);
+}
+
+
+
+int StringDecoderModeFailTest()
+{
+   QCBORDecodeContext DCtx;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+
+   QCBORItem Item;
+   QCBORError nCBORError;
+
+   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+      return -1;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP) {
+      return -2;
+   }
+
+   nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+   if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) {
+      return -3;
+   }
+
+   return 0;
+}
+
+
+// Same map as above, but using indefinite lengths
+static uint8_t spCSRInputIndefLen[] = {
+   0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f,
+   0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74,
+   0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47,
+   0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73,
+   0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e,
+   0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62,
+   0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28,
+   0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04,
+   0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff,
+   0x35, 0xbf, 0x24, 0x22, 0xff, 0xff};
+
+int NestedMapTestIndefLen()
+{
+   QCBORDecodeContext DCtx;
+
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), QCBOR_DECODE_MODE_NORMAL);
+
+   return CheckCSRMaps(&DCtx);
+}
+
+
+
+static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage)
+{
+   UsefulOutBuf UOB;
+   UsefulOutBuf_Init(&UOB, Storage);
+
+   int i;
+   for(i = 0; i < n; i++) {
+      UsefulOutBuf_AppendByte(&UOB, 0x9f);
+   }
+
+   for(i = 0; i < n; i++) {
+      UsefulOutBuf_AppendByte(&UOB, 0xff);
+   }
+   return UsefulOutBuf_OutUBuf(&UOB);
+}
+
+
+static int parse_indeflen_nested(UsefulBufC Nested, int nNestLevel)
+{
+   QCBORDecodeContext DC;
+   QCBORDecode_Init(&DC, Nested, 0);
+
+   int j;
+   for(j = 0; j < nNestLevel; j++) {
+      QCBORItem Item;
+      int nReturn = QCBORDecode_GetNext(&DC, &Item);
+      if(j >= QCBOR_MAX_ARRAY_NESTING) {
+         // Should be in error
+         if(nReturn != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
+            return -4;
+         } else {
+            return 0; // Decoding doesn't recover after an error
+         }
+      } else {
+         // Should be no error
+         if(nReturn) {
+            return -9; // Should not have got an error
+         }
+      }
+      if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+         return -7;
+      }
+   }
+   int nReturn = QCBORDecode_Finish(&DC);
+   if(nReturn) {
+      return -3;
+   }
+   return 0;
+}
+
+
+int IndefiniteLengthNestTest()
+{
+   UsefulBuf_MAKE_STACK_UB(Storage, 50);
+   int i;
+   for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) {
+      const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage);
+      int nReturn = parse_indeflen_nested(Nested, i);
+      if(nReturn) {
+         return nReturn;
+      }
+   }
+   return 0;
+}
+
+
+
+static const uint8_t spIndefiniteArray[]     = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; // [1, [2, 3]]
+static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; // No closing break
+static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; // Not enough closing breaks
+static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; // Too many closing breaks
+static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; // Unclosed indeflen inside def len
+static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; // confused tag
+
+int IndefiniteLengthArrayMapTest()
+{
+   int nResult;
+   // --- first test -----
+    UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray);
+
+    // Decode it and see if it is OK
+    UsefulBuf_MAKE_STACK_UB(MemPool, 150);
+    QCBORDecodeContext DC;
+    QCBORItem Item;
+    QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+    QCBORDecode_SetMemPool(&DC, MemPool, false);
+
+    QCBORDecode_GetNext(&DC, &Item);
+
+    if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+       Item.uNestingLevel != 0 ||
+       Item.uNextNestLevel != 1) {
+       return -111;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_INT64 ||
+       Item.uNestingLevel != 1 ||
+       Item.uNextNestLevel != 1) {
+        return -2;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_ARRAY ||
+       Item.uNestingLevel != 1 ||
+       Item.uNextNestLevel != 2) {
+        return -3;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_INT64 ||
+       Item.uNestingLevel != 2 ||
+       Item.uNextNestLevel != 2) {
+        return -4;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_INT64 ||
+       Item.uNestingLevel != 2 ||
+       Item.uNextNestLevel != 0) {
+        return -5;
+    }
+
+    if(QCBORDecode_Finish(&DC)) {
+        return -6;
+    }
+
+   // --- next test -----
+   IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1);
+
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_SetMemPool(&DC, MemPool, false);
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -7;
+   }
+
+   nResult = QCBORDecode_Finish(&DC);
+   if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+      return -8;
+   }
+
+
+   // --- next test -----
+   IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2);
+
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_SetMemPool(&DC, MemPool, false);
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -9;
+   }
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -10;
+   }
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_INT64) {
+      return -11;
+   }
+
+   nResult = QCBORDecode_Finish(&DC);
+   if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+      return -12;
+   }
+
+
+   // --- next test -----
+   IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3);
+
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_SetMemPool(&DC, MemPool, false);
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -13;
+   }
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult != QCBOR_ERR_BAD_BREAK) {
+      return -14;
+   }
+
+
+   // --- next test -----
+   IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4);
+
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_SetMemPool(&DC, MemPool, false);
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -15;
+   }
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -16;
+   }
+
+   nResult = QCBORDecode_Finish(&DC);
+   if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+      return -17;
+   }
+
+   // --- next test -----
+   IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5);
+
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_SetMemPool(&DC, MemPool, false);
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -18;
+   }
+
+   nResult = QCBORDecode_GetNext(&DC, &Item);
+   if(nResult != QCBOR_ERR_BAD_BREAK) {
+      return -19;
+   }
+
+    return 0;
+}
+
+
+static const uint8_t spIndefiniteLenString[] = {
+   0x81, // Array of length one
+   0x7f, // text string marked with indefinite length
+   0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment
+   0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment
+   0xff // ending break
+};
+
+static const uint8_t spIndefiniteLenStringBad2[] = {
+   0x81, // Array of length one
+   0x7f, // text string marked with indefinite length
+   0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment
+   0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type
+   0xff // ending break
+};
+
+static const uint8_t spIndefiniteLenStringBad3[] = {
+   0x81, // Array of length one
+   0x7f, // text string marked with indefinite length
+   0x01, 0x02, // Not a string
+   0xff // ending break
+};
+
+static const uint8_t spIndefiniteLenStringBad4[] = {
+   0x81, // Array of length one
+   0x7f, // text string marked with indefinite length
+   0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment
+   0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment
+   // missing end of string
+};
+
+static const uint8_t spIndefiniteLenStringLabel[] = {
+   0xa1, // Array of length one
+   0x7f, // text string marked with indefinite length
+   0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment
+   0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment
+   0xff, // ending break
+   0x01 // integer being labeled.
+};
+
+static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) // TODO: size this
+{
+   UsefulOutBuf UOB;
+
+   UsefulOutBuf_Init(&UOB, Storage);
+   UsefulOutBuf_AppendByte(&UOB, 0x81);
+   UsefulOutBuf_AppendByte(&UOB, 0x5f);
+
+   int i = 0;
+   for(int nChunkSize = 1; nChunkSize <= 128; nChunkSize *= 2) {
+      UsefulOutBuf_AppendByte(&UOB, 0x58);
+      UsefulOutBuf_AppendByte(&UOB, (uint8_t)nChunkSize);
+      for(int j = 0; j < nChunkSize; j++ ) {
+         UsefulOutBuf_AppendByte(&UOB, i);
+         i++;
+      }
+   }
+   UsefulOutBuf_AppendByte(&UOB, 0xff);
+
+   return UsefulOutBuf_OutUBuf(&UOB);
+}
+
+static int CheckBigString(UsefulBufC BigString)
+{
+   if(BigString.len != 255) {
+      return 1;
+   }
+
+   for(uint8_t i = 0; i < 255; i++){
+      if(((const uint8_t *)BigString.ptr)[i] != i) {
+         return 1;
+      }
+   }
+   return 0;
+}
+
+
+int IndefiniteLengthStringTest()
+{
+   QCBORDecodeContext DC;
+   QCBORItem Item;
+   // big enough for MakeIndefiniteBigBstr() + MemPool overhead
+   UsefulBuf_MAKE_STACK_UB(MemPool, 350);
+
+   // --- Simple normal indefinite length string ------
+   UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString);
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
+      return -1;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -2;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) {
+      return -3;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -4;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) {
+      return -5;
+   }
+   if(QCBORDecode_Finish(&DC)) {
+      return -6;
+   }
+
+   // ----- types mismatch ---
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), QCBOR_DECODE_MODE_NORMAL);
+
+   if(QCBORDecode_SetMemPool(&DC,  MemPool, false)) {
+      return -7;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -8;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -9;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) {
+      return -10;
+   }
+
+   // ----- not a string ---
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), QCBOR_DECODE_MODE_NORMAL);
+
+   if(QCBORDecode_SetMemPool(&DC,  MemPool, false)) {
+      return -11;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -12;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -13;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) {
+      return -14;
+   }
+
+   // ----- no end -----
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), QCBOR_DECODE_MODE_NORMAL);
+
+   if(QCBORDecode_SetMemPool(&DC,  MemPool, false)) {
+      return -15;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -16;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -17;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) {
+      return -18;
+   }
+
+   // ------ Don't set a string allocator and see an error -----
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -19;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) {
+      return -20;
+   }
+
+   // ----- Mempool is way too small -----
+   UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, 20); // 20 is too small no matter what
+
+   QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+   if(!QCBORDecode_SetMemPool(&DC,  MemPoolTooSmall, false)) {
+      return -21;
+   }
+
+   // ----- Mempool is way too small -----
+   UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290);
+   const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage);
+
+   UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); // 80 is big enough for MemPool overhead, but not BigIndefBStr
+
+   QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL);
+   if(QCBORDecode_SetMemPool(&DC,  MemPoolSmall, false)) {
+      return -22;
+   }
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -23;
+   }
+   if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) {
+      return -24;
+   }
+
+   // ---- big bstr -----
+   QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL);
+
+   if(QCBORDecode_SetMemPool(&DC,  MemPool, false)) {
+      return -25;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -26;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) {
+      return -26;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)) {
+      return -27;
+   }
+   if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) {
+      return -28;
+   }
+   if(CheckBigString(Item.val.string)) {
+      return -3;
+   }
+   if(QCBORDecode_Finish(&DC)) {
+      return -29;
+   }
+
+   // --- label is an indefinite length string ------
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL);
+
+   if(QCBORDecode_SetMemPool(&DC,  MemPool, false)) {
+      return -30;
+   }
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP) {
+      return -31;
+   }
+
+   if(QCBORDecode_GetNext(&DC, &Item)){
+      return -32;
+   }
+   if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || Item.uDataType != QCBOR_TYPE_INT64 ||
+      Item.uDataAlloc || !Item.uLabelAlloc ||
+      UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) {
+      return -33;
+   }
+
+   if(QCBORDecode_Finish(&DC)) {
+      return -34;
+   }
+
+    return 0;
+}
+
+
+int AllocAllStringsTest()
+{
+   QCBORDecodeContext DC;
+   QCBORError nCBORError;
+
+
+   // First test, use the "CSRMap" as easy input and checking
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL);
+
+   UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE);
+
+   nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying.
+   if(nCBORError) {
+      return -1;
+   }
+
+   if(CheckCSRMaps(&DC)) {
+      return -2;
+   }
+
+   // Next parse, save pointers to a few strings, destroy original and see all is OK.
+   UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE);
+   const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded));
+
+   QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL);
+   UsefulBuf_Set(Pool, '/');
+   QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying.
+
+   QCBORItem Item1, Item2, Item3, Item4;
+   if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
+      return nCBORError;
+   if(Item1.uDataType != QCBOR_TYPE_MAP ||
+      Item1.val.uCount != 3)
+      return -3;
+   if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
+      return nCBORError;
+   if((nCBORError = QCBORDecode_GetNext(&DC, &Item2)))
+      return nCBORError;
+   if((nCBORError = QCBORDecode_GetNext(&DC, &Item3)))
+      return nCBORError;
+   if((nCBORError = QCBORDecode_GetNext(&DC, &Item4)))
+      return nCBORError;
+
+   UsefulBuf_Set(CopyOfStorage, '_');
+
+   if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      Item1.uDataType != QCBOR_TYPE_INT64 ||
+      Item1.val.int64 != 42 ||
+      UsefulBuf_Compare(Item1.label.string, UsefulBuf_FromSZ("first integer"))) {
+      return -4;
+   }
+
+
+   if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item2.label.string, UsefulBuf_FromSZ("an array of two strings")) ||
+      Item2.uDataType != QCBOR_TYPE_ARRAY ||
+      Item2.val.uCount != 2)
+      return -5;
+
+   if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item3.val.string, UsefulBuf_FromSZ("string1"))) {
+      return -6;
+   }
+
+   if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING ||
+      UsefulBuf_Compare(Item4.val.string, UsefulBuf_FromSZ("string2"))) {
+      return -7;
+   }
+
+   // Next parse with a pool that is too small
+   UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1);
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying.
+   if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
+      return -8;
+   if(Item1.uDataType != QCBOR_TYPE_MAP ||
+      Item1.val.uCount != 3) {
+      return -9;
+   }
+   if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){
+      if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) {
+         if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) {
+            nCBORError = QCBORDecode_GetNext(&DC, &Item4);
+         }
+      }
+   }
+   if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) {
+      return -10;
+   }
+
+   return 0;
+}
+
+// Cheating declaration to get to the special test hook
+size_t MemPoolTestHook_GetPoolSize(void *ctx);
+
+
+int MemPoolTest(void)
+{
+   // Set up the decoder with a tiny bit of CBOR to parse
+   QCBORDecodeContext DC;
+   const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map
+   QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0);
+
+   // Set up an memory pool of 100 bytes
+   UsefulBuf_MAKE_STACK_UB(Pool, 100);
+   QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0);
+   if(nError) {
+      return -9;
+   }
+
+   // Cheat a little to get to the string allocator object
+   // so we can call it directly to test it
+   QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)DC.pStringAllocator;
+   // Cheat some more to know exactly the
+   size_t uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc);
+
+   // First test -- ask for too much in one go
+   UsefulBuf Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool+1);
+   if(!UsefulBuf_IsNULL(Allocated)) {
+      return -1;
+   }
+
+
+   // Re do the set up for the next test that will do a successful alloc,
+   // a fail, a free and then success
+   // This test should work on 32 and 64-bit machines if the compiler
+   // does the expected thing with pointer sizes for the internal
+   // MemPool implementation leaving 44 or 72 bytes of pool memory.
+   QCBORDecode_SetMemPool(&DC, Pool, 0);
+
+   // Cheat a little to get to the string allocator object
+   // so we can call it directly to test it
+   pAlloc = (QCBORStringAllocator *)DC.pStringAllocator;
+   // Cheat some more to know exactly the
+   uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc);
+
+   Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool-1);
+   if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed
+      return -2;
+   }
+   UsefulBuf Allocated2 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2);
+   if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail
+      return -3;
+   }
+   (*pAlloc->fFree)(pAlloc->pAllocaterContext, Allocated.ptr);
+   Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2);
+   if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free
+      return -4;
+   }
+
+
+   // Re do set up for next test that involves a successful alloc,
+   // and a successful realloc and a failed realloc
+   QCBORDecode_SetMemPool(&DC, Pool, 0);
+
+   // Cheat a little to get to the string allocator object
+   // so we can call it directly to test it
+   pAlloc = (QCBORStringAllocator *)DC.pStringAllocator;
+   Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2);
+   if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed
+      return -5;
+   }
+   Allocated2 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, Allocated.ptr, uAvailPool);
+   if(UsefulBuf_IsNULL(Allocated2)) {
+      return -6;
+   }
+   if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) {
+      return -7;
+   }
+   UsefulBuf Allocated3 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, Allocated.ptr, uAvailPool+1);
+   if(!UsefulBuf_IsNULL(Allocated3)) { // expected to fail
+      return -8;
+   }
+
+   return 0;
+}
+
diff --git a/lib/ext/qcbor/test/qcbor_decode_tests.h b/lib/ext/qcbor/test/qcbor_decode_tests.h
new file mode 100644
index 0000000..2b09c55
--- /dev/null
+++ b/lib/ext/qcbor/test/qcbor_decode_tests.h
@@ -0,0 +1,229 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#ifndef __QCBOR__qcbort_decode_tests__
+#define __QCBOR__qcbort_decode_tests__
+
+#include "qcbor.h"
+
+
+/*
+ Notes:
+
+ - All the functions in qcbor.h are called once in the aggregation of all the tests below.
+
+ - All the types that are supported are given as input and parsed by these tests
+
+ - There is some hostile input such as invalid lengths and CBOR too complex
+   and types this parser doesn't handle
+
+ */
+
+
+
+
+/*
+ Parse a well-known set of integers including those around the boundaries and
+ make sure the expected values come out
+ */
+int IntegerValuesParseTest(void);
+
+
+
+
+
+/*
+ Decode a simple CBOR encoded array and make sure it returns all the correct values.
+ This is a decode test.
+ */
+int SimpleArrayTest(void);
+
+
+/*
+ Make sure a maximally deep array can be parsed and that the
+ reported nesting level is correct.  This uses test vector
+ of CBOR encoded data with a depth of 10.  This a parse test.
+ */
+int ParseDeepArrayTest(void);
+
+
+/*
+ See that the correct error is reported when parsing
+ an array of depth 11, one too large.
+ */
+int ParseTooDeepArrayTest(void);
+
+
+/*
+  Try to parse some legit CBOR types that this parsers
+  doesn't support.
+ */
+int UnsupportedCBORDecodeTest(void);
+
+
+/*
+  This takes the encoded CBOR integers used in the above test and parses
+  it over and over with one more byte less each time. It should fail
+  every time on incorrect CBOR input. This is a hostile input decode test.
+ */
+int ShortBufferParseTest(void);
+
+
+/*
+   Same as ShortBufferParseTest, but with a different encoded CBOR input.
+   It is another hostile input test
+ */
+int ShortBufferParseTest2(void);
+
+
+/*
+  Parses the somewhat complicated CBOR MAP and makes sure all the correct
+  values parse out.  About 15 values are tested. This is a decode test.
+ */
+int ParseMapTest(void);
+
+
+
+int FloatValuesTest1(void);
+
+
+
+int SimpleValuesTest1(void);
+
+
+/*
+
+ */
+int ParseMapAsArrayTest(void);
+
+
+
+int ParseSimpleTest(void);
+
+
+
+/*
+ Tests a number of failure cases on bad CBOR to get the right error code
+ */
+int FailureTests(void);
+
+
+/*
+ Parses all possible inputs that are two bytes long. Main point
+ is that the test doesn't crash as it doesn't evaluate the
+ input for correctness in any way.
+
+ (Parsing all possible 3 byte strings takes too long on all but
+  very fast machines).
+ */
+int ComprehensiveInputTest(void);
+
+
+/*
+ Parses all possible inputs that are four bytes long. Main point
+ is that the test doesn't crash as it doesn't evaluate the
+ input for correctness in any way. This runs very slow, so it
+ is only practical as a once-in-a-while regression test on
+ fast machines.
+ */
+int BigComprehensiveInputTest(void);
+
+
+/*
+ Thest the date types -- epoch and strings
+ */
+int DateParseTest(void);
+
+
+/*
+  Test optional tags like the CBOR magic number.
+ */
+int OptTagParseTest(void);
+
+
+/*
+ Parse some big numbers, positive and negative
+ */
+int BignumParseTest(void);
+
+
+int StringDecoderModeFailTest(void);
+
+
+/*
+ Parse some nested maps
+ */
+int NestedMapTest(void);
+
+
+/*
+ Parse maps with indefinite lengths
+ */
+int NestedMapTestIndefLen(void);
+
+
+/*
+ Parse some maps and arrays with indefinite lengths.
+ Includes some error cases.
+ */
+int IndefiniteLengthArrayMapTest(void);
+
+
+/*
+ Parse indefinite length strings. Uses
+ MemPool. Includes error cases.
+ */
+int IndefiniteLengthStringTest(void);
+
+
+/*
+ Test deep nesting of indefinite length
+ maps and arrays including too deep.
+ */
+int IndefiniteLengthNestTest(void);
+
+
+/*
+ Test parsing strings were all strings, not
+ just indefinite length strings, are
+ allocated. Includes error test cases.
+ */
+int AllocAllStringsTest(void);
+
+
+/*
+ Direct test of MemPool string allocator
+ */
+int MemPoolTest(void);
+
+
+#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/lib/ext/qcbor/test/qcbor_encode_tests.c b/lib/ext/qcbor/test/qcbor_encode_tests.c
new file mode 100644
index 0000000..2a22cf1
--- /dev/null
+++ b/lib/ext/qcbor/test/qcbor_encode_tests.c
@@ -0,0 +1,2007 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#include "qcbor.h"
+#include "qcbor_encode_tests.h"
+
+
+/*
+ This is the test set for CBOR encoding.
+
+ This is largely complete for the implemented.
+
+ A few more things to do include:
+   - Add a test for counting the top level items and adding it back in with AddRaw()
+   - Run on some different CPUs like 32-bit and maybe even 16-bit
+   - Test the large array count limit
+   - Add the CBOR diagnostic output for every expected
+
+ */
+
+//#define PRINT_FUNCTIONS_FOR_DEBUGGINGXX
+
+#ifdef  PRINT_FUNCTIONS_FOR_DEBUGGINGXX
+#include <stdio.h>
+
+// ifdef these out to not have compiler warnings
+static void printencoded(const uint8_t *pEncoded, size_t nLen)
+{
+   size_t i;
+   for(i = 0; i < nLen; i++) {
+      uint8_t Z = pEncoded[i];
+      printf("%02x ", Z);
+   }
+   printf("\n");
+
+   fflush(stdout);
+}
+
+
+// Do the comparison and print out where it fails
+static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) {
+   size_t i;
+   for(i = 0; i < U1.len; i++) {
+      if(((uint8_t *)U1.ptr)[i] != ((uint8_t *)U2.ptr)[i]) {
+         printf("Position: %d  Actual: 0x%x   Expected: 0x%x\n", i, ((uint8_t *)U1.ptr)[i], ((uint8_t *)U2.ptr)[i]);
+         return 1;
+      }
+   }
+   return 0;
+
+}
+
+#define CheckResults(Enc, Expected) \
+   UsefulBuf_Compare_Print(Enc, (UsefulBufC){Expected, sizeof(Expected)})
+
+#else
+
+#define CheckResults(Enc, Expected) \
+   UsefulBuf_Compare(Enc, (UsefulBufC){Expected, sizeof(Expected)})
+
+#endif
+
+
+
+// One big buffer that is used by all the tests to encode into
+// Putting it in uninitialized data is better than using a lot
+// of stack. The tests should run on small devices too.
+static uint8_t spBigBuf[2200];
+
+
+
+/*
+ Some very minimal tests.
+ */
+int BasicEncodeTest()
+{
+   // Very simple CBOR, a map with one boolean that is true in it
+   QCBOREncodeContext EC;
+
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddBoolToMapN(&EC, 66, true);
+   QCBOREncode_CloseMap(&EC);
+
+   UsefulBufC Encoded;
+   if(QCBOREncode_Finish(&EC, &Encoded)) {
+      return -1;
+   }
+
+
+   // Decode it and see that is right
+   QCBORDecodeContext DC;
+   QCBORItem Item;
+   QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP) {
+      return -2;
+   }
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_TRUE) {
+      return -3;
+   }
+
+   if(QCBORDecode_Finish(&DC)) {
+      return -4;
+   }
+
+
+   // Make another encoded message with the CBOR from the previous put into this one
+   UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20);
+   QCBOREncode_Init(&EC, MemoryForEncoded2);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddUInt64(&EC, 451);
+   QCBOREncode_AddEncoded(&EC, Encoded);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddEncodedToMapN(&EC, -70000, Encoded);
+   QCBOREncode_CloseMap(&EC);
+   QCBOREncode_CloseArray(&EC);
+
+   UsefulBufC Encoded2;
+   if(QCBOREncode_Finish(&EC, &Encoded2)) {
+      return -5;
+   }
+    /*
+     [                // 0    1:3
+        451,          // 1    1:2
+        {             // 1    1:2   2:1
+          66: true    // 2    1:1
+        },
+        {             // 1    1:1   2:1
+          -70000: {   // 2    1:1   2:1   3:1
+            66: true  // 3    XXXXXX
+          }
+        }
+     ]
+
+
+
+      83                # array(3)
+         19 01C3        # unsigned(451)
+         A1             # map(1)
+            18 42       # unsigned(66)
+            F5          # primitive(21)
+         A1             # map(1)
+            3A 0001116F # negative(69999)
+            A1          # map(1)
+               18 42    # unsigned(66)
+               F5       # primitive(21)
+     */
+
+   // Decode it and see if it is OK
+   QCBORDecode_Init(&DC, Encoded2, QCBOR_DECODE_MODE_NORMAL);
+
+   // 0    1:3
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
+      return -6;
+   }
+
+   // 1    1:2
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_INT64 || Item.val.uint64 != 451) {
+      return -7;
+   }
+
+   // 1    1:2   2:1
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
+      return -8;
+   }
+
+   // 2    1:1
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_TRUE) {
+      return -9;
+   }
+
+   // 1    1:1   2:1
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
+      return -10;
+   }
+
+   // 2    1:1   2:1   3:1
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1 || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != -70000) {
+      return -11;
+   }
+
+   // 3    XXXXXX
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_TRUE || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != 66) {
+      return -12;
+   }
+
+   if(QCBORDecode_Finish(&DC)) {
+      return -13;
+   }
+
+   return 0;
+}
+
+
+
+static const uint8_t spExpectedEncodedAll[] = {
+ 0x98, 0x22, 0x66, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x32, 0xd8,
+ 0x64, 0x1a, 0x05, 0x5d, 0x23, 0x15, 0x65, 0x49, 0x4e, 0x54,
+ 0x36, 0x34, 0xd8, 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x12, 0x16,
+ 0xaf, 0x2b, 0x15, 0x00, 0x38, 0x2b, 0xa4, 0x63, 0x4c, 0x42,
+ 0x4c, 0x18, 0x4d, 0x23, 0x18, 0x58, 0x78, 0x1a, 0x4e, 0x45,
+ 0x47, 0x4c, 0x42, 0x4c, 0x54, 0x48, 0x41, 0x54, 0x20, 0x49,
+ 0x53, 0x20, 0x4b, 0x49, 0x4e, 0x44, 0x20, 0x4f, 0x46, 0x20,
+ 0x4c, 0x4f, 0x4e, 0x47, 0x3b, 0x00, 0x00, 0x02, 0x2d, 0x9a,
+ 0xc6, 0x94, 0x55, 0x3a, 0x05, 0xf5, 0xe0, 0xff, 0x3a, 0x2f,
+ 0xaf, 0x07, 0xff, 0xc1, 0x1a, 0x8e, 0x15, 0x1c, 0x8a,
+ 0xa3, 0x74, 0x4c, 0x6f, 0x6e, 0x67, 0x4c, 0x69, 0x76, 0x65,
+ 0x44, 0x65, 0x6e, 0x69, 0x73, 0x52, 0x69, 0x74, 0x63, 0x68,
+ 0x69, 0x65, 0xc1, 0x1a, 0x53, 0x72, 0x4e, 0x00, 0x66, 0x74,
+ 0x69, 0x6d, 0x65, 0x28, 0x29, 0xc1, 0x1a, 0x58, 0x0d, 0x41,
+ 0x72, 0x39, 0x07, 0xb0, 0xc1, 0x1a, 0x58, 0x0d, 0x3f, 0x76,
+ 0x42, 0xff, 0x00, 0xa3, 0x66, 0x62, 0x69, 0x6e, 0x62, 0x69,
+ 0x6e, 0xda, 0x00, 0x01, 0x86, 0xa0, 0x41, 0x00, 0x66, 0x62,
+ 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x01, 0x02, 0x03, 0x00,
+ 0x44, 0x04, 0x02, 0x03, 0xfe, 0x6f, 0x62, 0x61, 0x72, 0x20,
+ 0x62, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x62, 0x61,
+ 0x72, 0x64, 0x6f, 0x6f, 0x66, 0x0a, 0xd8, 0x20, 0x78, 0x6b,
+ 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x74, 0x61,
+ 0x63, 0x6b, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x32, 0x38, 0x30, 0x35, 0x39,
+ 0x36, 0x39, 0x37, 0x2f, 0x68, 0x6f, 0x77, 0x2d, 0x64, 0x6f,
+ 0x2d, 0x69, 0x2d, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x2d,
+ 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x2d, 0x64, 0x65,
+ 0x62, 0x75, 0x67, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x72, 0x65,
+ 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x62, 0x75, 0x69, 0x6c,
+ 0x64, 0x73, 0x2d, 0x69, 0x6e, 0x2d, 0x78, 0x63, 0x6f, 0x64,
+ 0x65, 0x2d, 0x36, 0x2d, 0x37, 0x2d, 0x38, 0xd8, 0x22, 0x78,
+ 0x1c, 0x59, 0x57, 0x35, 0x35, 0x49, 0x47, 0x4e, 0x68, 0x63,
+ 0x6d, 0x35, 0x68, 0x62, 0x43, 0x42, 0x77, 0x62, 0x47, 0x56,
+ 0x68, 0x63, 0x33, 0x56, 0x79, 0x5a, 0x51, 0x3d, 0x3d, 0xd8,
+ 0x23, 0x67, 0x5b, 0x5e, 0x61, 0x62, 0x63, 0x5d, 0x2b, 0xd8,
+ 0x24, 0x79, 0x01, 0x57, 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e,
+ 0x30, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
+ 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74,
+ 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65,
+ 0x64, 0x3b, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72,
+ 0x79, 0x3d, 0x22, 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75,
+ 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74,
+ 0x22, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+ 0x20, 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61,
+ 0x72, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+ 0x20, 0x69, 0x6e, 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66,
+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d,
+ 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61,
+ 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65,
+ 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61,
+ 0x69, 0x6e, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69,
+ 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79,
+ 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58,
+ 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72,
+ 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a,
+ 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69,
+ 0x6e, 0x3b, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x2d, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69,
+ 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68,
+ 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74,
+ 0x2e, 0x74, 0x78, 0x74, 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69,
+ 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61,
+ 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20,
+ 0x74, 0x65, 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58,
+ 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79,
+ 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x2d, 0xae, 0x65, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x6f, 0x66, 0x6f, 0x6f, 0x20, 0x62,
+ 0x61, 0x72, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, 0x6f, 0x6f,
+ 0x64, 0x5f, 0x5f, 0x5f, 0x5f, 0x67, 0x66, 0x6f, 0x6f, 0x20,
+ 0x62, 0x61, 0x72, 0x66, 0x28, 0x29, 0x28, 0x29, 0x28, 0x29,
+ 0xd9, 0x03, 0xe8, 0x6b, 0x72, 0x61, 0x62, 0x20, 0x72, 0x61,
+ 0x62, 0x20, 0x6f, 0x6f, 0x66, 0x16, 0x6f, 0x66, 0x6f, 0x6f,
+ 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66,
+ 0x6f, 0x6f, 0x62, 0x5e, 0x5e, 0x69, 0x6f, 0x6f, 0x6f, 0x6f,
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x66, 0x18, 0x63, 0x6d, 0x66, 0x66,
+ 0x66, 0x66, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
+ 0x66, 0x63, 0x52, 0x46, 0x43, 0xd8, 0x20, 0x78, 0x31, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x6f, 0x6f,
+ 0x6c, 0x73, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72,
+ 0x67, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2f, 0x72, 0x66, 0x63,
+ 0x37, 0x30, 0x34, 0x39, 0x23, 0x73, 0x65, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2d, 0x32, 0x2e, 0x34, 0x2e, 0x35, 0x18, 0x89,
+ 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x63, 0x62, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x2f, 0x68, 0x77,
+ 0x68, 0x65, 0x6e, 0x69, 0x6d, 0x36, 0x34, 0xd8, 0x22, 0x6c,
+ 0x63, 0x47, 0x78, 0x6c, 0x59, 0x58, 0x4e, 0x31, 0x63, 0x6d,
+ 0x55, 0x75, 0x18, 0x40, 0xd8, 0x22, 0x68, 0x63, 0x33, 0x56,
+ 0x79, 0x5a, 0x53, 0x34, 0x3d, 0x64, 0x70, 0x6f, 0x70, 0x6f,
+ 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5c, 0x73, 0x2a, 0x6d,
+ 0x6b, 0x38, 0x32, 0xd8, 0x23, 0x66, 0x70, 0x65, 0x72, 0x6c,
+ 0x5c, 0x42, 0x63, 0x4e, 0x65, 0x64, 0xd8, 0x24, 0x79, 0x01,
+ 0x57, 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70,
+ 0x65, 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61,
+ 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x3b, 0x0a,
+ 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22,
+ 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61,
+ 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x22, 0x0a, 0x0a,
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20,
+ 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x20,
+ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e,
+ 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, 0x6f, 0x72, 0x6d,
+ 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58,
+ 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20,
+ 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65,
+ 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74,
+ 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x0a,
+ 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x65,
+ 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58,
+ 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74,
+ 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65,
+ 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0a,
+ 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69,
+ 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a,
+ 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e,
+ 0x74, 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d,
+ 0x65, 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78,
+ 0x74, 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69,
+ 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61,
+ 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x78,
+ 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62,
+ 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65,
+ 0x78, 0x74, 0x2d, 0x2d, 0x0a, 0xd8, 0x24, 0x79, 0x01, 0x57,
+ 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x43, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65,
+ 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72,
+ 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x3b, 0x0a, 0x62,
+ 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22, 0x58,
+ 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72,
+ 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x22, 0x0a, 0x0a, 0x54,
+ 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6d,
+ 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6d,
+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20,
+ 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61,
+ 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58,
+ 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74,
+ 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65,
+ 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x0a, 0x0a,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x65, 0x78,
+ 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62,
+ 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65,
+ 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78,
+ 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0a, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69, 0x73,
+ 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20,
+ 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74,
+ 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
+ 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74,
+ 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
+ 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74,
+ 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f,
+ 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, 0x78,
+ 0x74, 0x2d, 0x2d, 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2d,
+ 0x31, 0x32, 0x2d, 0x31, 0x33, 0x54, 0x31, 0x38, 0x3a, 0x33,
+ 0x30, 0x3a, 0x30, 0x32, 0x5a, 0xa2, 0x68, 0x42, 0x65, 0x64,
+ 0x20, 0x74, 0x69, 0x6d, 0x65, 0xc0, 0x78, 0x1c, 0x32, 0x30,
+ 0x30, 0x33, 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x33, 0x54, 0x31,
+ 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x32, 0x2e, 0x32, 0x35,
+ 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x18, 0x58, 0xc0, 0x78,
+ 0x1c, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x31, 0x32, 0x2d, 0x31,
+ 0x33, 0x54, 0x31, 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x32,
+ 0x2e, 0x32, 0x35, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xf7,
+ 0xa3, 0x64, 0x64, 0x61, 0x72, 0x65, 0xd8, 0x42, 0xf5, 0x62,
+ 0x75, 0x75, 0xf4, 0x1a, 0x00, 0x0b, 0x41, 0x62, 0xf6, 0x80,
+ 0xa3, 0x78, 0x1c, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x20, 0x61,
+ 0x6e, 0x64, 0x20, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x20,
+ 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x61, 0x72, 0x72, 0x61,
+ 0x79, 0xd9, 0x04, 0x45, 0x80, 0x65, 0x61, 0x6c, 0x61, 0x62,
+ 0x6c, 0x80, 0x18, 0x2a, 0x80, 0xa1, 0x68, 0x69, 0x6e, 0x20,
+ 0x61, 0x20, 0x6d, 0x61, 0x70, 0xa1, 0x19, 0x15, 0xb4, 0xa1,
+ 0x6e, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x61,
+ 0x20, 0x69, 0x6e, 0x20, 0x61, 0xd9, 0x23, 0x7f, 0xa0, 0xa5,
+ 0x62, 0x73, 0x31, 0xd8, 0x58, 0xf8, 0xff, 0x62, 0x73, 0x32,
+ 0xe0, 0x62, 0x73, 0x33, 0xd8, 0x58, 0xf8, 0x21, 0x1a, 0x05,
+ 0x44, 0x8c, 0x06, 0xd8, 0x58, 0xf8, 0xff, 0x18, 0x59, 0xd8,
+ 0x58, 0xf3, 0xd8, 0x25, 0x50, 0x53, 0x4d, 0x41, 0x52, 0x54,
+ 0x43, 0x53, 0x4c, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41,
+ 0x32, 0xa2, 0x64, 0x55, 0x55, 0x55, 0x55, 0xd8, 0x25, 0x50,
+ 0x53, 0x4d, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4c, 0x54, 0x54,
+ 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, 0x18, 0x63, 0xd8, 0x25,
+ 0x50, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4c, 0x54,
+ 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, 0xf5, 0xf4, 0xa2,
+ 0x71, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x20, 0x69, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0xf5, 0x19,
+ 0x10, 0x41, 0xf5, 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x63, 0x42, 0x4E, 0x2B,
+ 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x40, 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x42, 0x4E, 0x2D, 0xC3, 0x49,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+ 0x3F, 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+
+static const char *szMIME = "\
+MIME-Version: 1.0\n\
+Content-Type: multipart/mixed;\n\
+boundary=\"XXXXboundary text\"\n\
+\n\
+This is a multipart message in MIME format.\n\
+\n\
+--XXXXboundary text\n\
+Content-Type: text/plain\n\
+\n\
+this is the body text\n\
+\n\
+--XXXXboundary text\n\
+Content-Type: text/plain;\n\
+Content-Disposition: attachment;\n\
+filename=\"test.txt\"\n\
+\n\
+this is the attachment text\n\
+\n\
+--XXXXboundary text--";
+
+
+int AllAddMethodsTest()
+{
+   // TODO: this test should be broken down into several so it is more managable. Tags and labels could be more sensible
+   QCBOREncodeContext ECtx;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_OpenArray(&ECtx);
+
+   // Some ints that are tagged and have strings preceeding them (not labels becase it is not a map)
+   QCBOREncode_AddSZString(&ECtx, "UINT62");
+   QCBOREncode_AddTag(&ECtx, 100);
+   QCBOREncode_AddUInt64(&ECtx, 89989909);
+   QCBOREncode_AddSZString(&ECtx, "INT64");
+   QCBOREncode_AddTag(&ECtx, 76);
+   QCBOREncode_AddInt64(&ECtx, 77689989909);
+   QCBOREncode_AddUInt64(&ECtx,0);
+   QCBOREncode_AddInt64(&ECtx, -44);
+
+   // ints that go in maps
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddUInt64ToMap(&ECtx, "LBL", 77);
+   QCBOREncode_AddUInt64ToMapN(&ECtx, -4, 88);
+   QCBOREncode_AddInt64ToMap(&ECtx, "NEGLBLTHAT IS KIND OF LONG", -2394893489238);
+   QCBOREncode_AddInt64ToMapN(&ECtx, -100000000, -800000000);
+   QCBOREncode_CloseMap(&ECtx);
+
+   // Epoch Date
+   QCBOREncode_AddDateEpoch(&ECtx, 2383748234);
+
+   // Epoch date with labels
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddDateEpochToMap(&ECtx, "LongLiveDenisRitchie", 1400000000);
+   QCBOREncode_AddDateEpochToMap(&ECtx, "time()", 1477263730);
+   QCBOREncode_AddDateEpochToMapN(&ECtx, -1969, 1477263222);
+   QCBOREncode_CloseMap(&ECtx);
+
+   // Binary blobs
+   QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0xff, 0x00}, 2}));
+
+   // binary blobs in maps
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddSZString(&ECtx, "binbin");
+   QCBOREncode_AddTag(&ECtx, 100000);
+   QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1}));
+   QCBOREncode_AddBytesToMap(&ECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3}));
+   QCBOREncode_AddBytesToMapN(&ECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4}));
+   QCBOREncode_CloseMap(&ECtx);
+
+   // text blobs
+   QCBOREncode_AddText(&ECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar"));
+   QCBOREncode_AddSZString(&ECtx, "oof\n");
+   QCBOREncode_AddURI(&ECtx, UsefulBuf_FROM_SZ_LITERAL("http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8"));
+   QCBOREncode_AddB64Text(&ECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ=="));
+   QCBOREncode_AddRegex(&ECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+"));
+   QCBOREncode_AddMIMEData(&ECtx, UsefulBuf_FromSZ(szMIME));
+
+   // text blobs in maps
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddTextToMap(&ECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo"));
+   QCBOREncode_AddTextToMap(&ECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar"));
+   QCBOREncode_AddSZString(&ECtx, "()()()");
+   QCBOREncode_AddTag(&ECtx, 1000);
+   QCBOREncode_AddSZString(&ECtx, "rab rab oof");
+   QCBOREncode_AddTextToMapN(&ECtx,22, UsefulBuf_FROM_SZ_LITERAL("foo foo foo foo"));
+   QCBOREncode_AddSZStringToMap(&ECtx, "^^", "oooooooof");
+   QCBOREncode_AddSZStringToMapN(&ECtx, 99, "ffffoooooooof");
+   QCBOREncode_AddURIToMap(&ECtx, "RFC", UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5"));
+   QCBOREncode_AddURIToMapN(&ECtx, 0x89, UsefulBuf_FROM_SZ_LITERAL("http://cbor.me/"));
+   QCBOREncode_AddB64TextToMap(&ECtx, "whenim64", UsefulBuf_FROM_SZ_LITERAL("cGxlYXN1cmUu"));
+   QCBOREncode_AddB64TextToMapN(&ECtx, 64, UsefulBuf_FROM_SZ_LITERAL("c3VyZS4="));
+   QCBOREncode_AddRegexToMap(&ECtx, "popo", UsefulBuf_FROM_SZ_LITERAL("100\\s*mk")); //   x code string literal bug
+   QCBOREncode_AddRegexToMapN(&ECtx, -51, UsefulBuf_FROM_SZ_LITERAL("perl\\B"));  //   x code string literal bug
+   QCBOREncode_AddMIMEDataToMap(&ECtx, "Ned", UsefulBuf_FromSZ(szMIME));
+   QCBOREncode_AddMIMEDataToMapN(&ECtx, 10, UsefulBuf_FromSZ(szMIME));
+   QCBOREncode_CloseMap(&ECtx);
+
+   // Date strings
+   QCBOREncode_AddDateString(&ECtx, "2003-12-13T18:30:02Z");
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddDateStringToMap(&ECtx, "Bed time", "2003-12-13T18:30:02.25+01:00");
+   QCBOREncode_AddDateStringToMapN(&ECtx, 88, "2003-12-13T18:30:02.25+01:00");
+   QCBOREncode_CloseMap(&ECtx);
+
+   // true / false ...
+   QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF);
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddSZString(&ECtx, "dare");
+   QCBOREncode_AddTag(&ECtx, 66);
+   QCBOREncode_AddBool(&ECtx, true);
+   QCBOREncode_AddBoolToMap(&ECtx, "uu", false);
+   QCBOREncode_AddSimpleToMapN(&ECtx, 737634, CBOR_SIMPLEV_NULL);
+   QCBOREncode_CloseMap(&ECtx);
+
+   // opening an array
+   QCBOREncode_OpenArray(&ECtx);
+   QCBOREncode_CloseArray(&ECtx);
+
+   // opening arrays in a map
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddSZString(&ECtx, "label and tagged empty array");
+   QCBOREncode_AddTag(&ECtx, 1093);
+   QCBOREncode_OpenArray(&ECtx);
+   QCBOREncode_CloseArray(&ECtx);
+   QCBOREncode_OpenArrayInMap(&ECtx, "alabl");
+   QCBOREncode_CloseArray(&ECtx);
+   QCBOREncode_OpenArrayInMapN(&ECtx, 42);
+   QCBOREncode_CloseArray(&ECtx);
+   QCBOREncode_CloseMap(&ECtx);
+
+   // opening maps with labels and tagging
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_OpenMapInMap(&ECtx, "in a map");
+   QCBOREncode_OpenMapInMapN(&ECtx, 5556);
+   QCBOREncode_AddSZString(&ECtx, "in a in a in a");
+   QCBOREncode_AddTag(&ECtx, 9087);
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_CloseMap(&ECtx);
+   QCBOREncode_CloseMap(&ECtx);
+   QCBOREncode_CloseMap(&ECtx);
+   QCBOREncode_CloseMap(&ECtx);
+
+
+   // Extended simple values (these are not standard...)
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddSZString(&ECtx, "s1");
+   QCBOREncode_AddTag(&ECtx, 88);
+   QCBOREncode_AddSimple(&ECtx, 255);
+   QCBOREncode_AddSimpleToMap(&ECtx, "s2", 0);
+   QCBOREncode_AddSZString(&ECtx, "s3");
+   QCBOREncode_AddTag(&ECtx, 88);
+   QCBOREncode_AddSimple(&ECtx, 33);
+   QCBOREncode_AddInt64(&ECtx, 88378374); // label before tag
+   QCBOREncode_AddTag(&ECtx, 88);
+   QCBOREncode_AddSimple(&ECtx, 255);
+   QCBOREncode_AddInt64(&ECtx, 89); // label before tag
+   QCBOREncode_AddTag(&ECtx, 88);
+   QCBOREncode_AddSimple(&ECtx, 19);
+   QCBOREncode_CloseMap(&ECtx);
+
+   // UUIDs
+   static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32};
+   const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID);
+   QCBOREncode_AddBinaryUUID(&ECtx, XXUUID);
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddBinaryUUIDToMap(&ECtx, "UUUU", XXUUID);
+   QCBOREncode_AddBinaryUUIDToMapN(&ECtx, 99, XXUUID);
+   QCBOREncode_CloseMap(&ECtx);
+
+   // Bool
+   QCBOREncode_AddBool(&ECtx, true);
+   QCBOREncode_AddBool(&ECtx, false);
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddBoolToMap(&ECtx, "George is the man", true);
+   QCBOREncode_AddBoolToMapN(&ECtx, 010101, true);
+   QCBOREncode_CloseMap(&ECtx);
+
+
+   static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+   const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum);
+   QCBOREncode_AddPositiveBignum(&ECtx, BIGNUM);
+   QCBOREncode_AddNegativeBignum(&ECtx, BIGNUM);
+   QCBOREncode_OpenMap(&ECtx);
+   QCBOREncode_AddPositiveBignumToMap(&ECtx, "BN+", BIGNUM);
+   QCBOREncode_AddPositiveBignumToMapN(&ECtx, 64, BIGNUM);
+   QCBOREncode_AddNegativeBignumToMap(&ECtx, "BN-", BIGNUM);
+   QCBOREncode_AddNegativeBignumToMapN(&ECtx, -64, BIGNUM);
+   QCBOREncode_CloseMap(&ECtx);
+
+   QCBOREncode_CloseArray(&ECtx);
+
+   UsefulBufC Enc;
+
+   if(QCBOREncode_Finish(&ECtx, &Enc)) {
+      nReturn = -1;
+      goto Done;
+   }
+
+   if(CheckResults(Enc, spExpectedEncodedAll))
+      nReturn = -2;
+
+Done:
+   return nReturn;
+}
+
+/*
+ 98 2F                  # array(47)
+   3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807)
+   3B 0000000100000000 # negative(4294967296)
+   3A FFFFFFFF         # negative(4294967295)
+   3A FFFFFFFE         # negative(4294967294)
+   3A FFFFFFFD         # negative(4294967293)
+   3A 7FFFFFFF         # negative(2147483647)
+   3A 7FFFFFFE         # negative(2147483646)
+   3A 00010001         # negative(65537)
+   3A 00010000         # negative(65536)
+   39 FFFF             # negative(65535)
+   39 FFFE             # negative(65534)
+   39 FFFD             # negative(65533)
+   39 0100             # negative(256)
+   38 FF               # negative(255)
+   38 FE               # negative(254)
+   38 FD               # negative(253)
+   38 18               # negative(24)
+   37                  # negative(23)
+   36                  # negative(22)
+   20                  # negative(0)
+   00                  # unsigned(0)
+   00                  # unsigned(0)
+   01                  # unsigned(1)
+   16                  # unsigned(22)
+   17                  # unsigned(23)
+   18 18               # unsigned(24)
+   18 19               # unsigned(25)
+   18 1A               # unsigned(26)
+   18 FE               # unsigned(254)
+   18 FF               # unsigned(255)
+   19 0100             # unsigned(256)
+   19 0101             # unsigned(257)
+   19 FFFE             # unsigned(65534)
+   19 FFFF             # unsigned(65535)
+   1A 00010000         # unsigned(65536)
+   1A 00010001         # unsigned(65537)
+   1A 00010002         # unsigned(65538)
+   1A 7FFFFFFF         # unsigned(2147483647)
+   1A 7FFFFFFF         # unsigned(2147483647)
+   1A 80000000         # unsigned(2147483648)
+   1A 80000001         # unsigned(2147483649)
+   1A FFFFFFFE         # unsigned(4294967294)
+   1A FFFFFFFF         # unsigned(4294967295)
+   1B 0000000100000000 # unsigned(4294967296)
+   1B 0000000100000001 # unsigned(4294967297)
+   1B 7FFFFFFFFFFFFFFF # unsigned(9223372036854775807)
+   1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615)
+ */
+static const uint8_t spExpectedEncodedInts[] = {
+   0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01,
+   0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff,
+   0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff,
+   0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff,
+   0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01,
+   0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39,
+   0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd,
+   0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38,
+   0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00,
+   0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18,
+   0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00,
+   0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff,
+   0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00,
+   0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02,
+   0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff,
+   0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a,
+   0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff,
+   0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00,
+   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b,
+   0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+   0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff};
+
+/*
+
+  Test the generation of integers. This also ends up testing
+  encoding of all the different lengths. It encodes integers
+  of many lengths and values, especially around the boundaries
+  for different types of integers.  It compares the output
+  to expected values generated from http://cbor.me.
+
+ */
+int IntegerValuesTest1()
+{
+   QCBOREncodeContext ECtx;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_OpenArray(&ECtx);
+
+   QCBOREncode_AddInt64(&ECtx, -9223372036854775807LL - 1);
+   QCBOREncode_AddInt64(&ECtx, -4294967297);
+   QCBOREncode_AddInt64(&ECtx, -4294967296);
+   QCBOREncode_AddInt64(&ECtx, -4294967295);
+   QCBOREncode_AddInt64(&ECtx, -4294967294);
+   QCBOREncode_AddInt64(&ECtx, -2147483648);
+   QCBOREncode_AddInt64(&ECtx, -2147483647);
+   QCBOREncode_AddInt64(&ECtx, -65538);
+   QCBOREncode_AddInt64(&ECtx, -65537);
+   QCBOREncode_AddInt64(&ECtx, -65536);
+   QCBOREncode_AddInt64(&ECtx, -65535);
+   QCBOREncode_AddInt64(&ECtx, -65534);
+   QCBOREncode_AddInt64(&ECtx, -257);
+   QCBOREncode_AddInt64(&ECtx, -256);
+   QCBOREncode_AddInt64(&ECtx, -255);
+   QCBOREncode_AddInt64(&ECtx, -254);
+   QCBOREncode_AddInt64(&ECtx, -25);
+   QCBOREncode_AddInt64(&ECtx, -24);
+   QCBOREncode_AddInt64(&ECtx, -23);
+   QCBOREncode_AddInt64(&ECtx, -1);
+   QCBOREncode_AddInt64(&ECtx, 0);
+   QCBOREncode_AddUInt64(&ECtx, 0ULL);
+   QCBOREncode_AddInt64(&ECtx, 1);
+   QCBOREncode_AddInt64(&ECtx, 22);
+   QCBOREncode_AddInt64(&ECtx, 23);
+   QCBOREncode_AddInt64(&ECtx, 24);
+   QCBOREncode_AddInt64(&ECtx, 25);
+   QCBOREncode_AddInt64(&ECtx, 26);
+   QCBOREncode_AddInt64(&ECtx, 254);
+   QCBOREncode_AddInt64(&ECtx, 255);
+   QCBOREncode_AddInt64(&ECtx, 256);
+   QCBOREncode_AddInt64(&ECtx, 257);
+   QCBOREncode_AddInt64(&ECtx, 65534);
+   QCBOREncode_AddInt64(&ECtx, 65535);
+   QCBOREncode_AddInt64(&ECtx, 65536);
+   QCBOREncode_AddInt64(&ECtx, 65537);
+   QCBOREncode_AddInt64(&ECtx, 65538);
+   QCBOREncode_AddInt64(&ECtx, 2147483647);
+   QCBOREncode_AddInt64(&ECtx, 2147483647);
+   QCBOREncode_AddInt64(&ECtx, 2147483648);
+   QCBOREncode_AddInt64(&ECtx, 2147483649);
+   QCBOREncode_AddInt64(&ECtx, 4294967294);
+   QCBOREncode_AddInt64(&ECtx, 4294967295);
+   QCBOREncode_AddInt64(&ECtx, 4294967296);
+   QCBOREncode_AddInt64(&ECtx, 4294967297);
+   QCBOREncode_AddInt64(&ECtx, 9223372036854775807LL);
+   QCBOREncode_AddUInt64(&ECtx, 18446744073709551615ULL);
+
+   QCBOREncode_CloseArray(&ECtx);
+
+   UsefulBufC Enc;
+   if(QCBOREncode_Finish(&ECtx, &Enc)) {
+      nReturn = -1;
+   }
+
+   if(CheckResults(Enc, spExpectedEncodedInts))
+     return -2;
+
+   return(nReturn);
+}
+
+
+/*
+ 85                  # array(5)
+   F5               # primitive(21)
+   F4               # primitive(20)
+   F6               # primitive(22)
+   F7               # primitive(23)
+   A1               # map(1)
+      65            # text(5)
+         554E446566 # "UNDef"
+      F7            # primitive(23)
+ */
+static const uint8_t spExpectedEncodedSimple[] = {
+   0x85, 0xf5, 0xf4, 0xf6, 0xf7, 0xa1, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7};
+
+int SimpleValuesTest1()
+{
+   QCBOREncodeContext ECtx;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_OpenArray(&ECtx);
+
+   QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE);
+   QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE);
+   QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL);
+   QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF);
+
+   QCBOREncode_OpenMap(&ECtx);
+
+   QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF);
+   QCBOREncode_CloseMap(&ECtx);
+
+   QCBOREncode_CloseArray(&ECtx);
+
+   UsefulBufC ECBOR;
+   if(QCBOREncode_Finish(&ECtx, &ECBOR)) {
+      nReturn = -1;
+   }
+
+   if(CheckResults(ECBOR, spExpectedEncodedSimple))
+      return -2;
+
+   return(nReturn);
+}
+
+
+/*
+ 83                                      # array(3)
+   C0                                   # tag(0)
+      74                                # text(20)
+         323031332D30332D32315432303A30343A30305A # "2013-03-21T20:04:00Z"
+   C1                                   # tag(1)
+      1A 514B67B0                       # unsigned(1363896240)
+   A2                                   # map(2)
+      78 19                             # text(25)
+         53616D706C6520446174652066726F6D205246432033333339 # "Sample Date from RFC 3339"
+      C0                                # tag(0)
+         77                             # text(23)
+            313938352D30342D31325432333A32303A35302E35325A # "1985-04-12T23:20:50.52Z"
+      62                                # text(2)
+         5344                           # "SD"
+      C1                                # tag(1)
+         19 03E7                        # unsigned(999)
+ */
+static const uint8_t spExpectedEncodedDates[] = {
+   0x83, 0xc0, 0x74, 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30, 0x33,
+   0x2d, 0x32, 0x31, 0x54, 0x32, 0x30, 0x3a, 0x30, 0x34, 0x3a,
+   0x30, 0x30, 0x5a, 0xc1, 0x1a, 0x51, 0x4b, 0x67, 0xb0, 0xa2,
+   0x78, 0x19, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44,
+   0x61, 0x74, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x52,
+   0x46, 0x43, 0x20, 0x33, 0x33, 0x33, 0x39, 0xc0, 0x77, 0x31,
+   0x39, 0x38, 0x35, 0x2d, 0x30, 0x34, 0x2d, 0x31, 0x32, 0x54,
+   0x32, 0x33, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x30, 0x2e, 0x35,
+   0x32, 0x5a, 0x62, 0x53, 0x44, 0xc1, 0x19, 0x03, 0xe7
+};
+
+int EncodeDateTest()
+{
+   QCBOREncodeContext ECtx;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_OpenArray(&ECtx);
+
+
+   QCBOREncode_AddDateString(&ECtx, "2013-03-21T20:04:00Z"); // from CBOR RFC
+   QCBOREncode_AddDateEpoch(&ECtx, 1363896240); // from CBOR RFC
+
+
+   QCBOREncode_OpenMap(&ECtx);
+
+   QCBOREncode_AddDateStringToMap(&ECtx, "Sample Date from RFC 3339", "1985-04-12T23:20:50.52Z");
+
+   QCBOREncode_AddDateEpochToMap(&ECtx, "SD", 999);
+
+   QCBOREncode_CloseMap(&ECtx);
+
+   QCBOREncode_CloseArray(&ECtx);
+
+   UsefulBufC ECBOR;
+
+   if(QCBOREncode_Finish(&ECtx, &ECBOR)) {
+      nReturn = -1;
+   }
+
+   if(CheckResults(ECBOR, spExpectedEncodedDates))
+      return -2;
+
+   return(nReturn);
+}
+
+
+int ArrayNestingTest1()
+{
+   QCBOREncodeContext ECtx;
+   int i;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
+      QCBOREncode_OpenArray(&ECtx);
+   }
+   for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
+      QCBOREncode_CloseArray(&ECtx);
+   }
+   UsefulBufC Encoded;
+   if(QCBOREncode_Finish(&ECtx, &Encoded)) {
+      nReturn = -1;
+   }
+
+   return(nReturn);
+}
+
+
+
+int ArrayNestingTest2()
+{
+   QCBOREncodeContext ECtx;
+   int i;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   for(i = QCBOR_MAX_ARRAY_NESTING+1; i; i--) {
+      QCBOREncode_OpenArray(&ECtx);
+   }
+   for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
+      QCBOREncode_CloseArray(&ECtx);
+   }
+
+   UsefulBufC Encoded;
+   if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
+      nReturn = -1;
+   }
+
+   return(nReturn);
+}
+
+
+
+int ArrayNestingTest3()
+{
+   QCBOREncodeContext ECtx;
+   int i;
+   int nReturn = 0;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
+      QCBOREncode_OpenArray(&ECtx);
+   }
+   for(i = QCBOR_MAX_ARRAY_NESTING+1 ; i; i--) {
+      QCBOREncode_CloseArray(&ECtx);
+   }
+   UsefulBufC Encoded;
+   if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_TOO_MANY_CLOSES) {
+      nReturn = -1;
+   }
+
+   return(nReturn);
+}
+
+
+/*
+ 81             # array(1)
+ 81          # array(1)
+ 81       # array(1)
+ 81    # array(1)
+ 80 # array(0)
+*/
+static const uint8_t spFiveArrarys[] = {0x81, 0x81, 0x81, 0x81, 0x80};
+
+// Validated at http://cbor.me and by manually examining its output
+/*
+ 82                        # array(2)
+ 81                     # array(1)
+ 81                  # array(1)
+ 81               # array(1)
+ 81            # array(1)
+ 80         # array(0)
+ 98 2F                  # array(47)
+ 3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807)
+ 3B 0000000100000000 # negative(4294967296)
+ 3A FFFFFFFF         # negative(4294967295)
+ 3A FFFFFFFE         # negative(4294967294)
+ 3A FFFFFFFD         # negative(4294967293)
+ 3A 7FFFFFFF         # negative(2147483647)
+ 3A 7FFFFFFE         # negative(2147483646)
+ 3A 00010001         # negative(65537)
+ 3A 00010000         # negative(65536)
+ 39 FFFF             # negative(65535)
+ 39 FFFE             # negative(65534)
+ 39 FFFD             # negative(65533)
+ 39 0100             # negative(256)
+ 38 FF               # negative(255)
+ 38 FE               # negative(254)
+ 38 FD               # negative(253)
+ 38 18               # negative(24)
+ 37                  # negative(23)
+ 36                  # negative(22)
+ 20                  # negative(0)
+ 00                  # unsigned(0)
+ 00                  # unsigned(0)
+ 01                  # unsigned(1)
+ 16                  # unsigned(22)
+ 17                  # unsigned(23)
+ 18 18               # unsigned(24)
+ 18 19               # unsigned(25)
+ 18 1A               # unsigned(26)
+ 18 FE               # unsigned(254)
+ 18 FF               # unsigned(255)
+ 19 0100             # unsigned(256)
+ 19 0101             # unsigned(257)
+ 19 FFFE             # unsigned(65534)
+ 19 FFFF             # unsigned(65535)
+ 1A 00010000         # unsigned(65536)
+ 1A 00010001         # unsigned(65537)
+ 1A 00010002         # unsigned(65538)
+ 1A 7FFFFFFF         # unsigned(2147483647)
+ 1A 7FFFFFFF         # unsigned(2147483647)
+ 1A 80000000         # unsigned(2147483648)
+ 1A 80000001         # unsigned(2147483649)
+ 1A FFFFFFFE         # unsigned(4294967294)
+ 1A FFFFFFFF         # unsigned(4294967295)
+ 1B 0000000100000000 # unsigned(4294967296)
+ 1B 0000000100000001 # unsigned(4294967297)
+ 1B 7FFFFFFFFFFFFFFF # unsigned(9223372036854775807)
+ 1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615)
+ */
+static const uint8_t spEncodeRawExpected[] = {
+   0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x98, 0x2f,
+   0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+   0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, 0xff, 0x3a,
+   0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, 0xff, 0xff,
+   0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, 0x3a, 0x7f,
+   0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, 0x00, 0x01,
+   0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, 0xff, 0xff,
+   0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, 0x39, 0x01,
+   0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, 0xfd, 0x38,
+   0x18, 0x37, 0x36, 0x20, 0x00, 0x00, 0x01, 0x16,
+   0x17, 0x18, 0x18, 0x18, 0x19, 0x18, 0x1a, 0x18,
+   0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, 0x19, 0x01,
+   0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, 0xff, 0x1a,
+   0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x00,
+   0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, 0x1a, 0x7f,
+   0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, 0xff, 0xff,
+   0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, 0x80, 0x00,
+   0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, 0xfe, 0x1a,
+   0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, 0x00, 0x00,
+   0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00,
+   0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1b, 0x7f,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1b,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+
+int EncodeRawTest()
+{
+   QCBOREncodeContext ECtx;
+
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_OpenArray(&ECtx);
+   QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spFiveArrarys));
+   QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts));
+   QCBOREncode_CloseArray(&ECtx);
+
+   UsefulBufC EncodedRawTest;
+
+   if(QCBOREncode_Finish(&ECtx, &EncodedRawTest)) {
+      return -4;
+   }
+
+   if(CheckResults(EncodedRawTest, spEncodeRawExpected)) {
+      return -5;
+   }
+
+   return 0;
+}
+
+/*
+ This returns a pointer to spBigBuf
+ */
+static int CreateMap(uint8_t **pEncoded, size_t *pEncodedLen)
+{
+   QCBOREncodeContext ECtx;
+   int nReturn = -1;
+
+   *pEncoded = NULL;
+   *pEncodedLen = INT32_MAX;
+   size_t uFirstSizeEstimate = 0;
+
+   // loop runs CBOR encoding twice. First with no buffer to
+   // calucate the length so buffer can be allocated correctly,
+   // and last with the buffer to do the actual encoding
+   do {
+      QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen});
+      QCBOREncode_OpenMap(&ECtx);
+      QCBOREncode_AddInt64ToMap(&ECtx, "first integer", 42);
+      QCBOREncode_OpenArrayInMap(&ECtx, "an array of two strings");
+      QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string1", 7}));
+      QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string2", 7}));
+      QCBOREncode_CloseArray(&ECtx);
+      QCBOREncode_OpenMapInMap(&ECtx, "map in a map");
+      QCBOREncode_AddBytesToMap(&ECtx,"bytes 1", ((UsefulBufC) { "xxxx", 4}));
+      QCBOREncode_AddBytesToMap(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4}));
+      QCBOREncode_AddInt64ToMap(&ECtx, "another int", 98);
+      QCBOREncode_AddTextToMap(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30}));
+      QCBOREncode_CloseMap(&ECtx);
+      QCBOREncode_CloseMap(&ECtx);
+
+      if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen))
+         goto Done;
+      if(*pEncoded != NULL) {
+         if(uFirstSizeEstimate != *pEncodedLen) {
+            nReturn = 1;
+         } else {
+            nReturn = 0;
+         }
+         goto Done;
+      }
+      *pEncoded = spBigBuf;
+      uFirstSizeEstimate = *pEncodedLen;
+
+   } while(1);
+
+ Done:
+   return(nReturn);
+}
+
+/*
+ A3                                      # map(3)
+   6D                                   # text(13)
+      666972737420696E7465676572        # "first integer"
+   18 2A                                # unsigned(42)
+   77                                   # text(23)
+      616E206172726179206F662074776F20737472696E6773 # "an array of two strings"
+   82                                   # array(2)
+      67                                # text(7)
+         737472696E6731                 # "string1"
+      67                                # text(7)
+         737472696E6732                 # "string2"
+   6C                                   # text(12)
+      6D617020696E2061206D6170          # "map in a map"
+   A4                                   # map(4)
+      67                                # text(7)
+         62797465732031                 # "bytes 1"
+      44                                # bytes(4)
+         78787878                       # "xxxx"
+      67                                # text(7)
+         62797465732032                 # "bytes 2"
+      44                                # bytes(4)
+         79797979                       # "yyyy"
+      6B                                # text(11)
+         616E6F7468657220696E74         # "another int"
+      18 62                             # unsigned(98)
+      66                                # text(6)
+         746578742032                   # "text 2"
+      78 1E                             # text(30)
+         6C6965732C2064616D6E206C69657320616E642073746174697374696373 # "lies, damn lies and statistics"
+ */
+static const uint8_t spValidMapEncoded[] = {
+   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 } ;
+
+
+int MapEncodeTest()
+{
+   uint8_t *pEncodedMaps;
+   size_t nEncodedMapLen;
+
+   if(CreateMap(&pEncodedMaps, &nEncodedMapLen)) {
+      return -1;
+   }
+
+   int nReturn = 0;
+   if(memcmp(spValidMapEncoded, pEncodedMaps, sizeof(spValidMapEncoded)))
+      nReturn = 2;
+
+   return(nReturn);
+}
+
+
+/*
+ @brief  Encode the RTIC results
+
+ @param[in]     nRResult        CBOR_SIMPLEV_TRUE, CBOR_SIMPLEV_FALSE or CBOR_SIMPLEV_NULL
+ @param[in]     time            Time stamp in UNIX epoch time or 0 for no time stamp
+ @param[in]     szAlexString    Diagnostic code.
+ @param[in[     pOut            Buffer to put the result in
+ @param[in/out] pnLen           Size of pOut buffer when called; length of data output in buffer on return
+
+ @return
+ One of the CBOR encoder errors. QCBOR_SUCCESS, which is has value 0, if no error.
+
+ The size of pOut should be 30 bytes plus the length of pnLen.  If you make it too
+ short an error will be returned. This function will never write off the end
+ of the buffer passed to it.
+
+ If the result is 0, then the correct encoded CBOR is in pOut and *pnLen is the
+ length of the encoded CBOR.
+
+ */
+
+static UsefulBufC FormatRTICResults(int nRResult, uint64_t time, const char *szType, const char *szAlexString, UsefulBuf Storage)
+{
+   // Buffer that the result will be written in to
+   // It is fixed size and small that a stack variable will be fine
+   // QCBOREncode will never write off the end of this buffer. If it won't fit QCBOREncode_Finish will return an error.
+
+   // Context for the encoder
+   QCBOREncodeContext ECtx;
+   QCBOREncode_Init(&ECtx, Storage);
+
+   // All the RTIC results are grouped in a CBOR Map which will get turned into a JSON Object
+   // Contents are label / value pairs
+   QCBOREncode_OpenMap(&ECtx);
+
+   { // Brace / indention just to show CBOR encoding nesting
+
+      // The result: 0 if scan happened and found nothing; 1 if it happened and found something wrong; 2 if it didn't happen
+      QCBOREncode_AddSimpleToMap(&ECtx, "integrity", nRResult);
+
+      // Add the diagnostic code
+      QCBOREncode_AddSZStringToMap(&ECtx, "type", szType);
+
+      // Add a time stamp
+      if(time) {
+         QCBOREncode_AddDateEpochToMap(&ECtx, "time", time);
+      }
+
+      // Add the diagnostic code
+      QCBOREncode_AddSZStringToMap(&ECtx, "diag", szAlexString);
+
+      // Open a subordinate map for telemtry data
+      QCBOREncode_OpenMapInMap(&ECtx, "telemetry");
+
+      { // Brace / indention just to show CBOR encoding nesting
+
+         // Add a few fake integers and buffers for now.
+         QCBOREncode_AddInt64ToMap(&ECtx, "Shoe Size", 12);
+
+         // Add a few fake integers and buffers for now.
+         QCBOREncode_AddInt64ToMap(&ECtx, "IQ", 0xffffffff);
+
+         // Add a few fake integers and buffers for now.
+         static const uint8_t pPV[] = {0x66, 0x67, 0x00, 0x56, 0xaa, 0xbb, 0x01, 0x01};
+         const UsefulBufC WSPV = {pPV, sizeof(pPV)};
+
+         QCBOREncode_AddBytesToMap(&ECtx, "WhaleSharkPatternVector", WSPV);
+      }
+   }
+
+   // Close the telemetry map
+   QCBOREncode_CloseMap(&ECtx);
+
+   // Close the map
+   QCBOREncode_CloseMap(&ECtx);
+
+   UsefulBufC Result;
+
+   QCBOREncode_Finish(&ECtx, &Result);
+
+   return Result;
+}
+
+
+/*
+ A5                                      # map(5)
+   69                                   # text(9)
+      696E74656772697479                # "integrity"
+   F4                                   # primitive(20)
+   64                                   # text(4)
+      74797065                          # "type"
+   66                                   # text(6)
+      726563656E74                      # "recent"
+   64                                   # text(4)
+      74696D65                          # "time"
+   C1                                   # tag(1)
+      1A 580D4172                       # unsigned(1477263730)
+   64                                   # text(4)
+      64696167                          # "diag"
+   6A                                   # text(10)
+      30784131654335303031              # "0xA1eC5001"
+   69                                   # text(9)
+      74656C656D65747279                # "telemetry"
+   A3                                   # map(3)
+      69                                # text(9)
+         53686F652053697A65             # "Shoe Size"
+      0C                                # unsigned(12)
+      62                                # text(2)
+         4951                           # "IQ"
+      1A FFFFFFFF                       # unsigned(4294967295)
+      77                                # text(23)
+         5768616C65536861726B5061747465726E566563746F72 # "WhaleSharkPatternVector"
+      48                                # bytes(8)
+         66670056AABB0101               # "fg\x00V\xAA\xBB\x01\x01"
+ */
+static const uint8_t spExpectedRTIC[] = {
+   0xa5, 0x69, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x69, 0x74,
+   0x79, 0xf4, 0x64, 0x74, 0x79, 0x70, 0x65, 0x66, 0x72, 0x65,
+   0x63, 0x65, 0x6e, 0x74, 0x64, 0x74, 0x69, 0x6d, 0x65, 0xc1,
+   0x1a, 0x58, 0x0d, 0x41, 0x72, 0x64, 0x64, 0x69, 0x61, 0x67,
+   0x6a, 0x30, 0x78, 0x41, 0x31, 0x65, 0x43, 0x35, 0x30, 0x30,
+   0x31, 0x69, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72,
+   0x79, 0xa3, 0x69, 0x53, 0x68, 0x6f, 0x65, 0x20, 0x53, 0x69,
+   0x7a, 0x65, 0x0c, 0x62, 0x49, 0x51, 0x1a, 0xff, 0xff, 0xff,
+   0xff, 0x77, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x53, 0x68, 0x61,
+   0x72, 0x6b, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x56,
+   0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x66, 0x67, 0x00, 0x56,
+   0xaa, 0xbb, 0x01, 0x01};
+
+
+int RTICResultsTest()
+{
+   const UsefulBufC Encoded = FormatRTICResults(CBOR_SIMPLEV_FALSE, 1477263730,
+                                          "recent", "0xA1eC5001",
+                                          UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   if(UsefulBuf_IsNULLC(Encoded)) {
+      return -1;
+   }
+
+   if(CheckResults(Encoded, spExpectedRTIC)) {
+      return -2;
+   }
+
+   return 0;
+}
+
+
+/*
+ 82           # array(2)
+   19 01C3   # unsigned(451)
+   43        # bytes(3)
+      1901D2 # "\x19\x01\xD2"
+*/
+static const uint8_t spExpectedBstrWrap[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2};
+
+/*
+ Very basic bstr wrapping test
+ */
+int BstrWrapTest()
+{
+   QCBOREncodeContext EC;
+
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddUInt64(&EC, 451);
+
+   QCBOREncode_BstrWrap(&EC);
+   QCBOREncode_AddUInt64(&EC, 466);
+
+   UsefulBufC Wrapped;
+   QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+
+   QCBOREncode_CloseArray(&EC);
+
+   UsefulBufC Encoded;
+   if(QCBOREncode_Finish(&EC, &Encoded)) {
+      return -1;
+   }
+
+   if(CheckResults(Encoded, spExpectedBstrWrap)) {
+      return -2;
+   }
+
+   /* Another test; see about handling length calculation */
+   QCBOREncode_Init(&EC, (UsefulBuf){NULL, INT32_MAX});
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_BstrWrap(&EC);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddNULL(&EC);
+   QCBOREncode_CloseArray(&EC);
+   UsefulBufC BStr;
+   QCBOREncode_CloseBstrWrap(&EC, &BStr);
+   // 2 is one byte for an array of length 1 and 1 byte for a NULL
+   if(BStr.ptr != NULL || BStr.len != 2) {
+      return -5;
+   }
+
+   return 0;
+}
+
+
+
+int BstrWrapErrorTest()
+{
+   // -------------- Test closing a bstrwrap when it is an array that is open -----------
+   QCBOREncodeContext EC;
+
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddUInt64(&EC, 451);
+
+   QCBOREncode_BstrWrap(&EC);
+   QCBOREncode_AddUInt64(&EC, 466);
+   QCBOREncode_OpenArray(&EC);
+
+   UsefulBufC Wrapped;
+   QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+
+   QCBOREncode_CloseArray(&EC);
+
+   UsefulBufC Encoded2;
+   if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_CLOSE_MISMATCH) {
+      return -1;
+   }
+
+   // ----------- test closing a bstrwrap when nothing is open ---------------------
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+   if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_TOO_MANY_CLOSES) {
+      return -2;
+   }
+
+   // --------------- test nesting too deep ----------------------------------
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   for(int i = 1; i < 18; i++) {
+      QCBOREncode_BstrWrap(&EC);
+   }
+   QCBOREncode_AddBool(&EC, true);
+
+   for(int i = 1; i < 18; i++) {
+      QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
+   }
+
+   if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
+      return -3;
+   }
+
+   return 0;
+}
+
+
+
+// Part of bstr_wrap_nest_test
+/*
+ 83 array with three
+ 53  byte string with 19 bytes
+ 01  #1
+ 50 byte string with 16 bytes
+ 02
+ 4D byte string with 13 bytes
+ 03
+ 4A byte string with 10 bytes
+ 04
+ 47 byte string with 7 bytes
+ 05
+ 44 byte string with 4 bytes
+ 06
+ 41 byte string with 1 byte
+ 07
+ 01
+ 02
+ 03
+ 04
+ 05
+ 06
+ 07
+ A2 map with two items
+ 18 20  label for byte string
+ 54 byte string of length 20
+ 82 Array with two items
+ 10  The integer value 10
+ A2 map with two items
+ 18 21 label for byte string
+ 44 byte string with 4 bytes
+ 81 array with 1 item
+ 11 integer value 11
+ 18 30 integer value 30
+ 18 40 integer label 40
+ 65 68 65 6C 6C 6F text string hello
+ 18 31 integer value 31
+ 18 41 integer label 41
+ 65 68 65 6C 6C 6F text string hello
+
+
+ */
+
+
+/*
+ 83                                      # array(3)
+   56                                   # bytes(22)
+      00530150024D034A0447054406410700010203040506 # "\x00S\x01P\x02M\x03J\x04G\x05D\x06A\a\x00\x01\x02\x03\x04\x05\x06"
+   07                                   # unsigned(7)
+   A2                                   # map(2)
+      18 20                             # unsigned(32)
+      54                                # bytes(20)
+         8210A21821448111183018406568656C6C6F1831 # "\x82\x10\xA2\x18!D\x81\x11\x180\x18@ehello\x181"
+      18 41                             # unsigned(65)
+      65                                # text(5)
+         68656C6C6F                     # "hello"
+ */
+static const uint8_t spExpectedDeepBstr[] =
+{
+   0x83, 0x56, 0x00, 0x53, 0x01, 0x50, 0x02, 0x4D,
+   0x03, 0x4A, 0x04, 0x47, 0x05, 0x44, 0x06, 0x41,
+   0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+   0x07, 0xA2, 0x18, 0x20, 0x54, 0x82, 0x10, 0xA2,
+   0x18, 0x21, 0x44, 0x81, 0x11, 0x18, 0x30, 0x18,
+   0x40, 0x65, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x18,
+   0x31, 0x18, 0x41, 0x65, 0x68, 0x65, 0x6C, 0x6C,
+   0x6F
+};
+
+// Part of bstr_wrap_nest_test
+static int DecodeNextNested(UsefulBufC Wrapped)
+{
+   int nReturn;
+   QCBORDecodeContext DC;
+   QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORItem Item;
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64) {
+      return -12;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn == QCBOR_ERR_HIT_END) {
+      return 0;
+   }
+   if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+      return -13;
+   }
+   nReturn =  DecodeNextNested(Item.val.string);
+   if(nReturn) {
+      return nReturn;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -14;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64) {
+      return -15;
+   }
+
+   if(QCBORDecode_Finish(&DC)) {
+      return -16;
+   }
+
+   return 0;
+}
+
+// Part of bstr_wrap_nest_test
+static int DecodeNextNested2(UsefulBufC Wrapped)
+{
+   int nReturn;
+   QCBORDecodeContext DC;
+   QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORItem Item;
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -12;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64) {
+      return -12;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_MAP) {
+      return 0;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+      return -13;
+   }
+   nReturn =  DecodeNextNested2(Item.val.string);
+   if(nReturn) {
+      return nReturn;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+      return -12;
+   }
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64) {
+      return -12;
+   }
+
+   if(QCBORDecode_Finish(&DC)) {
+      return -16;
+   }
+
+   return 0;
+}
+
+
+int BstrWrapNestTest()
+{
+   QCBOREncodeContext EC;
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   // ---- Make a complicated nested CBOR structure ---
+#define BSTR_TEST_DEPTH 10
+
+   QCBOREncode_OpenArray(&EC);
+
+   for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) {
+      QCBOREncode_BstrWrap(&EC);
+      QCBOREncode_AddUInt64(&EC, i);
+   }
+
+   for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) {
+      QCBOREncode_CloseBstrWrap(&EC, NULL);
+      QCBOREncode_AddUInt64(&EC, i);
+   }
+
+   for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) {
+      QCBOREncode_OpenMap(&EC);
+      QCBOREncode_BstrWrapInMapN(&EC, i+0x20);
+      QCBOREncode_OpenArray(&EC);
+      QCBOREncode_AddUInt64(&EC, i+0x10);
+   }
+
+   for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) {
+      QCBOREncode_CloseArray(&EC);
+      QCBOREncode_AddUInt64(&EC, i+0x30);
+      QCBOREncode_CloseBstrWrap(&EC, NULL);
+      QCBOREncode_AddSZStringToMapN(&EC, i+0x40, "hello");
+      QCBOREncode_CloseMap(&EC);
+   }
+   QCBOREncode_CloseArray(&EC);
+
+   UsefulBufC Encoded;
+   if(QCBOREncode_Finish(&EC, &Encoded)) {
+      return -1;
+   }
+
+   // ---Compare it to expected. Expected was hand checked with use of CBOR playground ----
+   if(UsefulBuf_Compare(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedDeepBstr), Encoded)) {
+      return -25;
+   }
+
+
+   // ---- Decode it and see if it is OK ------
+   QCBORDecodeContext DC;
+   QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
+
+   QCBORItem Item;
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
+      return -2;
+   }
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+      return -3;
+   }
+
+   int nReturn = DecodeNextNested(Item.val.string);
+   if(nReturn) {
+      return nReturn;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_INT64) {
+      return -12;
+   }
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 2) {
+      return -2;
+   }
+
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+      return -3;
+   }
+   nReturn = DecodeNextNested2(Item.val.string);
+   if(nReturn) {
+      return nReturn;
+   }
+
+   nReturn = QCBORDecode_GetNext(&DC, &Item);
+   if(nReturn) {
+      return -11;
+   }
+   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+      return -12;
+   }
+
+   if(QCBORDecode_Finish(&DC)) {
+      return -16;
+   }
+
+   return 0;
+}
+
+
+static const uint8_t spSignature[] = {
+   0x8e, 0xb3, 0x3e, 0x4c, 0xa3, 0x1d, 0x1c, 0x46, 0x5a, 0xb0,
+   0x5a, 0xac, 0x34, 0xcc, 0x6b, 0x23, 0xd5, 0x8f, 0xef, 0x5c,
+   0x08, 0x31, 0x06, 0xc4, 0xd2, 0x5a, 0x91, 0xae, 0xf0, 0xb0,
+   0x11, 0x7e, 0x2a, 0xf9, 0xa2, 0x91, 0xaa, 0x32, 0xe1, 0x4a,
+   0xb8, 0x34, 0xdc, 0x56, 0xed, 0x2a, 0x22, 0x34, 0x44, 0x54,
+   0x7e, 0x01, 0xf1, 0x1d, 0x3b, 0x09, 0x16, 0xe5, 0xa4, 0xc3,
+   0x45, 0xca, 0xcb, 0x36};
+
+/*
+ D2                                      # tag(18)
+   84                                   # array(4)
+      43                                # bytes(3)
+         A10126                         # "\xA1\x01&"
+      A1                                # map(1)
+         04                             # unsigned(4)
+         42                             # bytes(2)
+            3131                        # "11"
+      54                                # bytes(20)
+         546869732069732074686520636F6E74656E742E # "This is the content."
+      58 40                             # bytes(64)
+         8EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36 # "\x8E\xB3>L\xA3\x1D\x1CFZ\xB0Z\xAC4\xCCk#\xD5\x8F\xEF\\\b1\x06\xC4\xD2Z\x91\xAE\xF0\xB0\x11~*\xF9\xA2\x91\xAA2\xE1J\xB84\xDCV\xED*\"4DT~\x01\xF1\x1D;\t\x16\xE5\xA4\xC3E\xCA\xCB6"
+ */
+static const uint8_t spExpected[] = {
+   0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31,
+   0x31, 0x54, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+   0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E,
+   0x74, 0x2E, 0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D,
+   0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC, 0x6B, 0x23,
+   0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31, 0x06, 0xC4, 0xD2, 0x5A,
+   0x91, 0xAE, 0xF0, 0xB0, 0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91,
+   0xAA, 0x32, 0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A,
+   0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D, 0x3B, 0x09,
+   0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA, 0xCB, 0x36};
+
+/*
+ this corresponds exactly to the example in RFC 8152
+ section C.2.1. This doesn't actually verify the signature
+ though that would be nice as it would make the test
+ really good. That would require bring in ECDSA crypto
+ to this test.
+ */
+int CoseSign1TBSTest()
+{
+   // All of this is from RFC 8152 C.2.1
+   const char *szKid = "11";
+   const UsefulBufC Kid = UsefulBuf_FromSZ(szKid);
+   const char *szPayload = "This is the content.";
+   const UsefulBufC Payload = UsefulBuf_FromSZ(szPayload);
+   static const uint8_t pProtectedHeaders[] = {0xa1, 0x01, 0x26};
+   const UsefulBufC ProtectedHeaders = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pProtectedHeaders);
+
+   // It would be good to compare this to the output from
+   // a COSE implementation like COSE-C. It has been checked
+   // against the CBOR playground.
+   const UsefulBufC Signature = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSignature);
+
+   QCBOREncodeContext EC;
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   // top level array for cose sign1, 18 is the tag for COSE sign
+   QCBOREncode_AddTag(&EC, CBOR_TAG_COSE_SIGN1);
+   QCBOREncode_OpenArray(&EC);
+
+   // Add protected headers
+   QCBOREncode_AddBytes(&EC, ProtectedHeaders);
+
+   // Empty map with unprotected headers
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddBytesToMapN(&EC, 4, Kid);
+   QCBOREncode_CloseMap(&EC);
+
+   // The payload
+   UsefulBufC WrappedPayload;
+   QCBOREncode_BstrWrap(&EC);
+   QCBOREncode_AddEncoded(&EC, Payload); // Payload is not actually CBOR in example C.2.1
+   QCBOREncode_CloseBstrWrap(&EC, &WrappedPayload);
+
+   // Check we got back the actual payload expected
+   if(UsefulBuf_Compare(WrappedPayload, Payload)) {
+      return -1;
+   }
+
+   // The signature
+   QCBOREncode_AddBytes(&EC, Signature);
+   QCBOREncode_CloseArray(&EC);
+
+   // Finish and check the results
+   UsefulBufC COSE_Sign1;
+   if(QCBOREncode_Finish(&EC, &COSE_Sign1)) {
+      return -2;
+   }
+
+   // 98 is the size from RFC 8152 C.2.1
+   if(COSE_Sign1.len != 98) {
+      return -3;
+   }
+
+   if(CheckResults(COSE_Sign1, spExpected)) {
+      return -4;
+   }
+
+   return 0;
+}
+
+
+int EncodeErrorTests()
+{
+   QCBOREncodeContext EC;
+
+
+   // ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------
+   // Do all of these tests with NULL buffers so no actual large allocations are neccesary
+   UsefulBuf Buffer = (UsefulBuf){NULL, UINT32_MAX};
+
+   // First verify no error from a big buffer
+   QCBOREncode_Init(&EC, Buffer);
+   QCBOREncode_OpenArray(&EC);
+   // 6 is the CBOR overhead for opening the array and encodng the length
+   // This exactly fills the buffer.
+   QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, UINT32_MAX-6});
+   QCBOREncode_CloseArray(&EC);
+   size_t xx;
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) {
+      return -1;
+   }
+
+   // Second verify error from an array in encoded output too large
+   QCBOREncode_Init(&EC, Buffer);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, UINT32_MAX-6});
+   QCBOREncode_OpenArray(&EC); // Where QCBOR internally encounters and records error
+   QCBOREncode_CloseArray(&EC);
+   QCBOREncode_CloseArray(&EC);
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_BUFFER_TOO_LARGE) {
+      return -2;
+   }
+
+   // Third, fit an array in exactly at max position allowed
+   QCBOREncode_Init(&EC, Buffer);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, QCBOR_MAX_ARRAY_OFFSET-6});
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_CloseArray(&EC);
+   QCBOREncode_CloseArray(&EC);
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) {
+      return -10;
+   }
+
+
+   // ----- QCBOR_ERR_BUFFER_TOO_SMALL --------------
+   // Work close to the 4GB size limit for a better test
+   const uint32_t uLargeSize =  UINT32_MAX - 1024;
+   UsefulBuf Large = (UsefulBuf){NULL,uLargeSize};
+
+   QCBOREncode_Init(&EC, Large);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2 + 1});
+   QCBOREncode_CloseArray(&EC);
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) {
+      // Making sure it succeeds when it should first
+      return -3;
+   }
+
+   QCBOREncode_Init(&EC, Large);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2 + 1});
+   QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2});
+   QCBOREncode_CloseArray(&EC);
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_BUFFER_TOO_SMALL) {
+      // Now just 1 byte over, see that it fails
+      return -4;
+   }
+
+
+   // ----- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -------
+   QCBOREncode_Init(&EC, Large);
+   for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) {
+      QCBOREncode_OpenArray(&EC);
+   }
+   for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) {
+      QCBOREncode_CloseArray(&EC);
+   }
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) {
+      // Making sure it succeeds when it should first
+      return -5;
+   }
+
+   QCBOREncode_Init(&EC, Large);
+   for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) {
+      QCBOREncode_OpenArray(&EC);
+   }
+   for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) {
+      QCBOREncode_CloseArray(&EC);
+   }
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
+      // One more level to cause error
+      return -6;
+   }
+
+
+   // ------ QCBOR_ERR_TOO_MANY_CLOSES --------
+   QCBOREncode_Init(&EC, Large);
+   for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) {
+      QCBOREncode_OpenArray(&EC);
+   }
+   for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) {
+      QCBOREncode_CloseArray(&EC);
+   }
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_TOO_MANY_CLOSES) {
+      // One more level to cause error
+      return -7;
+   }
+
+
+   // ------ QCBOR_ERR_CLOSE_MISMATCH --------
+   QCBOREncode_Init(&EC, Large);
+   QCBOREncode_OpenArray(&EC);
+   UsefulBufC Wrap;
+   QCBOREncode_CloseBstrWrap(&EC, &Wrap);
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_CLOSE_MISMATCH) {
+      return -8;
+   }
+
+
+   // ------ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN ---------
+   QCBOREncode_Init(&EC, Large);
+   for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) {
+      QCBOREncode_OpenArray(&EC);
+   }
+   for(int i = QCBOR_MAX_ARRAY_NESTING-1; i > 0; i--) {
+      QCBOREncode_CloseArray(&EC);
+   }
+   if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+      // One more level to cause error
+      return -9;
+   }
+
+   /* QCBOR_ERR_ARRAY_TOO_LONG is not tested here as
+    it would require a 64KB of RAM to test */
+
+   return 0;
+}
+
diff --git a/lib/ext/qcbor/test/qcbor_encode_tests.h b/lib/ext/qcbor/test/qcbor_encode_tests.h
new file mode 100644
index 0000000..33703d8
--- /dev/null
+++ b/lib/ext/qcbor/test/qcbor_encode_tests.h
@@ -0,0 +1,145 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors, nor the name "Laurence Lundblade" may be used to
+      endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#ifndef __QCBOR__qcbor_encode_tests__
+#define __QCBOR__qcbor_encode_tests__
+
+#include "qcbor.h"
+
+
+/*
+ Notes:
+
+ - All the functions in qcbor.h are called once in the aggregation of all the tests below.
+
+ - All the types that are supported are given as input and parsed by these tests
+
+ - There is some hostile input such as invalid lengths and CBOR too complex
+   and types this parser doesn't handle
+
+ */
+
+
+/*
+ Most basic test.
+ */
+int BasicEncodeTest(void);
+
+
+/*
+ Encode lots of integer values, particularly around the boundary and make sure they
+ Match the expected binary output. Primarily an encoding test.
+ */
+int IntegerValuesTest1(void);
+
+
+
+/*
+ Create nested arrays to the max depth allowed and make sure it succeeds.
+ This is an encoding test.
+ */
+int ArrayNestingTest1(void);
+
+
+/*
+ Create nested arrays to one more than the meax depth and make sure it fails.
+ This is an encoding test.
+ */
+int ArrayNestingTest2(void);
+
+
+/*
+ Encoding test.
+ Create arrays to max depth and close one extra time and look for correct error code
+ */
+int ArrayNestingTest3(void);
+
+
+/*
+ This tests the QCBOREncode_AddRaw() function by adding two chunks or RAWCBOR to an
+ array and comparing with expected values. This is an encoding test.
+ */
+int EncodeRawTest(void);
+
+
+/*
+ This creates a somewhat complicated CBOR MAP and verifies it against expected
+ data. This is an encoding test.
+ */
+int MapEncodeTest(void);
+
+
+
+/*
+ Encodes a goodly number of floats and doubles and checks encoding is right
+ */
+int FloatValuesTest1(void);
+
+
+/*
+ Encodes true, false and the like
+ */
+int SimpleValuesTest1(void);
+
+
+/*
+ Encodes most data formats that are supported */
+int EncodeDateTest(void);
+
+
+/*
+ Encodes particular data structure that a particular app will need...
+ */
+int RTICResultsTest(void);
+
+
+/*
+ Calls all public encode methods in qcbor.h once.
+ */
+int AllAddMethodsTest(void);
+
+/*
+ The binary string wrapping of maps and arrays used by COSE
+ */
+int  BstrWrapTest(void);
+
+int BstrWrapErrorTest(void);
+
+int BstrWrapNestTest(void);
+
+int CoseSign1TBSTest(void);
+
+int EncodeErrorTests(void);
+
+
+
+#endif /* defined(__QCBOR__qcbor_encode_tests__) */
diff --git a/lib/ext/qcbor/test/run_tests.c b/lib/ext/qcbor/test/run_tests.c
new file mode 100644
index 0000000..6e35620
--- /dev/null
+++ b/lib/ext/qcbor/test/run_tests.c
@@ -0,0 +1,285 @@
+/*==============================================================================
+ run_tests.c -- test aggregator and results reporting
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 9/30/18
+ ==============================================================================*/
+
+#include "run_tests.h"
+#include "UsefulBuf.h"
+#include <stdbool.h>
+
+#include "float_tests.h"
+#include "qcbor_decode_tests.h"
+#include "qcbor_encode_tests.h"
+#include "UsefulBuf_Tests.h"
+
+
+
+// Used to test RunTests
+int fail_test()
+{
+    return -44;
+}
+
+
+
+
+/*
+ Convert a number up to 999999999 to a string. This is so sprintf doesn't
+ have to be linked in so as to minimized dependencies even in test code.
+  */
+const char *NumToString(int32_t nNum, UsefulBuf StringMem)
+{
+    const int32_t nMax = 1000000000;
+
+    UsefulOutBuf OutBuf;
+    UsefulOutBuf_Init(&OutBuf, StringMem);
+
+    if(nNum < 0) {
+        UsefulOutBuf_AppendByte(&OutBuf, '-');
+        nNum = -nNum;
+    }
+    if(nNum > nMax-1) {
+        return "XXX";
+    }
+
+    bool bDidSomeOutput = false;
+    for(int n = nMax; n > 0; n/=10) {
+        int x = nNum/n;
+        if(x || bDidSomeOutput){
+            bDidSomeOutput = true;
+            UsefulOutBuf_AppendByte(&OutBuf, '0' + x);
+            nNum -= x * n;
+        }
+    }
+    if(!bDidSomeOutput){
+        UsefulOutBuf_AppendByte(&OutBuf, '0');
+    }
+    UsefulOutBuf_AppendByte(&OutBuf, '\0');
+
+    return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr;
+}
+
+
+
+
+typedef int (test_fun_t)(void);
+typedef const char * (test_fun2_t)(void);
+
+
+#define TEST_ENTRY(test_name)  {#test_name, test_name, true}
+#define TEST_ENTRY_DISABLED(test_name)  {#test_name, test_name, false}
+
+typedef struct {
+    const char  *szTestName;
+    test_fun_t  *test_fun;
+    bool         bEnabled;
+} test_entry;
+
+typedef struct {
+    const char *szTestName;
+    test_fun2_t  *test_fun;
+    bool         bEnabled;
+} test_entry2;
+
+test_entry2 s_tests2[] = {
+    TEST_ENTRY(UBUTest_CopyUtil),
+    TEST_ENTRY(UOBTest_NonAdversarial),
+    TEST_ENTRY(TestBasicSanity),
+    TEST_ENTRY(UOBTest_BoundaryConditionsTest),
+    TEST_ENTRY(UBMacroConversionsTest),
+    TEST_ENTRY(UBUtilTests),
+    TEST_ENTRY(UIBTest_IntegerFormat)
+};
+
+
+test_entry s_tests[] = {
+    TEST_ENTRY(ParseMapAsArrayTest),
+    TEST_ENTRY_DISABLED(AllocAllStringsTest),
+    TEST_ENTRY(IndefiniteLengthNestTest),
+    TEST_ENTRY(NestedMapTestIndefLen),
+    TEST_ENTRY(ParseSimpleTest),
+    TEST_ENTRY(EncodeRawTest),
+    TEST_ENTRY(RTICResultsTest),
+    TEST_ENTRY(MapEncodeTest),
+    TEST_ENTRY(ArrayNestingTest1),
+    TEST_ENTRY(ArrayNestingTest2),
+    TEST_ENTRY(ArrayNestingTest3),
+    TEST_ENTRY(EncodeDateTest),
+    TEST_ENTRY(SimpleValuesTest1),
+    TEST_ENTRY(IntegerValuesTest1),
+    TEST_ENTRY(AllAddMethodsTest),
+    TEST_ENTRY(ParseTooDeepArrayTest),
+    TEST_ENTRY(ComprehensiveInputTest),
+    TEST_ENTRY(ParseMapTest),
+    TEST_ENTRY_DISABLED(IndefiniteLengthArrayMapTest),
+    TEST_ENTRY(BasicEncodeTest),
+    TEST_ENTRY(NestedMapTest),
+    TEST_ENTRY(BignumParseTest),
+    TEST_ENTRY(OptTagParseTest),
+    TEST_ENTRY(DateParseTest),
+    TEST_ENTRY(ShortBufferParseTest2),
+    TEST_ENTRY(ShortBufferParseTest),
+    TEST_ENTRY(ParseDeepArrayTest),
+    TEST_ENTRY(SimpleArrayTest),
+    TEST_ENTRY(IntegerValuesParseTest),
+    TEST_ENTRY_DISABLED(MemPoolTest),
+    TEST_ENTRY_DISABLED(IndefiniteLengthStringTest),
+    TEST_ENTRY(HalfPrecisionDecodeBasicTests),
+    TEST_ENTRY(DoubleAsSmallestTest),
+    TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest),
+    TEST_ENTRY(BstrWrapTest),
+    TEST_ENTRY(BstrWrapErrorTest),
+    TEST_ENTRY(BstrWrapNestTest),
+    TEST_ENTRY(CoseSign1TBSTest),
+    TEST_ENTRY(StringDecoderModeFailTest),
+    TEST_ENTRY_DISABLED(BigComprehensiveInputTest),
+    TEST_ENTRY(EncodeErrorTests),
+    //TEST_ENTRY(fail_test),
+};
+
+
+int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx, int *pNumTestsRun)
+{
+    int nTestsFailed = 0;
+    int nTestsRun = 0;
+    UsefulBuf_MAKE_STACK_UB(StringStorage, 5);
+
+    test_entry2 *t2;
+    const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2);
+
+    for(t2 = s_tests2; t2 < s_tests2_end; t2++) {
+        if(szTestNames[0]) {
+            // Some tests have been named
+            const char **szRequestedNames;
+            for(szRequestedNames = szTestNames; *szRequestedNames;  szRequestedNames++) {
+                if(!strcmp(t2->szTestName, *szRequestedNames)) {
+                    break; // Name matched
+                }
+            }
+            if(*szRequestedNames == NULL) {
+                // Didn't match this test
+                continue;
+            }
+        } else {
+            // no tests named, but don't run "disabled" tests
+            if(!t2->bEnabled) {
+                // Don't run disabled tests when all tests are being run
+                // as indicated by no specific test names being given
+                continue;
+            }
+        }
+
+        const char * szTestResult = (t2->test_fun)();
+        nTestsRun++;
+        if(pfOutput) {
+            (*pfOutput)(t2->szTestName, poutCtx, 0);
+        }
+
+        if(szTestResult) {
+            if(pfOutput) {
+                (*pfOutput)(" FAILED (returned ", poutCtx, 0);
+                (*pfOutput)(szTestResult, poutCtx, 0);
+                (*pfOutput)(")", poutCtx, 1);
+            }
+            nTestsFailed++;
+        } else {
+            if(pfOutput) {
+                (*pfOutput)( " PASSED", poutCtx, 1);
+            }
+        }
+    }
+
+
+    test_entry *t;
+    const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry);
+
+    for(t = s_tests; t < s_tests_end; t++) {
+        if(szTestNames[0]) {
+            // Some tests have been named
+            const char **szRequestedNames;
+            for(szRequestedNames = szTestNames; *szRequestedNames;  szRequestedNames++) {
+                if(!strcmp(t->szTestName, *szRequestedNames)) {
+                    break; // Name matched
+                }
+            }
+            if(*szRequestedNames == NULL) {
+                // Didn't match this test
+                continue;
+            }
+        } else {
+            // no tests named, but don't run "disabled" tests
+            if(!t->bEnabled) {
+                // Don't run disabled tests when all tests are being run
+                // as indicated by no specific test names being given
+                continue;
+            }
+        }
+
+        int nTestResult = (t->test_fun)();
+        nTestsRun++;
+        if(pfOutput) {
+            (*pfOutput)(t->szTestName, poutCtx, 0);
+        }
+
+        if(nTestResult) {
+            if(pfOutput) {
+                (*pfOutput)(" FAILED (returned ", poutCtx, 0);
+                (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx, 0);
+                (*pfOutput)(")", poutCtx, 1);
+            }
+            nTestsFailed++;
+        } else {
+            if(pfOutput) {
+                (*pfOutput)( " PASSED", poutCtx, 1);
+            }
+        }
+    }
+
+    if(pNumTestsRun) {
+        *pNumTestsRun = nTestsRun;
+    }
+
+    if(pfOutput) {
+        (*pfOutput)( "SUMMARY: ", poutCtx, 0);
+        (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx, 0);
+        (*pfOutput)( " tests run; ", poutCtx, 0);
+        (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx, 0);
+        (*pfOutput)( " tests failed", poutCtx, 1);
+    }
+
+    return nTestsFailed;
+}
+
+
+
+
+static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutput, void *pOutCtx)
+{
+   UsefulBuf_MAKE_STACK_UB(buffer, 20);
+
+   (*pfOutput)(szWhat, pOutCtx, 0);
+   (*pfOutput)(" ", pOutCtx, 0);
+   (*pfOutput)(NumToString(uSize, buffer), pOutCtx, 0);
+   (*pfOutput)("", pOutCtx, 1);
+}
+
+void PrintSizes(OutputStringCB pfOutput, void *pOutCtx)
+{
+   // Type and size of return from sizeof() varies. These will never be large so cast is safe
+   PrintSize("sizeof(QCBORTrackNesting)",   (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBOREncodeContext)",  (uint32_t)sizeof(QCBOREncodeContext), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBORDecodeNesting)",  (uint32_t)sizeof(QCBORDecodeNesting), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBORDecodeContext)",  (uint32_t)sizeof(QCBORDecodeContext), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBORItem)",           (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBORStringAllocator)",(uint32_t)sizeof(QCBORStringAllocator), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBORTagListIn)",      (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx);
+   PrintSize("sizeof(QCBORTagListOut)",     (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx);
+   (*pfOutput)("", pOutCtx, 1);
+}
diff --git a/lib/ext/qcbor/test/run_tests.h b/lib/ext/qcbor/test/run_tests.h
new file mode 100644
index 0000000..734d4f8
--- /dev/null
+++ b/lib/ext/qcbor/test/run_tests.h
@@ -0,0 +1,66 @@
+/*==============================================================================
+ run_tests.h -- test aggregator and results reporting
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created 9/30/18
+ ==============================================================================*/
+
+/**
+ @file run_tests.h
+*/
+
+/**
+ @brief Type for function to output a text string
+
+ @param[in] szString   The string to output
+ @param[in] pOutCtx    A context pointer; NULL if not needed
+ @param[in] bNewline   If non-zero, output a newline after the string
+
+ This is a prototype of a function to be passed to RunTests() to
+ output text strings.
+
+ This can be implemented with stdio (if available) using a straight
+ call to fputs() where the FILE * is passed as the pOutCtx as shown in
+ the example code below.  This code is for Linux where the newline is
+ a \\n. Windows usually prefers \\r\\n.
+
+ @code
+    static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine)
+    {
+        fputs(szString, (FILE *)pOutCtx);
+        if(bNewLine) {
+            fputs("\n", pOutCtx);
+        }
+     }
+ @endcode
+*/
+typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline);
+
+
+/**
+ @brief Runs the QCBOR tests.
+
+ @param[in]  szTestNames    An argv-style list of test names to run. If
+                            empty, all are run.
+ @param[in]  pfOutput       Function that is called to output text strings.
+ @param[in]  pOutCtx        Context pointer passed to output function.
+ @param[out] pNumTestsRun   Returns the number of tests run. May be NULL.
+
+ @return The number of tests that failed. Zero means overall success.
+ */
+int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *pOutCtx, int *pNumTestsRun);
+
+
+/**
+ @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.
+ */
+void PrintSizes(OutputStringCB pfOutput, void *pOutCtx);
+