Merge latest stuff from master (what is to be v 1.5)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7291e78..f3bedd2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,6 @@
 #-------------------------------------------------------------------------------
 # Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+# Copyright (c) 2024, Laurence Lundblade. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -39,6 +40,7 @@
     PRIVATE
         src/ieee754.c
         src/qcbor_decode.c
+        src/qcbor_tag_decode.c
         src/qcbor_encode.c
         src/qcbor_err_to_str.c
         src/UsefulBuf.c
@@ -78,6 +80,7 @@
     inc/qcbor/qcbor_private.h
     inc/qcbor/qcbor_encode.h
     inc/qcbor/qcbor_decode.h
+    inc/qcbor/qcbor_tag_decode.h
     inc/qcbor/qcbor_spiffy_decode.h
     inc/qcbor/UsefulBuf.h
 )
diff --git a/Makefile b/Makefile
index defcb72..d2ec8bf 100644
--- a/Makefile
+++ b/Makefile
@@ -24,11 +24,11 @@
 CFLAGS=$(CMD_LINE) -I inc -I test -Os -fPIC
 
 
-QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o src/qcbor_err_to_str.o
+QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/qcbor_tag_decode.o src/ieee754.o src/qcbor_err_to_str.o
 
 TEST_OBJ=test/UsefulBuf_Tests.o test/qcbor_encode_tests.o \
     test/qcbor_decode_tests.o test/run_tests.o \
-    test/float_tests.o test/half_to_double_from_rfc7049.o example.o ub-example.o
+    test/float_tests.o test/half_to_double_from_rfc7049.o example.o tag-examples.o ub-example.o
 
 .PHONY: all so install uninstall clean warn
 
@@ -58,12 +58,14 @@
 
 src/UsefulBuf.o: inc/qcbor/UsefulBuf.h
 src/qcbor_decode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_decode.h inc/qcbor/qcbor_spiffy_decode.h src/ieee754.h
+src/qcbor_tag_decode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_decode.h inc/qcbor/qcbor_tag_decode.h
 src/qcbor_encode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_encode.h src/ieee754.h
 src/iee754.o: src/ieee754.h
 src/qcbor_err_to_str.o: inc/qcbor/qcbor_common.h
 
 example.o:	$(PUBLIC_INTERFACE)
 ub-example.o:	$(PUBLIC_INTERFACE)
+tag-examples.o:	$(PUBLIC_INTERFACE)
 
 test/run_tests.o: test/UsefulBuf_Tests.h test/float_tests.h test/run_tests.h test/qcbor_encode_tests.h test/qcbor_decode_tests.h inc/qcbor/qcbor_private.h
 test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor/UsefulBuf.h
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index e43bf04..cf51075 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -56,7 +56,14 @@
 		E776E091214AE07500E67947 /* qcbor_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08E214AE07500E67947 /* qcbor_decode.c */; };
 		E776E097214AE0C700E67947 /* cmd_line_main.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E096214AE0C700E67947 /* cmd_line_main.c */; };
 		E7864766252CE63100A0C11B /* qcbor_err_to_str.c in Sources */ = {isa = PBXBuildFile; fileRef = E7864765252CE63100A0C11B /* qcbor_err_to_str.c */; };
+		E7C6D9972CB7D4010034425D /* tag-examples.c in Sources */ = {isa = PBXBuildFile; fileRef = E7C6D9962CB7D4010034425D /* tag-examples.c */; };
 		E7C960B92800A09E00FB537C /* ub-example.c in Sources */ = {isa = PBXBuildFile; fileRef = E7C960B82800A09E00FB537C /* ub-example.c */; };
+		E7CA1F1E2C8C337E0008F454 /* qcbor_tag_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */; };
+		E7CA1F1F2C8C337E0008F454 /* qcbor_tag_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */; };
+		E7CA1F202C8C337E0008F454 /* qcbor_tag_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */; };
+		E7CA1F212C8C337E0008F454 /* qcbor_tag_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */; };
+		E7CA1F222C8C337E0008F454 /* qcbor_tag_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */; };
+		E7CA1F232C8C337E0008F454 /* qcbor_tag_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */; };
 		E7FDBF04256C969D007138A8 /* qcbor_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08C214AE07400E67947 /* qcbor_encode.c */; };
 		E7FDBF05256C969D007138A8 /* ieee754.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B57582161CA690080D658 /* ieee754.c */; };
 		E7FDBF06256C969D007138A8 /* qcbor_err_to_str.c in Sources */ = {isa = PBXBuildFile; fileRef = E7864765252CE63100A0C11B /* qcbor_err_to_str.c */; };
@@ -178,8 +185,13 @@
 		E78C91DF240C90C100F4CECE /* qcbor_common.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_common.h; path = inc/qcbor/qcbor_common.h; sourceTree = "<group>"; tabWidth = 3; };
 		E78C91E0240C90C100F4CECE /* qcbor_private.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_private.h; path = inc/qcbor/qcbor_private.h; sourceTree = "<group>"; tabWidth = 3; };
 		E78C91E1240C90C100F4CECE /* qcbor_encode.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_encode.h; path = inc/qcbor/qcbor_encode.h; sourceTree = "<group>"; tabWidth = 3; };
+		E7A7B60E2B76FB62009102C2 /* Serialization.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = Serialization.md; path = doc/Serialization.md; sourceTree = "<group>"; };
+		E7C6D9952CB7D4010034425D /* tag-examples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "tag-examples.h"; sourceTree = "<group>"; };
+		E7C6D9962CB7D4010034425D /* tag-examples.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "tag-examples.c"; sourceTree = "<group>"; };
 		E7C960B72800A09E00FB537C /* ub-example.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ub-example.h"; sourceTree = "<group>"; };
 		E7C960B82800A09E00FB537C /* ub-example.c */ = {isa = PBXFileReference; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = "ub-example.c"; sourceTree = "<group>"; tabWidth = 3; };
+		E7CA1F152C8ACCAE0008F454 /* qcbor_tag_decode.h */ = {isa = PBXFileReference; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_tag_decode.h; path = inc/qcbor/qcbor_tag_decode.h; sourceTree = "<group>"; tabWidth = 3; };
+		E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_tag_decode.c; path = src/qcbor_tag_decode.c; sourceTree = "<group>"; tabWidth = 3; };
 		E7FDBF16256C969D007138A8 /* QCBOR_Disable_Indef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Indef; sourceTree = BUILT_PRODUCTS_DIR; };
 		E7FDBF2C257A6C1F007138A8 /* QCBOR_Disable_Indef_array */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Indef_array; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
@@ -233,6 +245,8 @@
 		E743D0E024AC51470017899F /* example */ = {
 			isa = PBXGroup;
 			children = (
+				E7C6D9962CB7D4010034425D /* tag-examples.c */,
+				E7C6D9952CB7D4010034425D /* tag-examples.h */,
 				E743D0F224AC54600017899F /* example.h */,
 				E743D0E124AC516D0017899F /* example.c */,
 				E7C960B72800A09E00FB537C /* ub-example.h */,
@@ -246,6 +260,7 @@
 			children = (
 				E776E161214EE19C00E67947 /* README.md */,
 				E743D132251014E60017899F /* Tagging.md */,
+				E7A7B60E2B76FB62009102C2 /* Serialization.md */,
 				E776E096214AE0C700E67947 /* cmd_line_main.c */,
 				E776E092214AE07C00E67947 /* inc */,
 				E776E08B214AE06600E67947 /* src */,
@@ -273,9 +288,10 @@
 			children = (
 				E776E08C214AE07400E67947 /* qcbor_encode.c */,
 				E776E08E214AE07500E67947 /* qcbor_decode.c */,
+				E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */,
 				E776E08D214AE07500E67947 /* UsefulBuf.c */,
-				E73B57582161CA690080D658 /* ieee754.c */,
 				E73B57572161CA680080D658 /* ieee754.h */,
+				E73B57582161CA690080D658 /* ieee754.c */,
 				E7864765252CE63100A0C11B /* qcbor_err_to_str.c */,
 			);
 			name = src;
@@ -288,6 +304,7 @@
 				E74BF411245D6713002CE8E8 /* UsefulBuf.h */,
 				E78C91DF240C90C100F4CECE /* qcbor_common.h */,
 				E78C91DE240C90C100F4CECE /* qcbor_decode.h */,
+				E7CA1F152C8ACCAE0008F454 /* qcbor_tag_decode.h */,
 				E78C91E1240C90C100F4CECE /* qcbor_encode.h */,
 				E78C91E0240C90C100F4CECE /* qcbor_private.h */,
 				E776E094214AE09700E67947 /* UsefulBuf.h */,
@@ -469,6 +486,7 @@
 				E743D10F24DD4EF50017899F /* qcbor_decode.c in Sources */,
 				E743D11024DD4EF50017899F /* float_tests.c in Sources */,
 				E743D11124DD4EF50017899F /* qcbor_decode_tests.c in Sources */,
+				E7CA1F202C8C337E0008F454 /* qcbor_tag_decode.c in Sources */,
 				E743D11224DD4EF50017899F /* UsefulBuf.c in Sources */,
 				E743D11324DD4EF50017899F /* qcbor_encode_tests.c in Sources */,
 				E743D11424DD4EF50017899F /* cmd_line_main.c in Sources */,
@@ -488,6 +506,7 @@
 				E743D12424DE05CC0017899F /* qcbor_decode.c in Sources */,
 				E743D12524DE05CC0017899F /* float_tests.c in Sources */,
 				E743D12624DE05CC0017899F /* qcbor_decode_tests.c in Sources */,
+				E7CA1F212C8C337E0008F454 /* qcbor_tag_decode.c in Sources */,
 				E743D12724DE05CC0017899F /* UsefulBuf.c in Sources */,
 				E743D12824DE05CC0017899F /* qcbor_encode_tests.c in Sources */,
 				E743D12924DE05CC0017899F /* cmd_line_main.c in Sources */,
@@ -507,6 +526,7 @@
 				E772021B23B52C02006E966E /* qcbor_decode.c in Sources */,
 				E772021C23B52C02006E966E /* float_tests.c in Sources */,
 				E772021D23B52C02006E966E /* qcbor_decode_tests.c in Sources */,
+				E7CA1F1F2C8C337E0008F454 /* qcbor_tag_decode.c in Sources */,
 				E772021E23B52C02006E966E /* UsefulBuf.c in Sources */,
 				E772021F23B52C02006E966E /* qcbor_encode_tests.c in Sources */,
 				E772022023B52C02006E966E /* cmd_line_main.c in Sources */,
@@ -520,6 +540,8 @@
 			buildActionMask = 2147483647;
 			files = (
 				E776E08F214AE07500E67947 /* qcbor_encode.c in Sources */,
+				E7C6D9972CB7D4010034425D /* tag-examples.c in Sources */,
+				E7CA1F1E2C8C337E0008F454 /* qcbor_tag_decode.c in Sources */,
 				E73B57592161CA690080D658 /* ieee754.c in Sources */,
 				E7864766252CE63100A0C11B /* qcbor_err_to_str.c in Sources */,
 				E73B575F2161CA7C0080D658 /* half_to_double_from_rfc7049.c in Sources */,
@@ -546,6 +568,7 @@
 				E7FDBF07256C969D007138A8 /* half_to_double_from_rfc7049.c in Sources */,
 				E7FDBF08256C969D007138A8 /* run_tests.c in Sources */,
 				E7FDBF09256C969D007138A8 /* qcbor_decode.c in Sources */,
+				E7CA1F222C8C337E0008F454 /* qcbor_tag_decode.c in Sources */,
 				E7FDBF0A256C969D007138A8 /* float_tests.c in Sources */,
 				E7FDBF0B256C969D007138A8 /* qcbor_decode_tests.c in Sources */,
 				E7FDBF0C256C969D007138A8 /* UsefulBuf.c in Sources */,
@@ -566,6 +589,7 @@
 				E7FDBF1D257A6C1F007138A8 /* half_to_double_from_rfc7049.c in Sources */,
 				E7FDBF1E257A6C1F007138A8 /* run_tests.c in Sources */,
 				E7FDBF1F257A6C1F007138A8 /* qcbor_decode.c in Sources */,
+				E7CA1F232C8C337E0008F454 /* qcbor_tag_decode.c in Sources */,
 				E7FDBF20257A6C1F007138A8 /* float_tests.c in Sources */,
 				E7FDBF21257A6C1F007138A8 /* qcbor_decode_tests.c in Sources */,
 				E7FDBF22257A6C1F007138A8 /* UsefulBuf.c in Sources */,
diff --git a/README.md b/README.md
index 46a2168..805279d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,18 @@
+This is the QCBOR 2.0 branch. It is under development and not ready for use.
+
+The plan for QCBOR 2 is a few larger features:
+  - Map sorting
+  - Full canonical encoding support (CDE)
+  - Improved support for tag handling
+  - Perhaps other features like OID support
+  - Perhaps dCBOR support
+  - Improved test and verification
+  - Improved documentation
+  - Better presence in GitHub
+
+The improved tag handling is one of the largest work items and may change
+backwards compatibility.
+
 ![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true)
 
 **QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that
@@ -323,23 +338,23 @@
 defining this is to remove dependency on floating point hardware and
 libraries.
 
+
 #### #define QCBOR_DISABLE_PREFERRED_FLOAT
 
-This eliminates support for half-precision
-and CBOR preferred serialization by disabling
-QCBOR's shift and mask based implementation of
-half-precision floating-point.
+This eliminates support of:
+- encode/decode of half-precision
+- shortest-form encoding of floats
+- QCBORDecode_GetNumberConvertPrecisely()
 
-With this defined, single and double-precision floating-point
-numbers can still be encoded and decoded. Conversion
-of floating-point to and from integers, big numbers and
-such is also supported. Floating-point dates are still
-supported.
+This saves about 1KB of object code, though much of this can be saved
+by not calling any functions to encode doubles or floats or
+QCBORDecode_GetNumberConvertPrecisely
 
-The primary reason to define this is to save object code.
-Roughly 900 bytes are saved, though about half of this
-can be saved just by not calling any functions that
-encode floating-point numbers.
+With this defined, single and double-precision floating-point numbers
+can still be encoded and decoded. Some conversion of floating-point to
+and from integers, big numbers and such is also supported. Floating-point
+dates are still supported.
+
 
 #### #define USEFULBUF_DISABLE_ALL_FLOAT
 
@@ -485,7 +500,7 @@
 
 QCBOR_DISABLE_NON_INTEGER_LABELS causes any label that doesn't
 fit in an int64_t to result in a QCBOR_ERR_MAP_LABEL_TYPE error.
-This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and 
+This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and
 QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. It is fairly common for CBOR-based
 protocols to use only small integers as labels.
 
diff --git a/cmd_line_main.c b/cmd_line_main.c
index da5d071..ceadef5 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -13,6 +13,7 @@
 #include <stdio.h>
 #include "run_tests.h"
 #include "example.h"
+#include "tag-examples.h"
 #include "ub-example.h"
 
 
@@ -34,6 +35,7 @@
    (void)argc; // Avoid unused parameter error
 
    RunQCborExample();
+   RunTagExamples();
    RunUsefulBufExample();
 
 
diff --git a/doc/Serialization.md b/doc/Serialization.md
new file mode 100644
index 0000000..8637e47
--- /dev/null
+++ b/doc/Serialization.md
@@ -0,0 +1,8 @@
+@file Serialization.md
+
+@anchor Serialization
+
+# Serialization and Determinism
+
+To be filled in...
+
diff --git a/doc/Tagging.md b/doc/Tagging.md
index 9d95382..7cbc95b 100644
--- a/doc/Tagging.md
+++ b/doc/Tagging.md
@@ -118,7 +118,7 @@
 encloses another, the enclosed tag is the content for the enclosing
 tag.
 
-Encoding nested tags is easy with QCBOREncode_AddTag(). Just call it
+Encoding nested tags is easy with QCBOREncode_AddTagNumber(). Just call it
 several times before calling the functions to encode the tag content.
 
 When QCBOR decodes tags it does so by first completely processing the
@@ -231,6 +231,81 @@
 is a registry of data types.
 
 
+
+## Tag Decoding
+
+QCBOR offers two ways to decoding tags.
+
+The first is by registering a call back that can transform the tag into
+a QCBORItem itendified by a new QCBOR Type. It is limited in that
+the decoded data must fit into the 24 bytes of a QCBORItem values. It is
+good for new data types.
+
+The second is by getting tag numbers in the course of decoding. This 
+is more suitable for tags numbers that indicate message types, those
+that alter the decode flow.
+
+QCBOR v2 (when not in v1 compatibility) requires all tags be consumed.
+If they are not consumed by one of the above methods, xxxx error occurs.
+They are never optional (as they were described in RFC 7049) just is
+it is not optional to ignore whether an item is a string rather than
+an integer.
+
+In v2
+
+TODO: make clean this up
+
+When asking for specific tag decode, for example GetDateEpoch()
+
+Tag required
+ - No tag gives error xxxx
+ - The epoch date tag by itself succeeds
+ - The epoch date tag with wrong content gives error yyy
+ - The epoch date tag with additional
+ - The additional have been consumed -- suceeds
+ - The aditional tags have not been consumed -- gives error aaa
+ - Another tag gives --- error zzz
+ 
+ Tag not required
+ - No tags, correct tag content -- success
+ - No tags, incorrect tag content type error yyy
+ - Another tag, not consumed ---  error aaa
+ - Another tag consumed -- success
+ - Another tag consumed and made into another type --- error xxxx
+ 
+ Tag optional
+ - No tags, correct content -- success
+ - No tags, incorrect content -- error yyy
+ - Expected tag -- success
+ - Another tag, consumed -- success
+ - Another tag, not consumed tag content correct -- error, probably aaa
+ - Another tag, consumed and made into another type -- error xxx
+ - Expected tag + another tag, not consumed -- error aaa
+ 
+ 
+ Now fan out for ALLOW_EXTRA --- yuckkkkk
+ 
+ Ignore ALLOW_EXTRA in v2?
+ 
+ Fan out for v1
+ 
+ 
+ 
+ 
+ 0(140) good date tag
+ 50000(140) 
+    interpret as a date with some other tag on it -- must be consumed, so unconsumed tag error
+    intepret this as not a date -- wrong type error
+    subjective depending on whether tag content decoder is installed
+ 1(140) same as above
+ 
+ Tag optional
+
+
+
+
+
+
 ## See Also
 
 See @ref Tags-Overview and @ref Tag-Usage.
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index 0a6e823..1ed558b 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -43,10 +43,17 @@
 
  when         who             what, where, why
  --------     ----            --------------------------------------------------
+ 08/31/2024   llundblade      Add UsefulBufC_NTH_BYTE().
  08/14/2024   llundblade      Add UsefulOutBuf_RetrieveOutputStorage().
  08/13/2024   llundblade      Add UsefulInputBuf_RetrieveUndecodedInput().
+ 8/10/2024    llundblade      Add UsefulBuf_SkipLeading().
  08/08/2024   llundblade      Add UsefulOutBuf_SubString().
  10/05/2024   llundblade      Add Xxx_OffsetToPointer.
+ 28/02/2024   llundblade      Rearrange UsefulOutBuf_Compare().
+ 1/7/2024     llundblade      Add UsefulInputBuf_Compare().
+ 19/11/2023   llundblade      Add UsefulOutBuf_GetOutput().
+ 19/11/2023   llundblade      Add UsefulOutBuf_Swap().
+ 19/11/2023   llundblade      Add UsefulOutBuf_Compare().
  19/12/2022   llundblade      Document that adding empty data is allowed.
  4/11/2022    llundblade      Add GetOutPlace and Advance to UsefulOutBuf.
  9/21/2021    llundbla        Clarify UsefulOutBuf size calculation mode
@@ -491,6 +498,10 @@
 static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
 
 
+/* Get the nth byte from a UsefulBufC. There's no length check! */
+#define UsefulBufC_NTH_BYTE(UBC, n)  (((const uint8_t *)(UBC.ptr))[n])
+
+
 /**
  * @brief Copy one @ref UsefulBuf into another at an offset.
  *
@@ -651,6 +662,17 @@
 
 
 /**
+ * @brief Skip leading bytes of a particular value in a string.
+ *
+ * @param[in] String  The input string. String.ptr must not be @c NULL.
+ * @param[in] uByte  The  byte value.
+ *
+ * @return Substring with leading bytes with value @c uByte removed.
+ */
+UsefulBufC UsefulBuf_SkipLeading(UsefulBufC String, uint8_t uByte);
+
+
+/**
  * @brief Convert a pointer to an offset with bounds checking.
  *
  * @param[in] UB  A UsefulBuf.
@@ -869,7 +891,7 @@
 
 
 /**
- * @brief Initialize and supply the actual output buffer.
+ * @brief Initialize and supply the output buffer.
  *
  * @param[out] pUOutBuf  The @ref UsefulOutBuf to initialize.
  * @param[in] Storage    Buffer to output into.
@@ -1351,7 +1373,7 @@
 
 
 /**
- *  @brief Returns the resulting valid data in a UsefulOutBuf
+ *  @brief Returns the data put into a UsefulOutBuf.
  *
  *  @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
  *
@@ -1369,7 +1391,7 @@
 
 
 /**
- * @brief Copies the valid data into a supplied buffer
+ * @brief Copy out the data put into a UsefulOutBuf.
  *
  * @param[in] pUOutBuf  Pointer to the @ref UsefulOutBuf.
  * @param[out] Dest     The destination buffer to copy into.
@@ -1379,13 +1401,37 @@
  *         state was entered.
  *
  * This is the same as UsefulOutBuf_OutUBuf() except it copies the
- * data to @c Dest.
+ * data to @c Dest rather than returning a pointer.
  */
 UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
 
 
 /**
- * @beief Return a substring of the output data.
+ * @brief Returns data starting at an offset that was put into a UsefulOutBuf.
+ *
+ * @param[in] pUOutBuf  Pointer to the @ref UsefulOutBuf.
+ * @param[in] uOffset    Offset to bytes to return.
+ *
+ * @return NULLUsefulBufC or the bytes at the offset.
+ *
+ * This is the same as UsefulOutBuf_OutUBuf() except a starting offset
+ * maybe specified. It returns the bytes starting at @c uOffset to the
+ * end of what was encoded so far. Calling this with @c uOffset 0 is
+ * equivalent to UsefulOutBuf_OutUBuf().
+ *
+ * If there's nothing at @c uOffset or it is past the in the output
+ * buffer, a \ref NULLUsefulBufC is returned.
+ *
+ * This is typically not needed in typical use. It is used by QCBOR
+ * along with UsefulOutBuf_Compare() and UsefulOutBuf_Swap() for
+ * sorting CBOR maps.
+ */
+UsefulBufC
+UsefulOutBuf_OutUBufOffset(UsefulOutBuf *pUOutBuf, size_t uOffset);
+
+
+/*
+ * @brief Return a substring of the output data.
  *
  * @param[in] pUOutBuf  Pointer to the @ref UsefulOutBuf.
  * @param[in] uStart    Offset of start of substring.
@@ -1414,6 +1460,77 @@
 static UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pUOutBuf);
 
 
+/**
+ * @brief Compare bytes at offsets.
+ *
+ * @param[in] pUOutBuf  Pointer to the @ref UsefulOutBuf.
+ * @param[in] uStart1   Offset of first bytes to compare.
+ * @param[in] uLen1     Length of first bytes to compare.
+ * @param[in] uStart2   Offset of second bytes to compare.
+ * @param[in] uLen2     Length of second bytes to compare.
+ *
+ * @return  0 for equality, positive if uStart1 is lexographically larger,
+ *          negative if uStart2 is lexographically larger.
+ * 
+ * This looks into bytes that have been output at the offsets @c start1
+ * and @c start2. It compares bytes at those two starting points until
+ * they are not equal or @c uLen1 or @c uLen2 is reached. If the
+ * length of the string given is off the end of the output data, the
+ * string will be effectively truncated to the data in the output
+ * buffer for the comparison.
+ *
+ * This returns positive when @c uStart1 lexographically sorts ahead
+ * of @c uStart2 and vice versa.  Zero is returned if the strings
+ * compare equally.
+ *
+ * If lengths are unequal and the first bytes are an exact subset of
+ * the second string, then a positve value will be returned and vice
+ * versa.
+ *
+ * If either start is past the end of data in the output buffer, 0
+ * will be returned. It is the caller's responsibility to make sure
+ * the offsets are not off the end so that a comparison is actually
+ * being made. No data will ever be read off the end of the buffer so
+ * this safe no matter what offsets are passed.
+ *
+ * This is a relatively odd function in that it works on data in the
+ * output buffer. It is employed by QCBOR to sort CBOR-encoded maps
+ * that are in the output buffer.
+ */
+int UsefulOutBuf_Compare(UsefulOutBuf *pUOutBuf,
+                         size_t uStart1, size_t uLen1,
+                         size_t uStart2, size_t uLen2);
+
+/**
+ * @brief Swap two regions of output bytes.
+ *
+ * @param[in] pUOutBuf  Pointer to the @ref UsefulOutBuf.
+ * @param[in] uStartOffset   Offset to start of bytes to be swapped.
+ * @param[in] uPivotOffset   Offset to pivot around which bytes are swapped.
+ * @param[in] uEndOffset       Offset to end of region to be swappe.
+ *
+ * This reaches into bytes that have been output and swaps two
+ * adjacent regions.
+ *
+ * If any of the offsets are outside the range of valid data, no
+ * swapping will be performed. If the start is not the smallest and
+ * the pivot is not in the middle no swapping will be performed.
+ *
+ * The byte at @c uStartOffset will participate in the swapping.  The
+ * byte at @c uEndOffset will not participate in the swapping, only
+ * the byte before it.
+ *
+ * This is a relatively odd function in that it works on data in the
+ * output buffer. It is employed by QCBOR to bubble sort encoded CBOR
+ * maps.
+ */
+void UsefulOutBuf_Swap(UsefulOutBuf *pUOutBuf,
+                       size_t        uStartOffset,
+                       size_t        uPivotOffset,
+                       size_t        uEndOffset);
+
+
+
 
 /**
  * @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf. It is
@@ -1756,8 +1873,7 @@
 static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen);
 
 
-/**
- * @brief  Retrieve the undecoded input buffer.
+/** @brief  Retrieve the undecoded input buffer.
  *
  * @param[in] pUInBuf  Pointer to the @ref UsefulInputBuf.
  *
@@ -1768,6 +1884,36 @@
 static UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pUInBuf);
 
 
+/**
+ * @brief Compare two ranges of bytes somewhere in the input buffer.
+ *
+ * @param[in] pUInBuf   The input buffer.
+ * @param[in] uOffset1  Offset of first range of bytes.
+ * @param[in] uLen1     Length of first range of bytes.
+ * @param[in] uOffset2  Offset of second range of bytes.
+ * @param[in] uLen2     Length of second range of bytes.
+ *
+ * This returns the same as UsefulBuf_Compare().
+ * 
+ * If the offset or the length plus offset or a range extends outside
+ * the input buffer, that range of bytes will be considered greater
+ * than the other string. If both are outside this is considered a
+ * degenerate condition and the first string is considered larger.
+ *
+ * This is a somewhat odd function of UsefulInputBuf as it is not used
+ * for consuming data. QCBOR uses it for map order and duplicate
+ * checking.
+ */
+int
+UsefulInputBuf_Compare(UsefulInputBuf *pUInBuf,
+                       const size_t    uOffset1,
+                       const size_t    uLen1,
+                       const size_t    uOffset2,
+                       const size_t    uLen2);
+
+
+
+
 /*----------------------------------------------------------
  Inline implementations.
  */
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 5b94001..89bfd00 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -33,6 +33,8 @@
 #ifndef qcbor_common_h
 #define qcbor_common_h
 
+//TODO: get rid of  QCBOR_DISABLE_EXP_AND_MANTISSA and uncommon tags
+
 #ifdef __cplusplus
 extern "C" {
 #if 0
@@ -40,7 +42,6 @@
 #endif
 #endif
 
-
 /**
  * @file qcbor_common.h
  *
@@ -57,9 +58,10 @@
  *   - QCBOR 1.1 is indicated by the #define QCBOR_1_1
  *   - QCBOR 1.0 is indicated by the absence of all the above
  */
-#define QCBOR_VERSION_MAJOR 1
-#define QCBOR_VERSION_MINOR 4
-#define QCBOR_VERSION_PATCH 1
+#define QCBOR_VERSION_MAJOR 2
+#define QCBOR_VERSION_MINOR 0
+#define QCBOR_VERSION_PATCH 0
+
 
 
 /**
@@ -121,9 +123,9 @@
 #define CBOR_TAG_DATE_STRING    0
 /** See QCBOREncode_AddTDateEpoch(). */
 #define CBOR_TAG_DATE_EPOCH     1
-/** See QCBOREncode_AddTPositiveBignum(). */
+/** See QCBOREncode_AddTBigNumber(). */
 #define CBOR_TAG_POS_BIGNUM     2
-/** See QCBOREncode_AddTNegativeBignum(). */
+/** See QCBOREncode_AddTBigNumber(). */
 #define CBOR_TAG_NEG_BIGNUM     3
 /** CBOR tag for a two-element array representing a fraction with a
  *  mantissa and base-10 scaling factor. See
@@ -151,13 +153,13 @@
 /** A hint that the following byte string should be encoded in
  *  Base64URL when converting to JSON or similar text-based
  *  representations. Call @c
- *  QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to
+ *  QCBOREncode_AddTagNumber(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to
  *  QCBOREncode_AddBytes(). */
 #define CBOR_TAG_ENC_AS_B64URL 21
 /** A hint that the following byte string should be encoded in Base64
  *  when converting to JSON or similar text-based
  *  representations. Call @c
- *  QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to
+ *  QCBOREncode_AddTagNumber(pCtx,CBOR_TAG_ENC_AS_B64) before the call to
  *  QCBOREncode_AddBytes(). */
 #define CBOR_TAG_ENC_AS_B64    22
 /** A hint that the following byte string should be encoded in base-16
@@ -165,7 +167,7 @@
  *  (https://www.rfc-editor.org/rfc/rfc4648.html) when converting to
  *  JSON or similar text-based representations. Essentially, Base-16
  *  encoding is the standard case- insensitive hex encoding and may be
- *  referred to as "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16)
+ *  referred to as "hex". Call @c QCBOREncode_AddTagNumber(pCtx,CBOR_TAG_ENC_AS_B16)
  *  before the call to QCBOREncode_AddBytes(). */
 #define CBOR_TAG_ENC_AS_B16    23
 /** See QCBORDecode_EnterBstrWrapped()). */
@@ -230,6 +232,9 @@
 /** The 64-bit invalid tag from the CBOR tags registry */
 #define CBOR_TAG_INVALID64 0xffffffffffffffff
 
+/** Allows tag content handler installed by QCBORDecode_InstallTagDecoders to match any tag number */
+#define CBOR_TAG_ANY (CBOR_TAG_INVALID64 - 1)
+
 
 
 
@@ -405,7 +410,7 @@
     *  this error is returned. This error is unrecoverable because the
     *  built-in tag decoding doesn't try to consume the unexpected
     *  type. In previous versions of QCBOR this was considered a
-    *  recoverable error hence @ref QCBOR_ERR_BAD_TAG_CONTENT. Going
+    *  recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going
     *  back further, RFC 7049 use the name "optional tags". That name
     *  is no longer used because "optional" was causing confusion. See
     *  also @ref QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT. */
@@ -521,10 +526,49 @@
     * (to save object code). */
    QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78,
 
+   /** Attempt to output non-preferred, non-CDE or non-dCBOR when not
+    * allowed by mode. See QCBOREncode_SerializationPreferred(),
+    * QCBOREncode_SerializationCDE(),
+    * QCBOREncode_SerializationdCBOR().
+    */
+   QCBOR_ERR_NOT_PREFERRED = 79,
+
+   /** Trying to encode something that is discouraged (e.g., 65-bit
+    * negative integer) without allowing it by calling
+    * QCBOREncode_Allow() */
+   QCBOR_ERR_NOT_ALLOWED = 80,
+
    /** QCBORDecode_EnterBstrWrapped() cannot be used on
-    * indefinite-length strings because they exist in memory pool for
+    * indefinite-length strings because they exist in the memory pool for
     * a @ref QCBORStringAllocate. */
-   QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 79,
+   QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 81,
+
+   /** Decoded CBOR is does not conform to preferred serialization. The CBOR head's argument is not encoded in shortest form, or indefinite lengths are used.*/
+   QCBOR_ERR_PREFERRED_CONFORMANCE = 82,
+
+   /** Decoded CBOR does not conform to CDE. This occurs when a map is not sorted. Other
+    * CDE issues are reported as QCBOR_ERR_PREFERRED_CONFORMANCE. */
+   QCBOR_ERR_CDE_CONFORMANCE = 83,
+
+   /** Decoded CBOR does not conform to dCBOR. Floating point numbers are not reduced to integers.
+    * Other issues are reported as either QCBOR_ERR_CDE_CONFORMANCE or QCBOR_ERR_PREFERRED_CONFORMANCE. */
+   QCBOR_ERR_DCBOR_CONFORMANCE = 84,
+
+   /** A map is unsorted and should be for CDE or dCBOR. */
+   QCBOR_ERR_UNSORTED = 85,
+
+   /** Conformance checking requested, preferred serialization disabled, float in the input. */
+   QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE = 86,
+
+   /* Can't output a negative zero big num */
+   QCBOR_ERR_NO_NEGATIVE_ZERO = 87,
+
+   /** An unconsumed tag number was encountered. */
+   QCBOR_ERR_UNEXPECTED_TAG_NUMBER = 89, // TODO: rid of this in favor of below?
+
+   /** In QCBOR v2, tag numbers must be processed by QCBORDecode_GetNextTagNumber(). 
+    * See @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS. */
+   QCBOR_ERR_UNPROCESSED_TAG_NUMBER = 90,
 
    /** A range of error codes that can be made use of by the
     * caller. QCBOR internally does nothing with these except notice
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 8c7a44c..e120bd2 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -193,10 +193,44 @@
    /** See QCBORDecode_Init() */
    QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
    /** See QCBORDecode_Init() */
-   QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
+   QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2,
+   /**
+    * This checks that the input is encoded with preferred
+    * serialization. The checking is performed as each item is
+    * decoded. If no QCBORDecode_GetXxx() is called for an item,
+    * there's no check on that item. Preferred serialization was first
+    * defined in section 4.1 of RFC 8949, but is more sharply in
+    * draft-ietf-cbor-cde. Summarizing, the requirements are: the use
+    * of definite-length encoding only, integers, including string
+    * lengths and tags, must be in shortest form, and floating-point
+    * numbers must be reduced to shortest form all the way to
+    * half-precision. */
+   QCBOR_DECODE_MODE_PREFERRED = 3,
+
+   /** This checks that maps in the input are sorted by label as
+    * described in RFC 8949 section 4.2.1.  This also performs
+    * duplicate label checking.  This mode adds considerable CPU-time
+    * expense to decoding, though it is probably only of consequence
+    * for large inputs on slow CPUs.
+    *
+    * This also performs all the checks that
+    * QCBOR_DECODE_MODE_PREFERRED does. */
+   QCBOR_DECODE_MODE_CDE = 4,
+   
+   /** This requires integer-float unification. It performs all the checks that
+    * QCBOR_DECODE_MODE_CDE does. */
+   QCBOR_DECODE_MODE_DCBOR = 5,
+
+   /** Makes QCBOR v2 compatible with v1. The error @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER is not returned.
+    * This can be or'd with the above modes. */
+   QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS = 8,
+
    /* This is stored in uint8_t in places; never add values > 255 */
 } QCBORDecodeMode;
 
+#define QCBOR_DECODE_MODE_MASK 0x07
+
+
 /**
  * The maximum size of input to the decoder. Slightly less than
  * @c UINT32_MAX to make room for some special indicator values.
@@ -220,7 +254,7 @@
 
 /** Type for an integer that decoded either between @c INT64_MIN and
  *  @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member
- *  @c val.int64. */
+ *  @c val.int64. See also \ref QCBOR_TYPE_65BIT_NEG_INT */
 #define QCBOR_TYPE_INT64          2
 
 /** Type for an integer that decoded to a more than @c INT64_MAX and
@@ -242,11 +276,19 @@
 #define QCBOR_TYPE_TEXT_STRING    7
 
 /** Type for a positive big number. Data is in @c val.bignum, a
- *  pointer and a length. */
+ *  pointer and a length. See QCBORDecode_ProcessBigNumber(). */
 #define QCBOR_TYPE_POSBIGNUM      9
 
 /** Type for a negative big number. Data is in @c val.bignum, a
- *  pointer and a length. */
+ *  pointer and a length. Type 1 integers in the range of [-2^64,
+ *  -2^63 - 1] are returned in this type.  1 MUST be subtracted from
+ *  what is returned to get the actual value. This is because of the
+ *  way CBOR negative numbers are represented. QCBOR doesn't do this
+ *  because it can't be done without storage allocation and QCBOR
+ *  avoids storage allocation for the most part.  For example, if 1 is
+ *  subtraced from a negative big number that is the two bytes 0xff
+ *  0xff, the result would be 0x01 0x00 0x00, one byte longer than
+ *  what was received. See QCBORDecode_ProcessBigNumber(). */
 #define QCBOR_TYPE_NEGBIGNUM     10
 
 /** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date
@@ -275,14 +317,23 @@
 
 /** A decimal fraction made of decimal exponent and positive big
  *  number mantissa. See @ref expAndMantissa and
- *  QCBOREncode_AddTDecimalFractionBigNum(). */
+ *  QCBOREncode_AddTDecimalFractionBigMantissa(). */
 #define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15
 
 /** A decimal fraction made of decimal exponent and negative big
  *  number mantissa. See @ref expAndMantissa and
- *  QCBOREncode_AddTDecimalFractionBigNum(). */
+ *  QCBOREncode_AddTDecimalFractionBigMantissa(). */
 #define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16
 
+/** A decimal fraction made of decimal exponent and positive
+ * uint64_t . See QCBOREncode_AddTDecimalFractionBigMantissa(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION_POS_U64    79
+
+/** A decimal fraction made of decimal exponent and negative big
+ *  number mantissa. See @ref expAndMantissa and
+ *  QCBOREncode_AddTDecimalFractionBigMantissa(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64    80
+
 /** A floating-point number made of base-2 exponent and integer
  *  mantissa.  See @ref expAndMantissa and
  *  QCBOREncode_AddTBigFloat(). */
@@ -290,14 +341,26 @@
 
 /** A floating-point number made of base-2 exponent and positive big
  *  number mantissa.  See @ref expAndMantissa and
- *  QCBOREncode_AddTBigFloatBigNum(). */
+ *  QCBOREncode_AddTBigFloatBigMantissa(). */
+// TODO: rename to BIGMANTISSA?
 #define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM         18
 
 /** A floating-point number made of base-2 exponent and negative big
  *  number mantissa.  See @ref expAndMantissa and
- *  QCBOREncode_AddTBigFloatBigNum(). */
+ *  QCBOREncode_AddTBigFloatBigMantissa(). */
 #define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM         19
 
+/** A floating-point number made of base-2 exponent and positive big
+ *  number mantissa.  See @ref expAndMantissa and
+ *  QCBOREncode_AddTBigFloatBigMantissa(). */
+// TODO: rename to U64MANTISSA
+#define QCBOR_TYPE_BIGFLOAT_POS_U64            82
+
+/** A floating-point number made of base-2 exponent and negative big
+ *  number mantissa.  See @ref expAndMantissa and
+ *  QCBOREncode_AddTBigFloatBigMantissa(). */
+#define QCBOR_TYPE_BIGFLOAT_NEG_U64            83
+
 /** Type for the simple value false. */
 #define QCBOR_TYPE_FALSE         20
 
@@ -316,6 +379,15 @@
 /** Type for a double floating-point number. Data is in @c val.dfnum. */
 #define QCBOR_TYPE_DOUBLE        27
 
+/** Special type for integers between -2^63 - 1 to -2^64 that
+ * can't be returned as @ref QCBOR_TYPE_INT64 because they don't fit
+ * in an int64_t. The value is returned in @c val.uint64, but this
+ * isn't the number transmitted. Do this arithmatic (carefully to
+ * avoid over/underflow) to get the value transmitted: - val.uint64 - 1.
+ * See QCBOREncode_AddNegativeUInt64() for a longer explanation
+ * and warning. */
+#define QCBOR_TYPE_65BIT_NEG_INT 28
+
 #define QCBOR_TYPE_BREAK         31 /* Used internally; never returned */
 
 /** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is
@@ -366,15 +438,22 @@
  *  @c val.epochDays */
 #define QCBOR_TYPE_DAYS_EPOCH    78
 
-#define QCBOR_TYPE_TAG          254 /* Used internally; never returned */
+/* 79, 80, 82, 83 is used above for decimal fraction and big float */
 
-#define QCBOR_TYPE_OPTTAG   QCBOR_TYPE_TAG /* Depricated. See QCBOR_TYPE_TAG */
 
+#define QCBOR_TYPE_TAG_NUMBER 127 /* Used internally; never returned */
+
+/** Start of user-defined data types. The range is mainly for user-defined tag content
+ * decoders. See QCBORTagContentCallBack */
+#define QCBOR_TYPE_START_USER_DEFINED 128
+
+/** End of user-defined data types. */
+#define QCBOR_TYPE_END_USER_DEFINED 255
 
 
 /**
  * The largest value in @c utags that is unmapped and can be used without
- * mapping it through QCBORDecode_GetNthTag().
+ * mapping it through QCBORDecode_GetNthTagNumber().
  */
 #define QCBOR_LAST_UNMAPPED_TAG (CBOR_TAG_INVALID16 - QCBOR_NUM_MAPPED_TAGS - 1)
 
@@ -417,6 +496,7 @@
    int64_t nExponent;
    union {
       int64_t    nInt;
+      uint64_t   uInt;
       UsefulBufC bigNum;
    } Mantissa;
 } QCBORExpAndMantissa;
@@ -506,19 +586,20 @@
       /** The value for @c uDataType @ref QCBOR_TYPE_DAYS_EPOCH -- the
        *  number of days before or after Jan 1, 1970. */
       int64_t     epochDays;
-      /** No longer used. Was the value for @ref QCBOR_TYPE_DATE_STRING,
-       * but now that value is in @c string. This will be removed in QCBOR 2.0. */
-      UsefulBufC  dateString;
+
       /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and
        * @ref QCBOR_TYPE_NEGBIGNUM.  */
       UsefulBufC  bigNum;
+
       /** See @ref QCBOR_TYPE_UKNOWN_SIMPLE */
       uint8_t     uSimple;
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
       QCBORExpAndMantissa expAndMantissa;
 #endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
-      uint64_t    uTagV;  /* Used internally during decoding */
+      uint64_t    uTagNumber; /* Used internally during decoding */
 
+      /* For use by user-defined tag content handlers */
+      uint8_t     userDefined[24];
    } val;
 
    /** Union holding the different label types selected based on @c uLabelType */
@@ -536,28 +617,15 @@
 
 #ifndef QCBOR_DISABLE_TAGS
    /**
-    * The tags numbers for which the item is the tag content.  Tags
-    * nest, so index 0 in the array is the tag on the data item
-    * itself, index 1 is the tag that applies to the tag in index
-    * 0. The end of the list is indicated by @ref CBOR_TAG_INVALID16
+    * PRIVATE MEMBER
+    * Use  QCBORDecode_GetNthTagNumber() to retrieve tag numbers on an item.
+    * Also see @ref Tags-Overview.
     *
-    * Tag nesting is uncommon and rarely deep. This implementation
-    * only allows nesting to a depth of @ref QCBOR_MAX_TAGS_PER_ITEM,
-    * usually 4.
-    *
-    * Tag numbers in the array below and equal to @ref
-    * QCBOR_LAST_UNMAPPED_TAG are unmapped and can be used
-    * directly. Tag numbers above this must be translated through
-    * QCBORDecode_GetNthTag().
-    *
-    * See also the large number of functions like
-    * QCBORDecode_GetEpochDate() and QCBORDecode_GetBignum() in
-    * qcbor_spiffy_decode.h for a way to decode tagged types without
-    * having to reference this array. Also see @ref Tags-Overview.
+    * In QCBOR v1 this was named uTags and was in the reverse order.
+    * It wasn't explicitly described as private, but was implicitly private.
     */
-   uint16_t uTags[QCBOR_MAX_TAGS_PER_ITEM];
+   QCBORMappedTagNumbers auTagNumbers;
 #endif
-
 } QCBORItem;
 
 /**
@@ -678,6 +746,7 @@
  * error @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by
  * QCBORDecode_GetNext().
  *
+ * TODO: get rid of QCBOR_DECODE_MODE_MAP_STRINGS_ONLY in v2?
  * In strings-only mode, @ref 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 @ref QCBOR_ERR_MAP_LABEL_TYPE is
@@ -878,33 +947,7 @@
  * array. For indefinite-length arrays, @c QCBORItem.val.uCount
  * is @c UINT16_MAX.
  *
- * All tags defined in RFC 8949 are automatically fully decoded. There
- * are QCBOR_TYPES and members in @ref QCBORItem for them. For
- * example, the tag 9 will show up in the @ref QCBORItem as type
- * @ref QCBOR_TYPE_POSBIGNUM with the value in
- * @c QCBORItem.val.bignum. There is also support for
- * some of the tags in the IANA tag registry.
- *
- * Most tags with a CBOR_TAG_XXX define in qcbor_common.h like @ref
- * CBOR_TAG_DATE_STRING are automaticlly decoded by QCBOR. Those that
- * are defined but not decoded are so noted.
- *
- * Tags that are not decoded by QCBOR will be identified and recorded
- * in @ref QCBORItem. Use QCBORDecode_GetNthTag() to get them. Only
- * @ref QCBOR_MAX_TAGS_PER_ITEM tags are recorded per item and an
- * error is returned if there are more than that.
- *
- * Previous versions of QCBOR handled tags in a more complex way using
- * QCBORDecode_SetCallerConfiguredTagList() and
- * QCBORDecode_GetNextWithTags().  This version is largely compatible, but
- * imposes the limit of @ref QCBOR_MAX_TAGS_PER_ITEM tags per item.
- *
- * See @ref Tags-Overview for a description of how to go about
- * creating custom tags.
- *
- * This tag decoding design is to be open-ended and flexible to be
- * able to handle newly defined tags, while using very little memory,
- * in particular keeping @ref QCBORItem as small as possible.
+ * See extensive discussion in @ref Tag-Decoding.
  *
  * See [Decode Error Overview](#Decode-Errors-Overview).
  *
@@ -1118,32 +1161,103 @@
 QCBORDecode_EndCheck(QCBORDecodeContext *pCtx);
 
 
+#ifndef QCBOR_DISABLE_TAGS
 /**
  * @brief Returns the tag numbers for an item.
  *
  * @param[in] pCtx    The decoder context.
+ * @param[out] puTagNumber  The returned tag number.
+ *
+ * In QCBOR v2, all tag numbers on an item MUST be fetched with this
+ * method. If not, @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER will
+ * occur. This is a major change from QCBORv1. The QCBOR v1 behavior
+ * is too lax for proper CBOR decoding. When a tag number occurs it
+ * indicates the item is a new data type (except for a few tag numbers
+ * that are hints).  Note also that in RFC 7049, tag numbers were
+ * incorrectly characterized as optional implying they could be
+ * ignored.
+ *
+ * In typical item decoding, tag numbers are not used, not present and
+ * not expected. There's no need to call this.
+ *
+ * When the protocol being decoded does use a tag number then this
+ * must be called for the items were the tag numbers occur before the
+ * items themselves are decoded. Making this call prevents the
+ * @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER error, but the caller still has to
+ * check that the tag number is the right one. Probably the tag number
+ * will be used to switch the flow of the decoder.
+ *
+ * It's possible that an item might use the presence/absence of a tag
+ * number to switch the flow of decoding. If there's a possibility of
+ * a tag number then this must be called.
+ *
+ * If this is called and there is no tag number, then this will return
+ * @ref QCBOR_SUCCESS and the tag number returned will be
+ * @ref CBOR_TAG_INVALID64.
+ *
+ * Usually there is only one tag number per item, but CBOR allows
+ * more. That it allows nesting of tags where the content of one tag
+ * is another tag. If there are multiple tag numbers, this must be
+ * called multiple times. This only returns one tag number at a time,
+ * because tag numbers are typically processed one at a time.
+ *
+ * If there is an error decoding the tag or the item it is on, the
+ * error code will be set and the tag number @ref CBOR_TAG_INVALID64
+ * will be returned. That is, @ref CBOR_TAG_INVALID64 will be returned if
+ * there is a decode error or there is no tag number.
+ */
+void
+QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber);
+
+
+/**
+ * @brief Returns the tag numbers for an item.
+ *
+ * @param[in] pCtx    The decoder context.
+ * @param[out] puTagNumber  The returned tag number.
+ *
+ * @return See error table of decoding errors set by QCBORDecode_VGetNext().
+ *
+ * Like QCBORDecode_VGetNextTagNumber(), but returns the
+ * error rather than set last error.
+ */
+QCBORError
+QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber);
+
+
+
+/**
+ * @brief Returns the tag numbers for a decoded item.
+ *
+ * @param[in] pCtx    The decoder context.
  * @param[in] pItem The CBOR item to get the tag for.
  * @param[in] uIndex The index of the tag to get.
  *
- * @returns The nth tag number or CBOR_TAG_INVALID64.
+ * @returns The nth tag number or @ref CBOR_TAG_INVALID64.
+ *
+ * Typically, this is only used with @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS.
+ * Normally, tag numbers are processed QCBORDecode_VGetNextTagNumber() or
+ * QCBORTagContentCallBack.
  *
  * When QCBOR decodes an item that is a tag, it will fully decode tags
  * it is able to. Tags that it is unable to process are put in a list
  * in the QCBORItem.
  *
- * Tags nest. Here the tag with index 0 has the data item as its content. The
- * tag with index 1 has the tag at index 0 has its content and so forth.
+ * Tags nest. Here the tag with index 0 is the outermost, the one
+ * furthest form the data item that is the tag content. This is
+ * the opposite order of QCBORDecode_GetNthTag(), but more
+ * useful.
  *
  * Deep tag nesting is rare so this implementation imposes a limit of
  * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref
  * QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this
- * implementation, not of CBOR. (To be able to handle deeper
- * nesting, the constant can be increased and the library
- * recompiled. It will use more memory).
+ * implementation, not of CBOR. (To be able to handle deeper nesting,
+ * the constant can be increased and the library recompiled. It will
+ * use more memory).
  *
- * See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview.
+ * See also @ref Tag-Decoding @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview.
  *
- * To reduce memory used by a QCBORItem, tag numbers larger than
+ * To reduce memory used by a @ref QCBORItem, tag numbers larger than
  * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be
  * accessed with this function rather than directly.
  *
@@ -1152,7 +1266,7 @@
  * item or no tag at @c uIndex.
  */
 uint64_t
-QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex);
+QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint8_t uIndex);
 
 
 /**
@@ -1161,10 +1275,10 @@
  * @param[in] pCtx    The decoder context.
  * @param[in] uIndex The index of the tag to get.
  *
- * @returns The nth tag number or CBOR_TAG_INVALID64.
+ * @returns The nth tag number or @ref CBOR_TAG_INVALID64.
  *
- * This returns tags of the most recently decoded item.  See
- * QCBORDecode_GetNthTag(). This is particularly of use for spiffy
+ * This returns tags of the most recently decoded item. See
+ * QCBORDecode_GetNthTagNumber(). This is particularly of use for spiffy
  * decode functions that don't return a @ref QCBORItem.
  *
  * This does not work for QCBORDecode_GetNext(),
@@ -1172,12 +1286,14 @@
  * QCBORDecode_VGetNextConsume() but these all return a
  * @ref QCBORItem, so it is not necessary.
  *
- * If a decoding error is set, then this returns CBOR_TAG_INVALID64.
+ * If a decoding error is set, then this returns @ref CBOR_TAG_INVALID64.
  */
 uint64_t
-QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex);
+QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pCtx, uint8_t uIndex);
 
 
+#endif /* ! QCBOR_DISABLE_TAGS */
+
 /**
  * @brief Check that a decode completed successfully.
  *
@@ -1363,6 +1479,93 @@
 QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError);
 
 
+/**
+ * @brief Decode a preferred serialization big number.
+ *
+ * @param[in] Item    The number to process.
+ * @param[in] BigNumberBuf  The buffer to output to.
+ * @param[out] pBigNumber   The resulting big number.
+ * @param[in,out] pbIsNegative  The sign of the resulting big number.
+ *
+ * This exists to process an item that is expected to be a big number
+ * encoded with preferred serialization.  This processing is not part
+ * of the main decoding because of the number of CBOR types it
+ * involves, because it needs a buffer to output to, and to keep code
+ * size of the core decoding small.
+ *
+ * This can also be used to do the subtraction of 1 for negative big
+ * numbers even if preferred serialization of big numbers is not in
+ * use.
+ *
+ * This works on all CBOR type 0 and 1 integers and all tag 2 and 3
+ * big numbers.  In terms of QCBOR types, this works on
+ * \ref QCBOR_TYPE_INT64, \ref QCBOR_TYPE_UINT64,
+ * \ref QCBOR_TYPE_65BIT_NEG, \ref QCBOR_TYPE_POSBIGNUM and
+ * \ref QCBOR_TYPE_NEGBIGNUM. This also works on
+ * \ref QCBOR_TYPE_BYTES in which case pIsNegative
+ * becomes an in parameter indicating the sign.
+ *
+ * This always returns the result as a big number. The integer types 0
+ * and 1 are converted. Leading zeros are removed. The value 0 is
+ * always returned as a one-byte big number with the value 0x00.
+ *
+ * If \c BigNumberBuf is too small, \c pBigNum.ptr will be \c NULL and \c
+ * pBigNum.len reports the required length. The size of \c BigNumberBuf
+ * might have to be one larger than the size of the tag 2 or 3 being
+ * decode because of two cases. In CBOR the value of a tag 3 big
+ * number is -n - 1. The subtraction of one might have a carry.  For
+ * example, an encoded tag 3 that is 0xff, is returned here as 0x01
+ * 0x00.  The other case is a empty tag 2 which is returned as a
+ * one-byte big number with the value 0x00.  (This is the only place
+ * in all of RFC 8949 except for indefinite length strings where the
+ * encoded buffer off the wire can't be returned directly, the only
+ * place some storage allocation is required.)
+ *
+ * This is the decode-side implementation of preferred serialization
+ * of big numbers described in section 3.4.3 of RFC 8949. It
+ * implements the decode-side unification of big numbers and regular
+ * integers.
+ *
+ * This can also be used if you happen to want type 0 and type 1
+ * integers converted to big numbers.
+ *
+ * See also QCBORDecode_ProcessBigNumberNoPreferred().
+ *
+ * If QCBOR is being used in an environment with a full big number
+ * library, it may be better (less object code) to use the big number
+ * library than this, particularly to subtract one for tag 3.
+ *
+ * Finally, the object code for this function is suprisingly large,
+ * almost 1KB. This is due to the number of CBOR data types, and the
+ * big number math required to subtract one and the buffer sizing
+ * issue it brings.
+ */
+QCBORError
+QCBORDecode_ProcessBigNumber(const QCBORItem Item,
+                             UsefulBuf       BigNumberBuf,
+                             UsefulBufC     *pBigNumber,
+                             bool           *pbIsNegative);
+
+
+/**
+ * @brief Decode a big number.
+ *
+ * @param[in] Item    The number to process.
+ * @param[in] BigNumberBuf  The buffer to output to.
+ * @param[out] pBigNumber   The resulting big number.
+ * @param[out] pbIsNegative  The sign of the resulting big number.
+ *
+ * This is the same as QCBORDecode_ProcessBigNumber(), but doesn't
+ * allow type 0 and 1 integers. It only works on tag 2 and 3 big numbers.
+ * The main work this does is handle the offset of 1 for negative big
+ * number decoding.
+ */
+QCBORError
+QCBORDecode_ProcessBigNumberNoPreferred(const QCBORItem Item,
+                                        UsefulBuf       BigNumberBuf,
+                                        UsefulBufC     *pBigNumber,
+                                        bool           *pbIsNegative);
+
 
 
 /**
@@ -1494,6 +1697,7 @@
 
 
 
+
 /* ========================================================================= *
  *    BEGINNING OF DEPRECATED FUNCTIONS                                      *
  *                                                                           *
@@ -1502,120 +1706,67 @@
  * ========================================================================= */
 
 /**
- * Deprecated -- Tag handling has been revised and this is no longer
- * used. See QCBORDecode_GetNthTag() for new tag handling.
- */
-typedef struct {
-   uint8_t         uNumTags;
-   const uint64_t *puTags;
-} QCBORTagListIn;
-
-
-/**
- * Deprecated -- this is retained only for backwards compatibility.
- * Use QCBORDecode_GetNthTag() instead.
+ * TODO: Initialize the CBOR decoder context with QCBOR v1 compatibility (deprecated).
  *
- * This is for QCBORDecode_GetNextWithTags() to be able to return the
- * full list of tags on an item.
+ * @param[in] pCtx         The context to initialize.
  *
- * On input, @c puTags points to a buffer to be filled in and
- * uNumAllocated is the number of @c uint64_t values in the buffer.
+ * This is listed as deprecated even though it is new in QCBOR v2 because
+ * it recommended that v1 mode not be used because the tag number processing
+ * is too loose.
  *
- * On output the buffer contains the tags for the item.  @c uNumUsed
- * tells how many there are.
- */
-typedef struct {
-   uint8_t   uNumUsed;
-   uint8_t   uNumAllocated;
-   uint64_t *puTags;
-} QCBORTagListOut;
-
-
-/**
- * @brief Deprecated -- Configure list of caller-selected tags to be recognized.
+ * This links in a fair bit of object code for all the tag handlers that were
+ * always present in v1. If you don't care about them, use pass XXX to init().
  *
- * @param[in] pCtx       The decode context.
- * @param[out] pTagList  Structure holding the list of tags to configure.
+ * This is the same as QCBORDecode_Init() except it changes the
+ * tag number decoding behavior in two ways:
  *
- * Tag handling has been revised and it is no longer ncessary to use
- * this.  See QCBORDecode_GetNthTag().
+ * First, it sets @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS which
+ * causes no error to be returned when un processed tag numbers are encountered.
+ *
+ * Second, it installs all the same tag handlers that v1 had hardwwired.
+ *    QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
  */
 void
-QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext   *pCtx,
-                                       const QCBORTagListIn *pTagList);
+QCBORDecode_CompatibilityV1(QCBORDecodeContext *pCtx);
 
 
+
+#ifndef QCBOR_DISABLE_TAGS
+
 /**
- * @brief Deprecated -- Determine if a CBOR item is a particular tag.
+ * @brief Returns the tag numbers for an item. (deprecated).
  *
  * @param[in] pCtx    The decoder context.
- * @param[in] pItem   The CBOR item to check.
- * @param[in] uTag    The tag to check, one of @c CBOR_TAG_XXX,
- *                   for example, @ref CBOR_TAG_DATE_STRING.
+ * @param[in] uIndex The index of the tag to get.
  *
- * @return true if it was tagged, false if not.
- *
- * See QCBORDecode_GetNext() for the main description of tag
- * handling. For tags that are not fully decoded a bit corresponding
- * to the tag is set in in @c uTagBits in the @ref QCBORItem. The
- * particular bit depends on an internal mapping table. This function
- * checks for set bits against the mapping table.
- *
- * Typically, a protocol implementation just wants to know if a
- * particular tag is present. That is what this provides. To get the
- * full list of tags on a data item, see
- * QCBORDecode_GetNextWithTags().
- *
- * Also see QCBORDecode_SetCallerConfiguredTagList() for the means to
- * add new tags to the internal list so they can be checked for with
- * this function.
+ * This is the same as QCBORDecode_GetNthTagNumber() but the order is
+ * opposite when there are multiple tags. @c uIndex 0 is the tag
+ * number closest to the tag content. QCBORDecode_GetNthTagNumber() is
+ * more useful for checking the next tag number and switching the
+ * decode flow.
  */
-bool
-QCBORDecode_IsTagged(QCBORDecodeContext *pCtx,
-                     const QCBORItem    *pItem,
-                     uint64_t            uTag);
+uint64_t
+QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex);
 
 
 /**
- * @brief Deprecated -- Gets the next item including full list of tags for item.
+ * @brief Returns the tag numbers for last-decoded item (deprecated).
  *
- * @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. See
- * @ref QCBORTagListOut.
+ * @param[in] pCtx    The decoder context.
+ * @param[in] uIndex The index of the tag to get.
  *
- * @return See return values for QCBORDecode_GetNext().
+ * @returns The nth tag number or CBOR_TAG_INVALID64.
  *
- * @retval QCBOR_ERR_TOO_MANY_TAGS  The size of @c pTagList is too small.
- *
- * This is retained for backwards compatibility. It is replaced by
- * QCBORDecode_GetNthTag() which also returns all the tags that have
- * been decoded.
- *
- * This is not backwards compatibile in two ways. First, it is limited
- * to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was
- * unlimited. Second, it will not inlucde the tags that QCBOR decodes
- * internally.
- *
- * This works the same as QCBORDecode_GetNext() except that it also
- * returns the list of tags for the data item in @c pTagList.
- *
- * The 0th tag returned here is the one furthest from the data
- * item. This is opposite the order for QCBORDecode_GetNthTag().
- *
- * CBOR has no upper bound or limit on the number of tags that can be
- * associated with a data item but in practice the number of tags on
- * an item will usually be small. This will return @ref
- * QCBOR_ERR_TOO_MANY_TAGS if the array in @c pTagList is too small to
- * hold all the tags for the item.
+ * This is the same as QCBORDecode_GetNthTagNumberOfLast() but the
+ * order is opposite when there are multiple tags. @c uIndex 0 is the
+ * tag number closest to the tag content.
+ * QCBORDecode_GetNthTagNumber() is more useful for checking
+ * the next tag number and switching the decode flow.
  */
-QCBORError
-QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx,
-                            QCBORItem          *pDecodedItem,
-                            QCBORTagListOut    *pTagList);
+uint64_t
+QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex);
 
-
+#endif /* ! QCBOR_DISABLE_TAGS */
 /* ========================================================================= *
  *    END OF DEPRECATED FUNCTIONS                                            *
  * ========================================================================= */
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index f725217..79b92ac 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -278,7 +278,7 @@
  * See also @ref CBORTags and @ref Tag-Usage
  *
  * The encoding side of tags not built-in is handled by
- * QCBOREncode_AddTag() and is relatively simple. Tag decoding is more
+ * QCBOREncode_AddTagNumber() and is relatively simple. Tag decoding is more
  * complex and mainly handled by QCBORDecode_GetNext(). Decoding of the
  * structure of tagged data not built-in (if there is any) has to be
  * implemented by the caller.
@@ -360,6 +360,7 @@
  * - Max items in an array or map when encoding or decoding is
  *   @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
  * - Does not directly support labels in maps other than text strings & integers.
+ * - Traversal, duplicate and sort order checking errors out for labels that are arrays or maps.
  * - Does not directly support integer labels beyond whats fits in @c int64_t
  *   or @c uint64_t.
  * - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
@@ -439,7 +440,7 @@
  * is too small, encoding will go into an error state and not write
  * anything further.
  *
- * If allocating on the stack the convenience macro
+ * If allocating on the stack, the convenience macro
  * UsefulBuf_MAKE_STACK_UB() can be used, but its use is not required.
  *
  * Since there is no reallocation or such, the output buffer must be
@@ -472,6 +473,173 @@
 QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage);
 
 
+/* TODO: allow mix-and-match serialization behaviors
+ - Sort maps
+ - Reduce floats to integers
+ - Restrict non-preferred big nums
+ - Restrict indefinite-length strings
+ - Restrict indefinite-length maps and arrays
+ - Restrict simple values
+ - Dup detection
+ - Restrict NaN payload
+
+ Easy to do by changing uMode into a bit map.
+
+ Same for decode conformance check.
+ */
+
+
+/**
+ * @brief Select preferred serialization mode.
+ *
+ * @param[in] pCtx   The encoding context for mode set.
+ *
+ * This resests to the default serialization behaviors, that
+ * allows non-preferred serialization methods to be called,
+ * doesn't sort maps, and doesn't reduce whole-number floats
+ * to integer.
+ */
+static void
+QCBOREncode_SerializationAny(QCBOREncodeContext *pCtx);
+
+
+/**
+ * @brief Select preferred serialization mode.
+ *
+ * @param[in] pCtx   The encoding context for mode set.
+ *
+ * Setting this mode will cause QCBOR to return an error if an attempt
+ * is made to use one of the methods that produce non-preferred
+ * serialization. It doesn't change anything else as QCBOR produces
+ * preferred serialization by default.
+ *
+ * The non-preferred methods are: QCBOREncode_AddFloatNoPreferred(),
+ * QCBOREncode_AddDoubleNoPreferred(),
+ * QCBOREncode_OpenArrayIndefiniteLength(),
+ * QCBOREncode_CloseArrayIndefiniteLength(),
+ * QCBOREncode_OpenMapIndefiniteLength(),
+ * QCBOREncode_CloseMapIndefiniteLength(), plus those derived from the
+ * above listed.
+ *
+ * This mode is just a user guard to prevent accidentally calling
+ * something that produces non-preferred serialization. It doesn't do
+ * anything but causes errors to occur on attempts to call the above
+ * listed functions. This does nothing if the library is compiled
+ * QCBOR_DISABLE_ENCODE_USAGE_GUARDS.
+ *
+ * See @ref Serialization. It is usually not necessary to set this
+ * mode, but there is usually no disadvantage to setting it.  Preferred
+ * Serialization is defined in RFC 8949, section 4.1.
+ */
+static void
+QCBOREncode_SerializationPreferred(QCBOREncodeContext *pCtx);
+
+
+/**
+ * @brief Select CBOR deterministic encoding mode.
+ *
+ * @param[in] pCtx   The encoding context for mode set.
+
+ * This causes QCBOR to produce CBOR Deterministic Encoding (CDE).
+ * With CDE, two distant unrelated CBOR encoders will produce exactly
+ * the same encoded CBOR for a given input.
+ *
+ * In addition to doing everything
+ * QCBOREncode_SerializationPreferred() does (including exclusion of
+ * indefinite lengths), this causes maps to be sorted. The map is
+ * sorted automatically when QCBOREncode_CloseMap() is called.
+ * QCBOREncode_CloseMap() becomes equivalent to
+ * QCBOREncode_CloseAndSortMap().
+ *
+ * Note that linking this function causese about 30% more code from
+ * the QCBOR library to be linked. Also, QCBOREncode_CloseMap() runs
+ * slower, but this is probably only of consequence in very
+ * constrained environments.
+ *
+ * See @ref Serialization. It is usually not necessary to set this
+ * mode as determinism is very rarely needed. However it will
+ * usually work with most protocols. CDE is defined in
+ * draft-ietf-cbor-cde.
+ */
+static void
+QCBOREncode_SerializationCDE(QCBOREncodeContext *pCtx);
+
+
+/**
+ * @brief Select "dCBOR" encoding mode.
+ *
+ * @param[in] pCtx   The encoding context for mode set.
+ *
+ * This is a superset of CDE. This function does everything
+ * QCBOREncode_SerializationCDE() does. Also it is a super set of
+ * preferred serialization and does everything
+ * QCBOREncode_SerializationPreferred() does.
+ *
+ * The main feature of dCBOR is that there is only one way to serialize a
+ * particular numeric value. This changes the behavior of functions
+ * that add floating-point numbers.  If the floating-point number is
+ * whole, it will be encoded as an integer, not a floating-point number.
+ * 0.000 will be encoded as 0x00. Precision is never lost in this
+ * conversion.
+ *
+ * dCBOR also disallows NaN payloads. QCBOR will allow NaN payloads if
+ * you pass a NaN to one of the floating-point encoding functions.
+ * This mode forces all NaNs to the half-precision queit NaN. Also see
+ * QCBOREncode_Allow().
+ *
+ * dCBOR disallows use of any simple type other than true, false and
+ * NULL. In particular it disallows use of "undef" produced by
+ * QCBOREncode_AddUndef().
+ *
+ * See @ref Serialization. Set this mode only if the protocol you are
+ * implementing requires dCBOR. This mode is usually not compatible
+ * with protocols that don't use dCBOR. dCBOR is defined in
+ * draft-mcnally-deterministic-cbor.
+ */
+static void
+QCBOREncode_SerializationdCBOR(QCBOREncodeContext *pCtx);
+
+
+
+
+/** Bit flag to be passed to QCBOREncode_Allow() to allow NaN payloads
+ *  to be output by QCBOREncode_AddDouble(),
+ *  QCBOREncode_AddDoubleNoPreferred(), QCBORENcode_AddFloat() and
+ *  QCBOREncode_AddSingleleNoPreferred. */
+#define QCBOR_ENCODE_ALLOW_NAN_PAYLOAD 0x01
+
+/** Bit flag to be passed to QCBOREncode_Allow() output of less
+ *  interoperable values. See @ref QCBOR_ENCODE_ALLOW_NAN_PAYLOAD */
+#define QCBOR_ENCODE_ALLOW_ALL         0xFF
+
+
+/**
+ * @brief Allow encoding of less-interoperable values.
+ *
+ * @param[in] pCtx    The encoding context.
+ * @param[in] uAllow  Bit flags indicating what to allow.
+ *
+ * There are a few things in the CBOR standard that are often not
+ * supported and are thus not very interoperable.  By default QCBOR
+ * will error if you attempt to output them. This disables that
+ * error.
+ *
+ * See @ref QCBOR_ENCODE_ALLOW_NAN_PAYLOAD and 
+ * @ref QCBOR_ENCODE_ALLOW_65_BIG_NEG.
+ *
+ * This does nothing if the library is compiled
+ * QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+static void
+QCBOREncode_Allow(QCBOREncodeContext *pCtx, uint8_t uAllow);
+
+
+/*
+ * QCBOR_ENCODE_CONFIG_V1_COMPAT
+ */
+static void
+QCBOREncode_Setv1Compatibility(QCBOREncodeContext *pCtx);
+
+
 /**
  * @brief  Add a signed 64-bit integer to the encoded output.
  *
@@ -480,14 +648,14 @@
  *
  * 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
+ * This function figures out the size and the sign and encodes using
+ * CBOR preferred serialization. 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 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
+ * protocols. If integers can be kept between -23 and 23
  * they will be encoded in one byte including the major type.
  *
  * If you pass a smaller integer, like @c int16_t or a small value,
@@ -528,7 +696,7 @@
  * @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 integer is encoded and added to the CBOR output.
  *
  * The only reason so use this function is for integers larger than
  * @c INT64_MAX and smaller than @c UINT64_MAX. Otherwise
@@ -547,6 +715,52 @@
 
 
 /**
+ * @brief Add a negative 64-bit integer to encoded output
+ *
+ * @param[in] pCtx  The encoding context to add the integer to.
+ * @param[in] uNum  The integer to add.
+ *
+ * QCBOREncode_AddInt64() is much better to encode negative integers
+ * than this.  What this can do is add integers with one more
+ * significant bit than an int64_t (a "65-bit" integer if you count
+ * the sign as a bit) which is possible because CBOR happens to
+ * support such integers.
+ *
+ * The actual value encoded is -uNum - 1. That is, give 0 for uNum to
+ * transmit -1, give 1 to transmit -2 and give UINT64_MAX to transmit
+ * -UINT64_MAX-1 (18446744073709551616). The interface is odd like
+ * this so all negative values CBOR can represent can be encoded by
+ * QCBOR (making this a complete CBOR implementation).
+ *
+ * The most negative value QCBOREncode_AddInt64() can encode is
+ * -9223372036854775808 which is -(2^63) or negative 0x800000000000.
+ * This can encode from -9223372036854775809 to -18446744073709551616
+ * or -(2^63 +1)  to -(2^64). Note that it is not possible to represent
+ * positive or negative 18446744073709551616 in any standard C data
+ * type.
+ *
+ * Negative integers are normally decoded in QCBOR with type
+ * @ref QCBOR_TYPE_INT64.  Integers in the range of -9223372036854775809
+ * to -18446744073709551616 are returned as @ref QCBOR_TYPE_65BIT_NEG_INT.
+ *
+ * WARNING: some CBOR decoders will be unable to decode -(2^63 + 1) to
+ * -(2^64).  Also, most CPUs do not have registers that can represent
+ * this range.  If you need 65-bit negative integers, you likely need
+ * negative 66, 67 and 68-bit negative integers so it is likely better
+ * to use CBOR big numbers where you can have any number of bits. See
+ * QCBOREncode_AddTNegativeBignum() and @ref Serialization.
+ */
+static void
+QCBOREncode_AddNegativeUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
+
+static void
+QCBOREncode_AddNegativeUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
+
+static void
+QCBOREncode_AddNegativeUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum);
+
+
+/**
  * @brief  Add a UTF-8 text string to the encoded output.
  *
  * @param[in] pCtx   The encoding context to add the text to.
@@ -619,35 +833,44 @@
  * @param[in] pCtx  The encoding context to add the double to.
  * @param[in] dNum  The double-precision number to add.
  *
- * This encodes and outputs a double-precision floating-point
- * number. CBOR major type 7 is used.
+ * This encodes using preferred serialization, selectively encoding
+ * the input floating-point number as either double-precision,
+ * single-precision or half-precision. Infinity, NaN and 0 are always
+ * encoded as half-precision. The reduction to single-precision or
+ * half-precision is only performed if there is no loss or precision.
  *
- * This implements preferred serialization, selectively encoding the
- * double-precision floating-point number as either double-precision,
- * single-precision or half-precision. Infinity, NaN and zero are
- * always encoded as 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-precision.
+ * Half-precision floating-point numbers take up 2 bytes, half that of
+ * single-precision, one quarter of double-precision. This can reduce
+ * the size of encoded output a lot, especially if the values 0,
+ * infinity and NaN occur frequently.
  *
- * Half-precision floating-point numbers take up two bytes, half that
- * of single-precision, one quarter of double-precision. Preferred
- * serialization can therefore reduce message size down to one quarter
- * of the original if most of the values are zero, infinity or NaN.
+ * QCBOR decoding returns double-precision reversing this reduction.
  *
- * When decoded, QCBOR returns these values as double-precision even
- * if they were encoded as single or half-precision.
- *
- * It is possible to disable preferred serialization when compiling
- * QCBOR. In that case, this operates the same as
- * QCBOREncode_AddDoubleNoPreferred().
+ * Normally this outputs only CBOR major type 7.  If
+ * QCBOREncode_SerializationdCBOR() is called to enter dCBOR mode,
+ * floating-point inputs that are whole integers are further reduced
+ * to CBOR type 0 and 1. This is a unification of the floating-point
+ * and integer number spaces such that there is only one encoding of
+ * any numeric value. Note that this will result in the whole integers
+ * from -(2^63+1) to -(2^64) being encode as CBOR major type 1 which
+ * can't be directly decoded into an int64_t or uint64_t. See
+ * QCBORDecode_GetNumberConvertPrecisely(), a good method to use to
+ * decode dCBOR.
  *
  * Error handling is the same as QCBOREncode_AddInt64().
  *
+ * It is possible that preferred serialization is disabled when the
+ * QCBOR library was built. In that case, this functions the same as
+ * QCBOREncode_AddDoubleNoPreferred().
+ *
  * See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat()
  * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point.
+ *
+ * By default, this will error out on an attempt to encode a NaN with
+ * a payload. See QCBOREncode_Allow() and @ref
+ * QCBOR_ENCODE_ALLOW_NAN_PAYLOAD.
+ * If preferred serialization is disabled at compliation, this check for
+ * for NaN payloads is disabled.
  */
 static void
 QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
@@ -666,8 +889,7 @@
  * @param[in] fNum  The single-precision number to add.
  *
  * This is identical to QCBOREncode_AddDouble() except the input is
- * single-precision. The preferred serialization output will be either
- * single-precision or half-precision.
+ * single-precision. It also supports dCBOR.
  *
  * See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(),
  * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point.
@@ -688,8 +910,8 @@
  * @param[in] pCtx  The encoding context to add the double to.
  * @param[in] dNum  The double-precision number to add.
  *
- * This always outputs the number as a 64-bit double-precision.
- * Preferred serialization is not used.
+ * Output a double-precision float straight-through with no checking or
+ * processing for preferred serialization, dCBOR or other.
  *
  * Error handling is the same as QCBOREncode_AddInt64().
  *
@@ -712,8 +934,8 @@
  * @param[in] pCtx  The encoding context to add the double to.
  * @param[in] fNum  The single-precision number to add.
  *
- * This always outputs the number as a 32-bit single-precision.
- * Preferred serialization is not used.
+ * Output a single-precision float straight-through with no checking or
+ * processing for preferred serializtion, dCBOR or other.
  *
  * Error handling is the same as QCBOREncode_AddInt64().
  *
@@ -755,7 +977,7 @@
  * tags.
  */
 static void
-QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag);
+QCBOREncode_AddTagNumber(QCBOREncodeContext *pCtx, uint64_t uTag);
 
 
 /**
@@ -786,7 +1008,7 @@
  *
  * 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_AddTag() and QCBOREncode_AddDouble().
+ * if you want to by calling QCBOREncode_AddTagNumber() and QCBOREncode_AddDouble().
  *
  * Error handling is the same as QCBOREncode_AddInt64().
  *
@@ -971,53 +1193,124 @@
 
 
 /**
- * @brief Add a positive big number to the encoded output.
+ * @brief Add a big number to encoded output using preferred serialization.
  *
  * @param[in] pCtx             The encoding context.
  * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
  *                             @ref QCBOR_ENCODE_AS_BORROWED.
  * @param[in] BigNumber        Pointer and length of the big number.
  *
- * @c BigNumber makes up an aribtrary precision integer in
- * network/big-endian byte order.  The first byte is the most
- * significant.
+ * @c BigNumber is in network byte order. The most significant byte is
+ * first. There is no limit to the size of @c BigNumber.
  *
- * It is encoded as CBOR major type 2, a binary string, possibly with
- * tag @ref CBOR_TAG_POS_BIGNUM. See [RFC 8949 section 3.4.3]
- * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No
- * processing, such as removal of leading zeros, is perfomed.
+ * This encodes preferred serialization of big numbers as defined in
+ * [RFC 8949 section 3.4.3]
+ * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3).
+ * Positive values less than 2^64 are output as CBOR type 0 integers
+ * rather than as big numbers. Negative values greater than -(2^64)
+ * are output as CBOR type 1 integers. Otherwise the output is as a
+ * CBOR tag 2 or tag 3 big number.
  *
- * Sometimes big numbers are used to represent parts of cryptographic
- * keys, however, COSE which defines representations for keys does,
- * not use this particular type.
+ * This performs the offset of 1 for the encoding of all CBOR negative
+ * numbers. To effect this some big number arithmetic is done and the
+ * byte string output may be one byte shorter than the input. For
+ * example, the negative big number 0x01 0x00 is encoded as 0xff.
+ *
+ * Leading zeros are removed.
+ *
+ * See also QCBOREncode_AddTBigNumberNoPreferred().
+ *
+ * This is fairly complex internally because of support for preferred
+ * serialization and the offset of 1 for CBOR negative values. 
+ *
+ * QCBOREncode_AddTPositiveBignum() and related methods are still
+ * available but are listed as deprecated in favor of this because
+ * this does the full preferred serialization and offest of 1 for
+ * negative numbers.  The methods like
+ * QCBOREncode_AddTPositiveBignum() bring in less object code because
+ * they are mostly pass-through.
  */
-static void
-QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pCtx,
-                               uint8_t             uTagRequirement,
-                               UsefulBufC          BigNumber);
+void
+QCBOREncode_AddTBigNumber(QCBOREncodeContext *pCtx,
+                          uint8_t             uTagRequirement,
+                          bool                bNegative,
+                          UsefulBufC          BigNumber);
 
 static void
-QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx,
-                                      const char         *szLabel,
-                                      uint8_t             uTagRequirement,
-                                      UsefulBufC          BigNumber);
+QCBOREncode_AddTBigNumberToMapSZ(QCBOREncodeContext *pCtx,
+                                 const char         *szLabel,
+                                 uint8_t             uTagRequirement,
+                                 bool                bNegative,
+                                 UsefulBufC          BigNumber);
 
 static void
-QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx,
-                                     int64_t             nLabel,
-                                     uint8_t             uTagRequirement,
-                                     UsefulBufC          BigNumber);
+QCBOREncode_AddTBigNumberToMapN(QCBOREncodeContext *pCtx,
+                                int64_t             nLabel,
+                                uint8_t             uTagRequirement,
+                                bool                bNegative,
+                                UsefulBufC          BigNumber);
 
 
 /**
- * @brief Add a negative big number to the encoded output.
+ * @brief Add a big number to encoded output without preferred serialization.
  *
- * @param[in] pCtx             The encoding context.
+ * @param[in] pCtx             The encoding context to add the UUID to.
  * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
  *                             @ref QCBOR_ENCODE_AS_BORROWED.
- * @param[in] BigNumber            Pointer and length of the big number.
+ * @param[in] bNegative        If true @c BigNumber is negative.
+ * @param[in] BigNumber        The big number.
  *
- * @c BigNumber makes up an aribtrary precision integer in
+ * This is the same as QCBOREncode_AddTBigNumber(), without preferred
+ * serialization. This always outputs tag 2 or 3, never type 0 or 1
+ * integers.
+ *
+ * This removes leading zeros.
+ *
+ * See also QCBOREncode_AddTBigNumber().
+ *
+ * This performs the offset of 1 for encoded CBOR negative so the
+ * internal implementation is still complicated compared to the simple
+ * copy-through in methods like QCBOREncode_AddTPositiveBignum() from
+ * QCBOR v1.
+ */
+void
+QCBOREncode_AddTBigNumberNoPreferred(QCBOREncodeContext *pCtx,
+                                     uint8_t             uTagRequirement,
+                                     bool                bNegative,
+                                     UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddTBigNumberNoPreferredToMapSZ(QCBOREncodeContext *pCtx,
+                                            const char         *szLabel,
+                                            uint8_t             uTagRequirement,
+                                            bool                bNegative,
+                                            UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddTBigNumberNoPreferredToMapN(QCBOREncodeContext *pCtx,
+                                           int64_t             nLabel,
+                                           uint8_t             uTagRequirement,
+                                           bool                bNegative,
+                                           UsefulBufC          BigNumber);
+
+
+/**
+ * @brief Add a big number to encoded output with no processing.
+ *
+ * @param[in] pCtx             The encoding context to add the UUID to.
+ * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
+ *                             @ref QCBOR_ENCODE_AS_BORROWED.
+ * @param[in] bNegative        If true @c BigNumber is negative.
+ * @param[in] BigNumber        The big number.
+ *
+ * This does NOT offset negative numbers by 1 because it
+ * does no processing. For this to encode correctly,
+ * 1 must be subtract from BigNumber before this is called
+ * if bNegative is true.
+ *
+ * See QCBOREncode_AddTBigNumber().
+ *
+ * @c BigNum makes up an aribtrary precision integer in
  * network/big-endian byte order.  The first byte is the most
  * significant.
  *
@@ -1028,26 +1321,30 @@
  * of 1 for negative values, is perfomed.
  */
 static void
-QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx,
-                               uint8_t             uTagRequirement,
-                               UsefulBufC          BigNumber);
+QCBOREncode_AddTBigNumberRaw(QCBOREncodeContext *pCtx,
+                             uint8_t             uTagRequirement,
+                             bool                bNegative,
+                             UsefulBufC          BigNumber);
 
 static void
-QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx,
-                                      const char         *szLabel,
-                                      uint8_t             uTagRequirement,
-                                      UsefulBufC          BigNumber);
+QCBOREncode_AddTBigNumberRawToMapSZ(QCBOREncodeContext *pCtx,
+                                    const char         *szLabel,
+                                    uint8_t             uTagRequirement,
+                                    bool                bNegative,
+                                    UsefulBufC          BigNumber);
 
 static void
-QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx,
-                                     int64_t             nLabel,
-                                     uint8_t             uTagRequirement,
-                                     UsefulBufC          BigNumber);
+QCBOREncode_AddTBigNumberRawToMapN(QCBOREncodeContext *pCtx,
+                                   int64_t             nLabel,
+                                   uint8_t             uTagRequirement,
+                                   bool                bNegative,
+                                   UsefulBufC          BigNumber);
+
 
 
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
 /**
- * @brief Add a decimal fraction to the encoded output.
+ * @brief Add a decimal fraction.
  *
  * @param[in] pCtx             Encoding context to add the decimal fraction to.
  * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
@@ -1077,7 +1374,7 @@
  * CBOR Preferred serialization of the integers is used, thus they
  * will be encoded in the smallest number of bytes possible.
  *
- * See also QCBOREncode_AddTDecimalFractionBigNum() for a decimal
+ * See also QCBOREncode_AddTDecimalFractionBigNumber() for a decimal
  * fraction with arbitrarily large precision and
  * QCBOREncode_AddTBigFloat().
  *
@@ -1107,44 +1404,88 @@
                                       int64_t             nBase10Exponent);
 
 
+
 /**
- * @brief Add a decimal fraction with a big number mantissa to the encoded output.
+ * @brief Add a decimal fraction with a big number mantissa..
  *
  * @param[in] pCtx             Encoding context to add the decimal fraction to.
  * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
  *                             @ref QCBOR_ENCODE_AS_BORROWED.
- * @param[in] Mantissa         The mantissa.
+ * @param[in] Mantissa         The big number mantissa.
  * @param[in] bIsNegative      false if mantissa is positive, true if negative.
  * @param[in] nBase10Exponent  The exponent.
  *
  * This is the same as QCBOREncode_AddTDecimalFraction() except the
- * mantissa is a big number (See QCBOREncode_AddTPositiveBignum())
+ * mantissa is a big number (See QCBOREncode_AddTBignumber())
  * allowing for arbitrarily large precision.
  *
+ * Preferred serialization of the big number is used. This means it may be converted to
+ * a type 0 or type 1 integers making the result the same as QCBOREncode_AddTDecimalFraction().
+ * This also offsets negative big numbers by one.
+ *
+ * If you want the big number to be copied straight through without the conversion to type 0
+ * and 1 integers and without the offset of 1 (and much smaller objet code) use QCBOREncode_AddTBigFloatBigMantissaRaw().
+ *
  * See @ref expAndMantissa for decoded representation.
  */
 static void
-QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx,
-                                      uint8_t             uTagRequirement,
-                                      UsefulBufC          Mantissa,
-                                      bool                bIsNegative,
-                                      int64_t             nBase10Exponent);
+QCBOREncode_AddTDecimalFractionBigMantissa(QCBOREncodeContext *pCtx,
+                                           uint8_t             uTagRequirement,
+                                           UsefulBufC          Mantissa,
+                                           bool                bIsNegative,
+                                           int64_t             nBase10Exponent);
 
 static void
-QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx,
-                                             const char         *szLabel,
-                                             uint8_t             uTagRequirement,
-                                             UsefulBufC          Mantissa,
-                                             bool                bIsNegative,
-                                             int64_t             nBase10Exponent);
+QCBOREncode_AddTDecimalFractionBigMantissaToMapSZ(QCBOREncodeContext *pCtx,
+                                                  const char         *szLabel,
+                                                  uint8_t             uTagRequirement,
+                                                  UsefulBufC          Mantissa,
+                                                  bool                bIsNegative,
+                                                  int64_t             nBase10Exponent);
 
 static void
-QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
-                                            int64_t             nLabel,
-                                            uint8_t             uTagRequirement,
-                                            UsefulBufC          Mantissa,
-                                            bool                bIsNegative,
-                                            int64_t             nBase10Exponent);
+QCBOREncode_AddTDecimalFractionBigMantissaToMapN(QCBOREncodeContext *pCtx,
+                                                 int64_t             nLabel,
+                                                 uint8_t             uTagRequirement,
+                                                 UsefulBufC          Mantissa,
+                                                 bool                bIsNegative,
+                                                 int64_t             nBase10Exponent);
+/**
+ * @brief Add a decimal fraction with a raw big number mantissa.
+ *
+ * @param[in] pCtx             The encoding context to add the bigfloat to.
+ * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
+ *                             @ref QCBOR_ENCODE_AS_BORROWED.
+ * @param[in] Mantissa         The mantissa.
+ * @param[in] bIsNegative      false if mantissa is positive, true if negative.
+ * @param[in] nBase10Exponent   The exponent.
+ *
+ * This is the same as QCBOREncode_AddTDecimalFractionBigMantissa() except the mantissa
+ * is not corrected by one and links in much less object code.
+ */static void
+QCBOREncode_AddTDecimalFractionBigMantissaRaw(QCBOREncodeContext *pCtx,
+                                              uint8_t             uTagRequirement,
+                                              UsefulBufC          Mantissa,
+                                              bool                bIsNegative,
+                                              int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddTDecimalFractionBigMantissaRawToMapSZ(QCBOREncodeContext *pCtx,
+                                                     const char         *szLabel,
+                                                     uint8_t             uTagRequirement,
+                                                     UsefulBufC          Mantissa,
+                                                     bool                bIsNegative,
+                                                     int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddTDecimalFractionBigMantissaRawToMapN(QCBOREncodeContext *pCtx,
+                                                    int64_t             nLabel,
+                                                    uint8_t             uTagRequirement,
+                                                    UsefulBufC          Mantissa,
+                                                    bool                bIsNegative,
+                                                    int64_t             nBase10Exponent);
+
+
 
 /**
  * @brief Add a big floating-point number to the encoded output.
@@ -1164,12 +1505,12 @@
  * which can be 8, 16, 32 or 64 bits. With both the mantissa and
  * exponent 64 bits they can express more precision and a larger range
  * than an IEEE double floating-point number. See
- * QCBOREncode_AddTBigFloatBigNum() for even more precision.
+ * QCBOREncode_AddTBigFloatBigMantissa() for even more precision.
  *
  * For example, 1.5 would be represented by a mantissa of 3 and an
  * exponent of -1.
  *
- * The exponent and mantissa have the range from @c INT64_MIN to
+ * The exponent has a range from @c INT64_MIN to
  * @c INT64_MAX for both encoding and decoding (CBOR allows @c
  * -UINT64_MAX to @c UINT64_MAX, but this implementation doesn't
  * support this range to reduce code size and interface complexity a
@@ -1205,8 +1546,7 @@
 
 
 /**
- * @brief Add a big floating-point number with a big number mantissa to
- *        the encoded output.
+ * @brief Add a big floating-point number with a big number mantissa.
  *
  * @param[in] pCtx             The encoding context to add the bigfloat to.
  * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
@@ -1216,33 +1556,77 @@
  * @param[in] nBase2Exponent   The exponent.
  *
  * This is the same as QCBOREncode_AddTBigFloat() except the mantissa
- * is a big number (See QCBOREncode_AddTPositiveBignum()) allowing for
+ * is a big number (See QCBOREncode_AddTBigMantissa()) allowing for
  * arbitrary precision.
  *
+ *The big number will be offset by 1 if negative and preferred serialization will be used (tag 0 and 1).
+ *
+ * If you want the big number to be copied straight through without the conversion to type 0
+ * and 1 integers and without the offset of 1 (and much smaller objet code) use QCBOREncode_AddTBigFloatBigMantissa().
+ *
  * See @ref expAndMantissa for decoded representation.
  */
 static void
-QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pCtx,
-                               uint8_t             uTagRequirement,
-                               UsefulBufC          Mantissa,
-                               bool                bIsNegative,
-                               int64_t             nBase2Exponent);
+QCBOREncode_AddTBigFloatBigMantissa(QCBOREncodeContext *pCtx,
+                                    uint8_t             uTagRequirement,
+                                    UsefulBufC          Mantissa,
+                                    bool                bIsNegative,
+                                    int64_t             nBase2Exponent);
 
 static void
-QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx,
-                                      const char         *szLabel,
-                                      uint8_t             uTagRequirement,
-                                      UsefulBufC          Mantissa,
-                                      bool                bIsNegative,
-                                      int64_t             nBase2Exponent);
+QCBOREncode_AddTBigFloatBigMantissaToMapSZ(QCBOREncodeContext *pCtx,
+                                           const char         *szLabel,
+                                           uint8_t             uTagRequirement,
+                                           UsefulBufC          Mantissa,
+                                           bool                bIsNegative,
+                                           int64_t             nBase2Exponent);
 
 static void
-QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
-                                     int64_t             nLabel,
-                                     uint8_t             uTagRequirement,
-                                     UsefulBufC          Mantissa,
-                                     bool                bIsNegative,
-                                     int64_t             nBase2Exponent);
+QCBOREncode_AddTBigFloatBigMantissaToMapN(QCBOREncodeContext *pCtx,
+                                          int64_t             nLabel,
+                                          uint8_t             uTagRequirement,
+                                          UsefulBufC          Mantissa,
+                                          bool                bIsNegative,
+                                          int64_t             nBase2Exponent);
+
+
+/**
+ * @brief Add a big floating-point number with a big number mantissa.
+ *
+ * @param[in] pCtx             The encoding context to add the bigfloat to.
+ * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
+ *                             @ref QCBOR_ENCODE_AS_BORROWED.
+ * @param[in] Mantissa         The mantissa.
+ * @param[in] bIsNegative      false if mantissa is positive, true if negative.
+ * @param[in] nBase2Exponent   The exponent.
+ *
+ * This is the same as QCBOREncode_AddTBigFloatBigMantissa() except the mantissa
+ * is not corrected by one and links in much less object code.
+ */
+static void
+QCBOREncode_AddTBigFloatBigMantissaRaw(QCBOREncodeContext *pCtx,
+                                       uint8_t             uTagRequirement,
+                                       UsefulBufC          Mantissa,
+                                       bool                bIsNegative,
+                                       int64_t             nBase2Exponent);
+
+
+static void
+QCBOREncode_AddTBigFloatBigMantissaRawToMapSZ(QCBOREncodeContext *pCtx,
+                                              const char         *szLabel,
+                                              uint8_t             uTagRequirement,
+                                              UsefulBufC          Mantissa,
+                                              bool                bIsNegative,
+                                              int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddTBigFloatBigMantissaRawToMapN(QCBOREncodeContext *pCtx,
+                                             int64_t             nLabel,
+                                             uint8_t             uTagRequirement,
+                                             UsefulBufC          Mantissa,
+                                             bool                bIsNegative,
+                                             int64_t             nBase2Exponent);
+
 
 #endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
 
@@ -1639,7 +2023,7 @@
  * 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 by calling QCBOREncode_AddTag()
+ * An array itself may be tagged by calling QCBOREncode_AddTagNumber()
  * before this call.
  */
 static void
@@ -1810,10 +2194,35 @@
  * This is the same as QCBOREncode_CloseMap(), but the open map that
  * is being close must be of indefinite length.
  */
-static  void
+static void
 QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx);
 
 
+/**
+ * @brief Close and sort an open map.
+ *
+ * @param[in] pCtx The encoding context to close the map in .
+ *
+ * This is the same as QCBOREncode_CloseMap() except it sorts the map
+ * per RFC 8949 Section 4.2.1 and checks for duplicate map keys. This
+ * sort is lexicographic of the CBOR-encoded map labels.
+ *
+ * This is more expensive than most things in the encoder. It uses
+ * bubble sort which runs in n-squared time where @c n is the number
+ * of map items. Sorting large maps on slow CPUs might be slow. This
+ * is also increases the object code size of the encoder by about 30%
+ * (500-1000 bytes).
+ *
+ * Bubble sort was selected so as to not need require configuration of
+ * a buffer to track map item offsets. Bubble sort works well even
+ * though map items are not all the same size because it always swaps
+ * adjacent items.
+ */
+void 
+QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pCtx);
+
+void 
+QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pCtx);
 
 
 /**
@@ -2190,6 +2599,213 @@
                        uint64_t  uNumber);
 
 
+/* ================ Deprecated ============================ */
+
+
+/* Deprecated. Use QCBOREncode_AddTagNumber() instead */
+static void
+QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag);
+
+
+/* Deprecated. Use QCBOREncode_AddTBigNumberRaw() instead */
+static void
+QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pCtx,
+                               uint8_t             uTagRequirement,
+                               UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx,
+                                      const char         *szLabel,
+                                      uint8_t             uTagRequirement,
+                                      UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx,
+                                     int64_t             nLabel,
+                                     uint8_t             uTagRequirement,
+                                     UsefulBufC          BigNumber);
+
+
+/* Deprecated. Use QCBOREncode_AddTBigNumberRaw() instead */
+static void
+QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx,
+                              UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx,
+                                   const char         *szLabel,
+                                   UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx,
+                                    int64_t             nLabel,
+                                    UsefulBufC          BigNumber);
+
+
+/* Deprecated. Use QCBOREncode_AddTBigNumberRaw() instead */
+static void
+QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx,
+                               uint8_t             uTagRequirement,
+                               UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx,
+                                      const char         *szLabel,
+                                      uint8_t             uTagRequirement,
+                                      UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx,
+                                     int64_t             nLabel,
+                                     uint8_t             uTagRequirement,
+                                     UsefulBufC          BigNumber);
+
+
+/* Deprecated. Use QCBOREncode_AddTBigNumberRaw() instead */
+static void
+QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx,
+                              UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx,
+                                   const char         *szLabel,
+                                   UsefulBufC          BigNumber);
+
+static void
+QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx,
+                                    int64_t             nLabel,
+                                    UsefulBufC          BigNumber);
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/* Deprecated. Use QCBOREncode_AddTDecimalFraction() instead */
+static void
+QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
+                               int64_t             nMantissa,
+                               int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
+                                    const char         *szLabel,
+                                    int64_t             nMantissa,
+                                    int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
+                                     int64_t             nLabel,
+                                     int64_t             nMantissa,
+                                     int64_t             nBase10Exponent);
+
+/*  Deprecated. Use QCBOREncode_AddTDecimalFractionBigMantissaRaw() instead */
+static void
+QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx,
+                                      uint8_t             uTagRequirement,
+                                      UsefulBufC          Mantissa,
+                                      bool                bIsNegative,
+                                      int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx,
+                                             const char         *szLabel,
+                                             uint8_t             uTagRequirement,
+                                             UsefulBufC          Mantissa,
+                                             bool                bIsNegative,
+                                             int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
+                                            int64_t             nLabel,
+                                            uint8_t             uTagRequirement,
+                                            UsefulBufC          Mantissa,
+                                            bool                bIsNegative,
+                                            int64_t             nBase10Exponent);
+
+/* Deprecated. Use QCBOREncode_AddTDecimalFractionBigMantissaRaw() instead */
+static void
+QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
+                                     UsefulBufC          Mantissa,
+                                     bool                bIsNegative,
+                                     int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx,
+                                            const char         *szLabel,
+                                            UsefulBufC          Mantissa,
+                                            bool                bIsNegative,
+                                            int64_t             nBase10Exponent);
+
+static void
+QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
+                                           int64_t             nLabel,
+                                           UsefulBufC          Mantissa,
+                                           bool                bIsNegative,
+                                           int64_t             nBase10Exponent);
+
+
+/* Deprecated. Use QCBOREncode_AddTBigFloat() instead. */
+static void
+QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
+                        int64_t             nMantissa,
+                        int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
+                             const char         *szLabel,
+                             int64_t             nMantissa,
+                             int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
+                              int64_t             nLabel,
+                              int64_t             nMantissa,
+                              int64_t             nBase2Exponent);
+
+
+/* Deprecated. Use QCBOREncode_AddTBigFloatBigMantissaRaw() instead */
+static void
+QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pCtx,
+                               uint8_t             uTagRequirement,
+                               UsefulBufC          Mantissa,
+                               bool                bIsNegative,
+                               int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx,
+                                      const char         *szLabel,
+                                      uint8_t             uTagRequirement,
+                                      UsefulBufC          Mantissa,
+                                      bool                bIsNegative,
+                                      int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
+                                     int64_t             nLabel,
+                                     uint8_t             uTagRequirement,
+                                     UsefulBufC          Mantissa,
+                                     bool                bIsNegative,
+                                     int64_t             nBase2Exponent);
+
+/* Deprecated. Use QCBOREncode_AddTBigFloatBigMantissaRaw() instead */
+static void
+QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
+                              UsefulBufC          Mantissa,
+                              bool                bIsNegative,
+                              int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
+                                   const char         *szLabel,
+                                   UsefulBufC          Mantissa,
+                                   bool                bIsNegative,
+                                   int64_t             nBase2Exponent);
+
+static void
+QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
+                                    int64_t             nLabel,
+                                    UsefulBufC          Mantissa,
+                                    bool                bIsNegative,
+                                    int64_t             nBase2Exponent);
+#endif /* ! QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
 
 
 /* ========================================================================= *
@@ -2574,14 +3190,32 @@
 
 /* Semi-private funcion used by public inline functions. See qcbor_encode.c */
 void
-QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pCtx,
-                                   uint64_t            uTag,
-                                   UsefulBufC          BigNumMantissa,
-                                   bool                bBigNumIsNegative,
-                                   int64_t             nMantissa,
-                                   int64_t             nExponent);
+QCBOREncode_Private_AddTExpIntMantissa(QCBOREncodeContext *pMe,
+                                       const int           uTagRequirement,
+                                       const uint64_t      uTagNumber,
+                                       const int64_t       nExponent,
+                                       const int64_t       nMantissa);
 
 
+/* Semi-private funcion used by public inline functions. See qcbor_encode.c */
+void
+QCBOREncode_Private_AddTExpBigMantissa(QCBOREncodeContext *pMe,
+                                       const int           uTagRequirement,
+                                       const uint64_t      uTagNumber,
+                                       const int64_t       nExponent,
+                                       const UsefulBufC    BigNumMantissa,
+                                       const bool          bBigNumIsNegative);
+
+
+/* Semi-private funcion used by public inline functions. See qcbor_encode.c */
+void
+QCBOREncode_Private_AddTExpBigMantissaRaw(QCBOREncodeContext *pMe,
+                                          const int           uTagRequirement,
+                                          const uint64_t      uTagNumber,
+                                          const int64_t       nExponent,
+                                          const UsefulBufC    BigNumMantissa,
+                                          const bool          bBigNumIsNegative);
+
 /**
  * @brief  Semi-private method to add simple items and floating-point.
  *
@@ -2606,50 +3240,61 @@
 }
 
 
-/**
- * @brief Semi-private method to add only the type and length of a byte string.
- *
- * @param[in] pCtx    The context to initialize.
- * @param[in] Bytes   Pointer and length of the input data.
- *
- * This will be removed in QCBOR 2.0. It was never a public function.
- *
- * This is the same as QCBOREncode_AddBytes() except it only adds the
- * CBOR encoding for the type and the length. It doesn't actually add
- * the bytes. You can't actually produce correct CBOR with this and
- * the rest of this API. It is only used for a special case where the
- * valid CBOR is created manually by putting this type and length in
- * and then adding the actual bytes. In particular, when only a hash
- * of the encoded CBOR is needed, where the type and header are hashed
- * separately and then the bytes is hashed. This makes it possible to
- * implement COSE Sign1 with only one copy of the payload in the
- * output buffer, rather than two, roughly cutting memory use in half.
- *
- * This is only used for this odd case, but this is a supported
- * tested function for QCBOR 1.0.
- *
- * See also QCBOREncode_EncodeHead().
- */
-static void
-QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx,
-                            UsefulBufC          Bytes);
-
-static void
-QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx,
-                                 const char         *szLabel,
-                                 UsefulBufC          Bytes);
-
-static void
-QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx,
-                                 int64_t              nLabel,
-                                 UsefulBufC           Bytes);
-
-
 /* Forward declaration */
 static void
 QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString);
 
 
+static inline void
+QCBOREncode_SerializationCDE(QCBOREncodeContext *pMe)
+{
+   /* The use of a function pointer here is a little trick to reduce
+    * code linked for the common use cases that don't sort.  If this
+    * function is never linked, then QCBOREncode_CloseAndSortMap() is
+    * never linked and the amount of code pulled in is small. If the
+    * mode switch between sorting and not sorting were an if
+    * statement, then QCBOREncode_CloseAndSortMap() would always be
+    * linked even when not used. */
+   pMe->pfnCloseMap = QCBOREncode_CloseAndSortMap;
+   pMe->uMode = QCBOR_ENCODE_MODE_CDE;
+}
+
+static inline void
+QCBOREncode_SerializationdCBOR(QCBOREncodeContext *pMe)
+{
+   pMe->pfnCloseMap = QCBOREncode_CloseAndSortMap;
+   pMe->uMode = QCBOR_ENCODE_MODE_DCBOR;
+}
+
+static inline void
+QCBOREncode_SerializationPreferred(QCBOREncodeContext *pMe)
+{
+   pMe->uMode = QCBOR_ENCODE_MODE_PREFERRED;
+}
+
+static inline void
+QCBOREncode_SerializationAny(QCBOREncodeContext *pMe)
+{
+   pMe->uMode = QCBOR_ENCODE_MODE_ANY;
+}
+
+static inline void
+QCBOREncode_Allow(QCBOREncodeContext *pMe, const uint8_t uAllow)
+{
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   pMe->uAllow = uAllow;
+#else
+   (void)uAllow;
+   (void)pMe;
+#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+}
+
+static inline void
+QCBOREncode_Setv1Compatibility(QCBOREncodeContext *pMe)
+{
+   pMe->uConfig = QCBOR_ENCODE_CONFIG_V1_COMPAT;
+}
+
 
 
 static inline void
@@ -2710,6 +3355,27 @@
 
 
 static inline void
+QCBOREncode_AddNegativeUInt64(QCBOREncodeContext *pMe, const uint64_t uValue)
+{
+   QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_NEGATIVE_INT, uValue, 0);
+}
+
+static inline void
+QCBOREncode_AddNegativeUInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, uint64_t uNum)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddNegativeUInt64(pMe, uNum);
+}
+
+static inline void
+QCBOREncode_AddNegativeUInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint64_t uNum)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddNegativeUInt64(pMe, uNum);
+}
+
+
+static inline void
 QCBOREncode_AddText(QCBOREncodeContext *pMe, const UsefulBufC Text)
 {
    QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
@@ -2772,12 +3438,19 @@
 
 
 static inline void
-QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag)
+QCBOREncode_AddTagNumber(QCBOREncodeContext *pMe, const uint64_t uTag)
 {
    QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0);
 }
 
 
+static inline void
+QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag)
+{
+   QCBOREncode_AddTagNumber(pMe, uTag);
+}
+
+
 
 
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
@@ -2927,7 +3600,7 @@
                           const int64_t       nDate)
 {
    if(uTag == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_EPOCH);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_DATE_EPOCH);
    }
    QCBOREncode_AddInt64(pMe, nDate);
 }
@@ -2984,7 +3657,7 @@
                           const int64_t       nDays)
 {
    if(uTag == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_EPOCH);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_DAYS_EPOCH);
    }
    QCBOREncode_AddInt64(pMe, nDays);
 }
@@ -3060,31 +3733,6 @@
 }
 
 
-static inline void
-QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, const UsefulBufC Bytes)
-{
-   QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes.len, 0);
-}
-
-
-static inline void
-QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe,
-                                 const char         *szLabel,
-                                 const UsefulBufC    Bytes)
-{
-    QCBOREncode_AddSZString(pMe, szLabel);
-    QCBOREncode_AddBytesLenOnly(pMe, Bytes);
-}
-
-static inline void
-QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe,
-                                  const int64_t       nLabel,
-                                  const UsefulBufC    Bytes)
-{
-    QCBOREncode_AddInt64(pMe, nLabel);
-    QCBOREncode_AddBytesLenOnly(pMe, Bytes);
-}
-
 
 static inline void
 QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe,
@@ -3092,7 +3740,7 @@
                            const UsefulBufC    Bytes)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_BIN_UUID);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_BIN_UUID);
    }
    QCBOREncode_AddBytes(pMe, Bytes);
 }
@@ -3144,146 +3792,221 @@
 
 
 static inline void
-QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe,
-                               const uint8_t       uTagRequirement,
-                               const UsefulBufC    Bytes)
+QCBOREncode_AddTBigNumberToMapSZ(QCBOREncodeContext *pMe,
+                                 const char         *szLabel,
+                                 uint8_t             uTagRequirement,
+                                 bool                bNegative,
+                                 UsefulBufC          BigNumber)
 {
-   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_POS_BIGNUM);
-   }
-   QCBOREncode_AddBytes(pMe, Bytes);
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTBigNumber(pMe, uTagRequirement, bNegative, BigNumber);
 }
 
 static inline void
+QCBOREncode_AddTBigNumberToMapN(QCBOREncodeContext *pMe,
+                                int64_t             nLabel,
+                                uint8_t             uTagRequirement,
+                                bool                bNegative,
+                                UsefulBufC          BigNumber)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTBigNumber(pMe, uTagRequirement, bNegative, BigNumber);
+}
+
+static inline void
+QCBOREncode_AddTBigNumberNoPreferredToMapSZ(QCBOREncodeContext *pMe,
+                                            const char         *szLabel,
+                                            uint8_t             uTagRequirement,
+                                            bool                bNegative,
+                                            UsefulBufC          BigNumber)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTBigNumberNoPreferred(pMe, uTagRequirement, bNegative, BigNumber);
+}
+
+static inline void
+QCBOREncode_AddTBigNumberNoPreferredToMapN(QCBOREncodeContext *pMe,
+                                           int64_t             nLabel,
+                                           uint8_t             uTagRequirement,
+                                           bool                bNegative,
+                                           UsefulBufC          BigNumber)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTBigNumberNoPreferred(pMe, uTagRequirement, bNegative, BigNumber);
+}
+
+/*
+ * @brief Add the tag number for a big number (private).
+ *
+ * @param[in] pMe  The decode context.
+ * @param[in] uTagRequirement
+ * @param[in] bNegative  If true, big number is negative.
+ */
+static inline void
+QCBOREncode_Private_BigNumberTag(QCBOREncodeContext *pMe,
+                                 const uint8_t       uTagRequirement,
+                                 bool                bNegative)
+{
+   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+      QCBOREncode_AddTag(pMe, bNegative ? CBOR_TAG_NEG_BIGNUM : CBOR_TAG_POS_BIGNUM);
+   }
+}
+
+static inline void
+QCBOREncode_AddTBigNumberRaw(QCBOREncodeContext *pMe,
+                             const uint8_t       uTagRequirement,
+                             bool                bNegative,
+                             const UsefulBufC    BigNumber)
+{
+   QCBOREncode_Private_BigNumberTag(pMe, uTagRequirement, bNegative);
+   QCBOREncode_AddBytes(pMe, BigNumber);
+}
+
+static inline void
+QCBOREncode_AddTBigNumberRawToMapSZ(QCBOREncodeContext *pMe,
+                                    const char         *szLabel,
+                                    const uint8_t       uTagRequirement,
+                                    bool                bNegative,
+                                    const UsefulBufC    BigNumber)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTBigNumberRaw(pMe, uTagRequirement, bNegative, BigNumber);
+}
+
+
+static inline void
+QCBOREncode_AddTBigNumberRawToMapN(QCBOREncodeContext *pMe,
+                                   int64_t             nLabel,
+                                   const uint8_t       uTagRequirement,
+                                   bool                bNegative,
+                                   const UsefulBufC    BigNumber)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTBigNumberRaw(pMe, uTagRequirement, bNegative, BigNumber);
+}
+
+
+static inline void /* Deprecated */
+QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe,
+                               const uint8_t       uTagRequirement,
+                               const UsefulBufC    BigNumber)
+{
+   QCBOREncode_AddTBigNumberRaw(pMe, uTagRequirement, false, BigNumber);
+}
+
+static inline void  /* Deprecated */
 QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pMe,
                                       const char         *szLabel,
                                       const uint8_t       uTagRequirement,
-                                      const UsefulBufC    Bytes)
+                                      const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddSZString(pMe, szLabel);
-   QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes);
+   QCBOREncode_AddTBigNumberRawToMapSZ(pMe, szLabel, uTagRequirement, false, BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pMe,
                                      const int64_t       nLabel,
                                      const uint8_t       uTagRequirement,
-                                     const UsefulBufC    Bytes)
+                                     const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddInt64(pMe, nLabel);
-   QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes);
+   QCBOREncode_AddTBigNumberRawToMapN(pMe, nLabel, uTagRequirement, false, BigNumber);
 }
 
-static inline void
-QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes)
+static inline void  /* Deprecated */
+QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, const UsefulBufC BigNumber)
 {
-   QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes);
+   QCBOREncode_AddTBigNumberRaw(pMe, QCBOR_ENCODE_AS_TAG, false, BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pMe,
                                    const char         *szLabel,
-                                   const UsefulBufC    Bytes)
+                                   const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddTPositiveBignumToMapSZ(pMe,
-                                         szLabel,
-                                         QCBOR_ENCODE_AS_TAG,
-                                         Bytes);
+   QCBOREncode_AddTBigNumberRawToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, false, BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pMe,
                                     const int64_t       nLabel,
-                                    const UsefulBufC    Bytes)
+                                    const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddTPositiveBignumToMapN(pMe,
-                                        nLabel,
-                                        QCBOR_ENCODE_AS_TAG,
-                                        Bytes);
+   QCBOREncode_AddTBigNumberRawToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, false, BigNumber);
 }
 
-
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe,
                                const uint8_t       uTagRequirement,
-                               const UsefulBufC    Bytes)
+                               const UsefulBufC    BigNumber)
 {
-   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_NEG_BIGNUM);
-   }
-   QCBOREncode_AddBytes(pMe, Bytes);
+   QCBOREncode_AddTBigNumberRaw(pMe, uTagRequirement, true, BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pMe,
                                       const char         *szLabel,
                                       const uint8_t       uTagRequirement,
-                                      const UsefulBufC    Bytes)
+                                      const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddSZString(pMe, szLabel);
-   QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes);
+   QCBOREncode_AddTBigNumberRawToMapSZ(pMe,
+                                       szLabel,
+                                       uTagRequirement,
+                                       true,
+                                       BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pMe,
                                      const int64_t       nLabel,
                                      const uint8_t       uTagRequirement,
-                                     const UsefulBufC    Bytes)
+                                     const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddInt64(pMe, nLabel);
-   QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes);
+   QCBOREncode_AddTBigNumberRawToMapN(pMe,
+                                      nLabel,
+                                      uTagRequirement,
+                                      true,
+                                      BigNumber);
 }
 
-static inline void
-QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes)
+static inline void  /* Deprecated */
+QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, const UsefulBufC BigNumber)
 {
-   QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes);
+   QCBOREncode_AddTBigNumberRaw(pMe, QCBOR_ENCODE_AS_TAG, true, BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pMe,
                                    const char         *szLabel,
-                                   const UsefulBufC    Bytes)
+                                   const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddTNegativeBignumToMapSZ(pMe,
-                                         szLabel,
-                                         QCBOR_ENCODE_AS_TAG,
-                                         Bytes);
+   QCBOREncode_AddTBigNumberRawToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, true, BigNumber);
 }
 
-static inline void
+static inline void  /* Deprecated */
 QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe,
                                     const int64_t       nLabel,
-                                    const UsefulBufC    Bytes)
+                                    const UsefulBufC    BigNumber)
 {
-   QCBOREncode_AddTNegativeBignumToMapN(pMe,
-                                        nLabel,
-                                        QCBOR_ENCODE_AS_TAG,
-                                        Bytes);
+   QCBOREncode_AddTBigNumberRawToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, true, BigNumber);
+
 }
 
 
 
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
 
+
 static inline void
 QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe,
                                 const uint8_t       uTagRequirement,
                                 const int64_t       nMantissa,
                                 const int64_t       nBase10Exponent)
 {
-   uint64_t uTag;
-   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      uTag = CBOR_TAG_DECIMAL_FRACTION;
-   } else {
-      uTag = CBOR_TAG_INVALID64;
-   }
-   QCBOREncode_Private_AddExpMantissa(pMe,
-                                      uTag,
-                                      NULLUsefulBufC,
-                                      false,
-                                      nMantissa,
-                                      nBase10Exponent);
+   QCBOREncode_Private_AddTExpIntMantissa(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          nBase10Exponent,
+                                          nMantissa);
 }
 
 static inline void
@@ -3314,7 +4037,7 @@
                                    nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pMe,
                                const int64_t       nMantissa,
                                const int64_t       nBase10Exponent)
@@ -3325,7 +4048,7 @@
                                    nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pMe,
                                     const char         *szLabel,
                                     const int64_t       nMantissa,
@@ -3338,7 +4061,7 @@
                                           nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pMe,
                                      const int64_t       nLabel,
                                      const int64_t       nMantissa,
@@ -3352,29 +4075,120 @@
 }
 
 
+static inline void
+QCBOREncode_AddTDecimalFractionBigMantissa(QCBOREncodeContext *pMe,
+                                           const uint8_t       uTagRequirement,
+                                           const UsefulBufC    Mantissa,
+                                           const bool          bIsNegative,
+                                           const int64_t       nBase10Exponent)
+{
+   QCBOREncode_Private_AddTExpBigMantissa(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          nBase10Exponent,
+                                          Mantissa,
+                                          bIsNegative);
+}
+
 
 static inline void
+QCBOREncode_AddTDecimalFractionBigMantissaToMapSZ(QCBOREncodeContext *pMe,
+                                                  const char         *szLabel,
+                                                  const uint8_t       uTagRequirement,
+                                                  const UsefulBufC    Mantissa,
+                                                  const bool          bIsNegative,
+                                                  const int64_t       nBase10Exponent)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTDecimalFractionBigMantissa(pMe,
+                                              uTagRequirement,
+                                              Mantissa,
+                                              bIsNegative,
+                                              nBase10Exponent);
+}
+
+static inline void
+QCBOREncode_AddTDecimalFractionBigMantissaToMapN(QCBOREncodeContext *pMe,
+                                                 const int64_t       nLabel,
+                                                 const uint8_t       uTagRequirement,
+                                                 const UsefulBufC    Mantissa,
+                                                 const bool          bIsNegative,
+                                                 const int64_t       nBase10Exponent)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTDecimalFractionBigMantissa(pMe,
+                                              uTagRequirement,
+                                              Mantissa,
+                                              bIsNegative,
+                                              nBase10Exponent);
+}
+
+static inline void
+QCBOREncode_AddTDecimalFractionBigMantissaRaw(QCBOREncodeContext *pMe,
+                                              const uint8_t       uTagRequirement,
+                                              const UsefulBufC    Mantissa,
+                                              const bool          bIsNegative,
+                                              const int64_t       nBase10Exponent)
+{
+   QCBOREncode_Private_AddTExpBigMantissaRaw(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_DECIMAL_FRACTION,
+                                             nBase10Exponent,
+                                             Mantissa,
+                                             bIsNegative);
+}
+
+
+static inline void
+QCBOREncode_AddTDecimalFractionBigMantissaRawToMapSZ(QCBOREncodeContext *pMe,
+                                                     const char         *szLabel,
+                                                     const uint8_t       uTagRequirement,
+                                                     const UsefulBufC    Mantissa,
+                                                     const bool          bIsNegative,
+                                                     const int64_t       nBase10Exponent)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTDecimalFractionBigMantissaRaw(pMe,
+                                                 uTagRequirement,
+                                                 Mantissa,
+                                                 bIsNegative,
+                                                 nBase10Exponent);
+}
+
+static inline void
+QCBOREncode_AddTDecimalFractionBigMantissaRawToMapN(QCBOREncodeContext *pMe,
+                                                    const int64_t       nLabel,
+                                                    const uint8_t       uTagRequirement,
+                                                    const UsefulBufC    Mantissa,
+                                                    const bool          bIsNegative,
+                                                    const int64_t       nBase10Exponent)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTDecimalFractionBigMantissaRaw(pMe,
+                                                 uTagRequirement,
+                                                 Mantissa,
+                                                 bIsNegative,
+                                                 nBase10Exponent);
+}
+
+
+
+static inline void /* Deprecated */
 QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe,
                                       const uint8_t       uTagRequirement,
                                       const UsefulBufC    Mantissa,
                                       const bool          bIsNegative,
                                       const int64_t       nBase10Exponent)
 {
-   uint64_t uTag;
-   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      uTag = CBOR_TAG_DECIMAL_FRACTION;
-   } else {
-      uTag = CBOR_TAG_INVALID64;
-   }
-   QCBOREncode_Private_AddExpMantissa(pMe,
-                                      uTag,
-                                      Mantissa,
-                                      bIsNegative,
-                                      0,
-                                      nBase10Exponent);
+   QCBOREncode_AddTDecimalFractionBigMantissaRaw(pMe,
+                                                 uTagRequirement,
+                                                 Mantissa,
+                                                 bIsNegative,
+                                                 nBase10Exponent);
 }
 
-static inline void
+
+static inline void /* Deprecated */
 QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe,
                                              const char         *szLabel,
                                              const uint8_t       uTagRequirement,
@@ -3382,15 +4196,15 @@
                                              const bool          bIsNegative,
                                              const int64_t       nBase10Exponent)
 {
-   QCBOREncode_AddSZString(pMe, szLabel);
-   QCBOREncode_AddTDecimalFractionBigNum(pMe,
-                                         uTagRequirement,
-                                         Mantissa,
-                                         bIsNegative,
-                                         nBase10Exponent);
+   QCBOREncode_AddTDecimalFractionBigMantissaRawToMapSZ(pMe,
+                                                        szLabel,
+                                                        uTagRequirement,
+                                                        Mantissa,
+                                                        bIsNegative,
+                                                        nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe,
                                             const int64_t       nLabel,
                                             const uint8_t       uTagRequirement,
@@ -3398,79 +4212,69 @@
                                             const bool          bIsNegative,
                                             const int64_t       nBase10Exponent)
 {
-   QCBOREncode_AddInt64(pMe, nLabel);
-   QCBOREncode_AddTDecimalFractionBigNum(pMe,
-                                         uTagRequirement,
-                                         Mantissa,
-                                         bIsNegative,
-                                         nBase10Exponent);
+   QCBOREncode_AddTDecimalFractionBigMantissaRawToMapN(pMe,
+                                                       nLabel,
+                                                       uTagRequirement,
+                                                       Mantissa,
+                                                       bIsNegative,
+                                                       nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pMe,
                                      const UsefulBufC    Mantissa,
                                      const bool          bIsNegative,
                                      const int64_t       nBase10Exponent)
 {
-   QCBOREncode_AddTDecimalFractionBigNum(pMe,
-                                         QCBOR_ENCODE_AS_TAG,
-                                         Mantissa,
-                                         bIsNegative,
-                                         nBase10Exponent);
+   QCBOREncode_AddTDecimalFractionBigMantissaRaw(pMe,
+                                                 QCBOR_ENCODE_AS_TAG,
+                                                 Mantissa,
+                                                 bIsNegative,
+                                                 nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe,
                                             const char         *szLabel,
                                             const UsefulBufC    Mantissa,
                                             const bool          bIsNegative,
                                             const int64_t       nBase10Exponent)
 {
-   QCBOREncode_AddTDecimalFractionBigNumToMapSZ(pMe,
-                                                szLabel,
-                                                QCBOR_ENCODE_AS_TAG,
-                                                Mantissa,
-                                                bIsNegative,
-                                                nBase10Exponent);
+   QCBOREncode_AddTDecimalFractionBigMantissaRawToMapSZ(pMe,
+                                                        szLabel,
+                                                        QCBOR_ENCODE_AS_TAG,
+                                                        Mantissa,
+                                                        bIsNegative,
+                                                        nBase10Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe,
                                            const int64_t       nLabel,
                                            const UsefulBufC    Mantissa,
                                            const bool          bIsNegative,
-                                           const int64_t       nBase2Exponent)
+                                           const int64_t       nBase10Exponent)
 {
-   QCBOREncode_AddTDecimalFractionBigNumToMapN(pMe,
-                                               nLabel,
-                                               QCBOR_ENCODE_AS_TAG,
-                                               Mantissa,
-                                               bIsNegative,
-                                               nBase2Exponent);
+   QCBOREncode_AddTDecimalFractionBigMantissaRawToMapN(pMe,
+                                                       nLabel,
+                                                       QCBOR_ENCODE_AS_TAG,
+                                                       Mantissa,
+                                                       bIsNegative,
+                                                       nBase10Exponent);
 }
 
 
-
-
-
 static inline void
 QCBOREncode_AddTBigFloat(QCBOREncodeContext *pMe,
                          const uint8_t       uTagRequirement,
                          const int64_t       nMantissa,
                          const int64_t       nBase2Exponent)
 {
-   uint64_t uTag;
-   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      uTag = CBOR_TAG_BIGFLOAT;
-   } else {
-      uTag = CBOR_TAG_INVALID64;
-   }
-   QCBOREncode_Private_AddExpMantissa(pMe,
-                                      uTag,
-                                      NULLUsefulBufC,
-                                      false,
-                                      nMantissa,
-                                      nBase2Exponent);
+   QCBOREncode_Private_AddTExpIntMantissa(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          nBase2Exponent,
+                                          nMantissa);
 }
 
 static inline void
@@ -3495,7 +4299,7 @@
    QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddBigFloat(QCBOREncodeContext *pMe,
                         const int64_t       nMantissa,
                         const int64_t       nBase2Exponent)
@@ -3506,7 +4310,7 @@
                             nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pMe,
                              const char         *szLabel,
                              const int64_t       nMantissa,
@@ -3519,7 +4323,7 @@
                                    nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pMe,
                               const int64_t       nLabel,
                               const int64_t       nMantissa,
@@ -3533,29 +4337,119 @@
 }
 
 
+static inline void
+QCBOREncode_AddTBigFloatBigMantissa(QCBOREncodeContext *pMe,
+                                    const uint8_t       uTagRequirement,
+                                    const UsefulBufC    Mantissa,
+                                    const bool          bIsNegative,
+                                    const int64_t       nBase2Exponent)
+{
+   QCBOREncode_Private_AddTExpBigMantissa(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          nBase2Exponent,
+                                          Mantissa,
+                                          bIsNegative);
+}
 
 static inline void
+QCBOREncode_AddTBigFloatBigMantissaToMapSZ(QCBOREncodeContext *pMe,
+                                           const char         *szLabel,
+                                           const uint8_t       uTagRequirement,
+                                           const UsefulBufC    Mantissa,
+                                           const bool          bIsNegative,
+                                           const int64_t       nBase2Exponent)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTBigFloatBigMantissa(pMe,
+                                       uTagRequirement,
+                                       Mantissa,
+                                       bIsNegative,
+                                       nBase2Exponent);
+}
+
+static inline void
+QCBOREncode_AddTBigFloatBigMantissaToMapN(QCBOREncodeContext *pMe,
+                                          const int64_t       nLabel,
+                                          const uint8_t       uTagRequirement,
+                                          const UsefulBufC    Mantissa,
+                                          const bool          bIsNegative,
+                                          const int64_t       nBase2Exponent)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTBigFloatBigMantissa(pMe,
+                                       uTagRequirement,
+                                       Mantissa,
+                                       bIsNegative,
+                                       nBase2Exponent);
+}
+
+
+
+static inline void
+QCBOREncode_AddTBigFloatBigMantissaRaw(QCBOREncodeContext *pMe,
+                                       const uint8_t       uTagRequirement,
+                                       const UsefulBufC    Mantissa,
+                                       const bool          bIsNegative,
+                                       const int64_t       nBase2Exponent)
+{
+   QCBOREncode_Private_AddTExpBigMantissaRaw(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_BIGFLOAT,
+                                             nBase2Exponent,
+                                             Mantissa,
+                                             bIsNegative);
+}
+
+static inline void
+QCBOREncode_AddTBigFloatBigMantissaRawToMapSZ(QCBOREncodeContext *pMe,
+                                              const char         *szLabel,
+                                              const uint8_t       uTagRequirement,
+                                              const UsefulBufC    Mantissa,
+                                              const bool          bIsNegative,
+                                              const int64_t       nBase2Exponent)
+{
+   QCBOREncode_AddSZString(pMe, szLabel);
+   QCBOREncode_AddTBigFloatBigMantissaRaw(pMe,
+                                          uTagRequirement,
+                                          Mantissa,
+                                          bIsNegative,
+                                          nBase2Exponent);
+}
+
+static inline void
+QCBOREncode_AddTBigFloatBigMantissaRawToMapN(QCBOREncodeContext *pMe,
+                                             const int64_t       nLabel,
+                                             const uint8_t       uTagRequirement,
+                                             const UsefulBufC    Mantissa,
+                                             const bool          bIsNegative,
+                                             const int64_t       nBase2Exponent)
+{
+   QCBOREncode_AddInt64(pMe, nLabel);
+   QCBOREncode_AddTBigFloatBigMantissaRaw(pMe,
+                                          uTagRequirement,
+                                          Mantissa,
+                                          bIsNegative,
+                                          nBase2Exponent);
+}
+
+
+
+static inline void /* Deprecated */
 QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pMe,
                                const uint8_t       uTagRequirement,
                                const UsefulBufC    Mantissa,
                                const bool          bIsNegative,
                                const int64_t       nBase2Exponent)
 {
-   uint64_t uTag;
-   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      uTag = CBOR_TAG_BIGFLOAT;
-   } else {
-      uTag = CBOR_TAG_INVALID64;
-   }
-   QCBOREncode_Private_AddExpMantissa(pMe,
-                                      uTag,
-                                      Mantissa,
-                                      bIsNegative,
-                                      0,
-                                      nBase2Exponent);
+   QCBOREncode_AddTBigFloatBigMantissaRaw(pMe,
+                                          uTagRequirement,
+                                          Mantissa,
+                                          bIsNegative,
+                                          nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pMe,
                                       const char         *szLabel,
                                       const uint8_t       uTagRequirement,
@@ -3563,15 +4457,15 @@
                                       const bool          bIsNegative,
                                       const int64_t       nBase2Exponent)
 {
-   QCBOREncode_AddSZString(pMe, szLabel);
-   QCBOREncode_AddTBigFloatBigNum(pMe,
-                                  uTagRequirement,
-                                  Mantissa,
-                                  bIsNegative,
-                                  nBase2Exponent);
+   QCBOREncode_AddTBigFloatBigMantissaRawToMapSZ(pMe,
+                                                 szLabel,
+                                                 uTagRequirement,
+                                                 Mantissa,
+                                                 bIsNegative,
+                                                 nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pMe,
                                      const int64_t       nLabel,
                                      const uint8_t       uTagRequirement,
@@ -3579,55 +4473,56 @@
                                      const bool          bIsNegative,
                                      const int64_t       nBase2Exponent)
 {
-   QCBOREncode_AddInt64(pMe, nLabel);
-   QCBOREncode_AddTBigFloatBigNum(pMe,
-                                  uTagRequirement,
-                                  Mantissa,
-                                  bIsNegative,
-                                  nBase2Exponent);
+   QCBOREncode_AddTBigFloatBigMantissaRawToMapN(pMe,
+                                                nLabel,
+                                                uTagRequirement,
+                                                Mantissa,
+                                                bIsNegative,
+                                                nBase2Exponent);
 }
 
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pMe,
                               const UsefulBufC    Mantissa,
                               const bool          bIsNegative,
                               const int64_t       nBase2Exponent)
 {
-   QCBOREncode_AddTBigFloatBigNum(pMe,
-                                  QCBOR_ENCODE_AS_TAG,
-                                  Mantissa, bIsNegative,
-                                  nBase2Exponent);
+   QCBOREncode_AddTBigFloatBigMantissaRaw(pMe,
+                                          QCBOR_ENCODE_AS_TAG,
+                                          Mantissa,
+                                          bIsNegative,
+                                          nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pMe,
                                    const char         *szLabel,
                                    const UsefulBufC    Mantissa,
                                    const bool          bIsNegative,
                                    const int64_t       nBase2Exponent)
 {
-   QCBOREncode_AddTBigFloatBigNumToMapSZ(pMe,
-                                         szLabel,
-                                         QCBOR_ENCODE_AS_TAG,
-                                         Mantissa,
-                                         bIsNegative,
-                                         nBase2Exponent);
+   QCBOREncode_AddTBigFloatBigMantissaRawToMapSZ(pMe,
+                                                 szLabel,
+                                                 QCBOR_ENCODE_AS_TAG,
+                                                 Mantissa,
+                                                 bIsNegative,
+                                                 nBase2Exponent);
 }
 
-static inline void
+static inline void /* Deprecated */
 QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pMe,
                                     const int64_t       nLabel,
                                     const UsefulBufC    Mantissa,
                                     const bool          bIsNegative,
                                     const int64_t       nBase2Exponent)
 {
-   QCBOREncode_AddTBigFloatBigNumToMapN(pMe,
-                                        nLabel,
-                                        QCBOR_ENCODE_AS_TAG,
-                                        Mantissa,
-                                        bIsNegative,
-                                        nBase2Exponent);
+   QCBOREncode_AddTBigFloatBigMantissaRawToMapN(pMe,
+                                                nLabel,
+                                                QCBOR_ENCODE_AS_TAG,
+                                                Mantissa,
+                                                bIsNegative,
+                                                nBase2Exponent);
 }
 #endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
 
@@ -3638,7 +4533,7 @@
                     const UsefulBufC    URI)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_URI);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_URI);
    }
    QCBOREncode_AddText(pMe, URI);
 }
@@ -3693,7 +4588,7 @@
                         const UsefulBufC    B64Text)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_B64);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_B64);
    }
    QCBOREncode_AddText(pMe, B64Text);
 }
@@ -3748,7 +4643,7 @@
                            const UsefulBufC    B64Text)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_B64URL);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_B64URL);
    }
    QCBOREncode_AddText(pMe, B64Text);
 }
@@ -3806,7 +4701,7 @@
                       const UsefulBufC    Bytes)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_REGEX);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_REGEX);
    }
    QCBOREncode_AddText(pMe, Bytes);
 }
@@ -3861,7 +4756,7 @@
                          const UsefulBufC    MIMEData)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_BINARY_MIME);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_BINARY_MIME);
    }
    QCBOREncode_AddBytes(pMe, MIMEData);
 }
@@ -3915,7 +4810,7 @@
                            const char         *szDate)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_STRING);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_DATE_STRING);
    }
    QCBOREncode_AddSZString(pMe, szDate);
 }
@@ -3969,7 +4864,7 @@
                            const char         *szDate)
 {
    if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
-      QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_STRING);
+      QCBOREncode_AddTagNumber(pMe, CBOR_TAG_DAYS_STRING);
    }
    QCBOREncode_AddSZString(pMe, szDate);
 }
@@ -3998,8 +4893,14 @@
 static inline void
 QCBOREncode_AddSimple(QCBOREncodeContext *pMe, const uint8_t uNum)
 {
-   /* This check often is optimized out because uNum is known at compile time. */
 #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   if(pMe->uMode >= QCBOR_ENCODE_MODE_DCBOR) {
+      if(uNum < CBOR_SIMPLEV_FALSE || uNum > CBOR_SIMPLEV_NULL) {
+         pMe->uError = QCBOR_ERR_NOT_PREFERRED;
+         return;
+      }
+   }
+   /* This check often is optimized out because uNum is known at compile time. */
    if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
       pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
       return;
@@ -4148,6 +5049,7 @@
    QCBOREncode_OpenArray(pMe);
 }
 
+
 static inline void
 QCBOREncode_CloseArray(QCBOREncodeContext *pMe)
 {
@@ -4184,7 +5086,7 @@
 static inline void
 QCBOREncode_CloseMap(QCBOREncodeContext *pMe)
 {
-   QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP);
+   (pMe->pfnCloseMap)(pMe);
 }
 
 static inline void
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index a061809..7e3b1b7 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -92,9 +92,9 @@
  *                                should return 'x'.
  *  FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled
  *                                             preferred float or disabling
- *                                             hardware floating point results in
- *                                             error, and all other cases should
- *                                             return 'x'.
+ *                                             hardware floating point results
+ *                                             in error, and all other cases
+ *                                             should return 'x'.
  */
 #ifdef USEFULBUF_DISABLE_ALL_FLOAT
    #define FLOAT_ERR_CODE_NO_FLOAT(x)                 QCBOR_ERR_ALL_FLOAT_DISABLED
@@ -165,6 +165,8 @@
  * a uin32_t.
  *
  * This will cause trouble on a machine where size_t is less than 32-bits.
+ *
+ * TODO: make this public?
  */
 #define QCBOR_MAX_ARRAY_OFFSET  (UINT32_MAX - 100)
 
@@ -215,14 +217,37 @@
  * 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
+ *  64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
  *  32-bit machine: 15 + 1 + 132 = 148 bytes
  */
+typedef struct _QCBOREncodeContext QCBORPrivateEncodeContext;
+
+
+/* These are in order of increasing strictness. Order is relied upon in
+ * implementation. */
+#define QCBOR_ENCODE_MODE_ANY       0
+#define QCBOR_ENCODE_MODE_PREFERRED 1
+#define QCBOR_ENCODE_MODE_CDE       2
+#define QCBOR_ENCODE_MODE_DCBOR     3
+
+
+// TODO: probably get rid of this
+/* Operate in compatibility with QCBOR 1.0
+ * So far the differences are:
+ *  - AddNegativeBigNum and AddBigFloat with a negative big num
+ */
+#define QCBOR_ENCODE_CONFIG_V1_COMPAT 0x01
+
 struct _QCBOREncodeContext {
    /* PRIVATE DATA STRUCTURE */
    UsefulOutBuf      OutBuf;  /* Pointer to output buffer, its length and
                                * position in it. */
    uint8_t           uError;  /* Error state, always from QCBORError enum */
+   uint8_t           uMode;   /* @ref QCBOR_ENCODE_MODE_PREFERRED or related */
+   uint8_t           uConfig; /* QCBOR_ENCODE_CONFIG_xxx */
+   uint8_t           uAllow;  /* @ref QCBOR_ENCODE_ALLOW_NAN_PAYLOAD, ... */
+   void            (*pfnCloseMap)(QCBORPrivateEncodeContext *); /* Use of function
+                               * pointer explained in QCBOREncode_SerializationCDE() */
    QCBORTrackNesting nesting; /* Keep track of array and map nesting */
 };
 
@@ -329,6 +354,11 @@
 } QCBORInternalAllocator;
 
 
+/* Private data structure for mapped tag numbers. The 0th entry
+ * is the one first in the traversal and furthest from the tag content.*/
+typedef uint16_t QCBORMappedTagNumbers[QCBOR_MAX_TAGS_PER_ITEM1];
+
+
 /*
  * PRIVATE DATA STRUCTURE
  *
@@ -366,14 +396,24 @@
    uint8_t  uDecodeMode;
    uint8_t  bStringAllocateAll;
    uint8_t  uLastError;  /* QCBORError stuffed into a uint8_t */
+   uint8_t  bAllowAllLabels; /* Used internally only, not an external feature yet */
 
    /* See MapTagNumber() for description of how tags are mapped. */
    uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS];
 
-   uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1];
+   QCBORMappedTagNumbers auLastTags;
+
+   const struct QCBORTagDecoderEntry *pTagDecoderTable;
+   void       *pTagDecodersContext;
+
+   size_t      uTagNumberCheckOffset;
+   uint8_t     uTagNumberIndex;
+#define QCBOR_ALL_TAGS_PROCESSED UINT8_MAX
 };
 
 
+
+
 /* Used internally in the impementation here Must not conflict with
  * any of the official CBOR types
  */
@@ -401,6 +441,8 @@
 /* The number of elements in a C array of a particular type */
 #define C_ARRAY_COUNT(array, type) (sizeof(array)/sizeof(type))
 
+#define ABSOLUTE_VALUE(x) ((x) < 0 ? -(x) : (x))
+
 
 #ifdef __cplusplus
 }
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index dcb03f3..e690f31 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -25,6 +25,7 @@
 #endif
 
 
+
 /**
  * @file qcbor_spiffy_decode.h
  *
@@ -297,6 +298,240 @@
                                    int64_t            *pnValue);
 
 
+#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+/**
+ * @brief dCBOR Decode next as a number with precision-preserving conversions.
+ *
+ * @param[in] pCtx           The decode context.
+ * @param[out] pNumber       The returned number.
+ *
+ * This gets the next item as a number and returns it as a C data type
+ * such that no precision is lost.
+ *
+ * This is primarily works with integers and floats for both the
+ * to-be-decoded CBOR and the decoded types.
+ *
+ * The CBOR input can be integers (major type 0 or 1) or floats (major
+ * type 7).  If not these, \ref QCBOR_ERR_UNEXPECTED_TYPE will be set.
+ *
+ * The conversion is as follows.
+ *
+ * Whole numbers from \c INT64_MIN to \c INT64_MAX will be returned as
+ * int64_t indicated as \ref QCBOR_TYPE_INT64. This includes
+ * conversion of floating-point values that are whole numbers.
+ *
+ * Whole numbers from \c INT64_MAX +1 to \c UINT64_MAX will be
+ * returned as uint64_t indicated as \ref QCBOR_TYPE_UINT64, again
+ * including conversion of floating-point values that are whole
+ * numbers.
+ *
+ * Most other numbers are returned as a double as indicated by 
+ * \ref QCBOR_TYPE_DOUBLE floating point with one set of exceptions.
+ *
+ * The exception is negative whole numbers in the range of -(2^63 + 1)
+ * to -(2^64) that have too much precision to be represented as a
+ * double. Doubles have only 52 bits of precision, so they can't
+ * precisely represent every whole integer in this range. CBOR can
+ * represent these values with 64-bits of precision and when this
+ * function encounters them they are returned as \ref
+ * QCBOR_TYPE_65BIT_NEG_INT.  See the description of this type for
+ * instructions to gets its value.  Also see
+ * QCBORDecode_ProcessBigNumber().
+ *
+ * To give an example, the value -18446744073709551616 can't be
+ * represented by an int64_t or uint64_t, but can be represented by a
+ * double so it is returned by this function as a double. The value
+ * -18446744073709551617 however can't be represented by a double
+ * because it has too much precision, so it is returned as \ref
+ * QCBOR_TYPE_65BIT_NEG_INT.
+ *
+ * This is useful for DCBOR which essentially combines floats and
+ * integers into one number space.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See also QCBORDecode_GetNumberConvertPreciselyBig().
+ */
+void
+QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pCtx,
+                                      QCBORItem          *pNumber);
+
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+/**
+ * @brief Decode next item as a big number encoded using preferred serialization.
+ *
+ * @param[in] pCtx          The decode context.
+ * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[in] BigNumberBuf     The buffer to write the result into.
+ * @param[out] pBigNumber     The output big number.
+ * @param[in,out] pbIsNegative  Set to true if the resulting big number is negative.
+ *
+ * See QCBORDecode_PreferedBigNumber() in full detail.
+ *
+ * The type processing rules are as follows.
+ *
+ * This always succeeds on type 0 and 1 integers (QCBOR_TYPE_INT64,
+ * QCBOR_TYPE_UINT64 and QCBOR_TYPE_65_BIT_NEG) no matter what
+ * uTagRequirement is. The rest of the rules pertain to what happens
+ * if the CBOR is not type 0 or type 1.
+ *
+ * If @c uTagRequirement is @ref QCBOR_TAG_REQUIREMENT_TAG, this will fail on anything but a
+ * full and correct tag 2 or tag 3 big number.
+ *
+ * If @c uTagRequreiement is @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG then this
+ * will fail on anything but a byte string.
+ *
+ * If @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, then this will succeed on
+ * either a byte string or a tag 2 or 3.
+ *
+ * If the item is a bare byte string, not a tag 2 or 3, then
+ * pbIsNegative is an input parameter that determines the sign of the
+ * big number. The sign must be known because the decoding of a
+ * positive big number is different than a negative.
+ */
+void
+QCBORDecode_GetTBigNumber(QCBORDecodeContext *pCtx,
+                          const uint8_t       uTagRequirement,
+                          UsefulBuf           BigNumberBuf,
+                          UsefulBufC         *pBigNumber,
+                          bool               *pbIsNegative);
+
+void
+QCBORDecode_GetTBigNumberInMapN(QCBORDecodeContext *pCtx,
+                                int64_t             nLabel,
+                                uint8_t             uTagRequirement,
+                                UsefulBuf           BigNumberBuf,
+                                UsefulBufC         *pBigNumber,
+                                bool               *pbIsNegative);
+
+void
+QCBORDecode_GetTBigNumberInMapSZ(QCBORDecodeContext *pCtx,
+                                 const char         *szLabel,
+                                 uint8_t             uTagRequirement,
+                                 UsefulBuf           BigNumberBuf,
+                                 UsefulBufC         *pBigNumber,
+                                 bool               *pbIsNegative);
+
+ /**
+  * @brief Decode the next item as a big number with no processing
+  *
+  * @param[in] pCtx             The decode context.
+  * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
+  * @param[out] pBigNumber          The returned big number.
+  * @param[out] pbIsNegative    Is @c true if the big number is negative. This
+  *                             is only valid when @c uTagRequirement is
+  *                             @ref QCBOR_TAG_REQUIREMENT_TAG.
+  *
+  * This decodes a standard CBOR big number, integer tag number of 2 or
+  * 3, or encoded CBOR that is not a tag, but borrows the content
+  * format.
+  *
+  * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+  *
+  * The big number is in network byte order. The first byte in @c
+  * pValue is the most significant byte. There may be leading zeros.
+  *
+  * This does not apply the offset of 1 to negative big numbers
+  * because it does no processing. To get the correct value
+  * one must be subtracted when the value is negative. That
+  * is one must be added to pBigNumber. Note that this
+  * operation may increase the length of pBigNumber
+  * because of the arithmetic carry. See
+  *
+  * The negative value is computed as -1 - n, where n is the postive
+  * big number in @c pValue. There is no standard representation for
+  * big numbers, positive or negative in C, so this function
+  * leaves it up to the caller to apply this computation for negative
+  * big numbers, but QCBORDecode_ProcessBigNumber() can be
+  * used too.
+  *
+  * See @ref Tag-Usage for discussion on tag requirements.
+  *
+  * Determination of the sign of the big number depends on the tag
+  * requirement of the protocol using the big number. If the protocol
+  * requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign
+  * indication is in the protocol and @c pbIsNegative indicates the
+  * sign. If the protocol doesn't use a tag,
+  * @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG, then the protocol design must
+  * have some way of indicating the sign.
+  *
+  * See also QCBORDecode_GetInt64ConvertAll(),
+  * QCBORDecode_GetUInt64ConvertAll(),
+  * QCBORDecode_GetDoubleConvertAll() and
+  * QCBORDecode_ProcessBigNumber() which can convert big numbers.
+  *
+  * See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM,
+  * QCBOREncode_AddPositiveBignum(), QCBOREncode_AddNegativeBignum(),
+  * @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM.
+  *
+  * To feed the output of this to QCBORDecode_ProcessBigNumber() construct
+  * a temporary QCBORItem and feed it to QCBORDecode_ProcessBigNumber().
+  * Set the data type to @ref CBOR_TAG_POS_BIGNUM or @ref CBOR_TAG_NEG_BIGNUM,
+  * and value to @c *pValue in the QCBORItem.
+  *
+  * This is the same as QCBORDecode_GetBignum() in QCBOR v1.
+  *
+  * This links in much less object code than QCBORDecode_GetTBitNumber() and
+  * QCBORDecode_GetTBitNumberNoPreferred().
+  */
+void
+QCBORDecode_GetTBigNumberRaw(QCBORDecodeContext *pCtx,
+                             const uint8_t       uTagRequirement,
+                             UsefulBufC         *pBigNumber,
+                             bool               *pbIsNegative);
+
+void
+QCBORDecode_GetTBigNumberRawInMapN(QCBORDecodeContext *pMe,
+                                   const int64_t       nLabel,
+                                   const uint8_t       uTagRequirement,
+                                   UsefulBufC         *pBigNumber,
+                                   bool               *pbIsNegative);
+
+void
+QCBORDecode_GetTBigNumberRawInMapSZ(QCBORDecodeContext *pMe,
+                                   const char        *szLabel,
+                                   const uint8_t       uTagRequirement,
+                                   UsefulBufC         *pBigNumber,
+                                   bool               *pbIsNegative);
+
+/**
+ * @brief Decode next item as a big number encoded using preferred serialization.
+ *
+ * @param[in] pCtx          The decode context.
+ * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[in] BigNumberBuf     The buffer to write the result into.
+ * @param[out] pBigNumber      The output big number.
+ * @param[in,out] pbIsNegative  Set to true if the resulting big number is negative.
+ *
+ * This is the same as QCBORDecode_GetBigNumber(), but will error
+ * out on type 0 and 1 integers. It only succeeds on tag 2 and tag 3.
+ */
+void
+QCBORDecode_GetTBigNumberNoPreferred(QCBORDecodeContext *pCtx,
+                                     const uint8_t       uTagRequirement,
+                                     UsefulBuf           BigNumberBuf,
+                                     UsefulBufC         *pBigNumber,
+                                     bool               *pbIsNegative);
+
+void
+QCBORDecode_GetTBigNumberNoPreferredInMapN(QCBORDecodeContext *pCtx,
+                                          int64_t             nLabel,
+                                          uint8_t             uTagRequirement,
+                                          UsefulBuf           BigNumberBuf,
+                                          UsefulBufC         *pBigNumber,
+                                          bool               *pbIsNegative);
+
+void
+QCBORDecode_GetTBigNumberNoPreferredInMapSZ(QCBORDecodeContext *pCtx,
+                                           const char         *szLabel,
+                                           uint8_t             uTagRequirement,
+                                           UsefulBuf           BigNumberBuf,
+                                           UsefulBufC         *pBigNumber,
+                                           bool               *pbIsNegative);
+
+
+
 /**
  * @brief Decode next item into a signed 64-bit integer with conversions.
  *
@@ -663,7 +898,7 @@
  * The typical way to iterate over items in an array is to call
  * QCBORDecode_VGetNext() until QCBORDecode_GetError() returns
  * @ref QCBOR_ERR_NO_MORE_ITEMS. Other methods like QCBORDecode_GetInt64(),
- * QCBORDecode_GetBignum() and such may also called until
+ * QCBORDecode_GetBignum() and such may also be called until
  * QCBORDecode_GetError() doesn't return QCBOR_SUCCESS.
  *
  * Another option is to get the array item count from
@@ -961,6 +1196,24 @@
 
 
 /**
+ * @brief Position traversal cursor by map label.
+ *
+ * TODO: finish this documentation
+ */
+void
+QCBORDecode_SeekToLabelN(QCBORDecodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ * @brief Position traversal cursor by map label.
+ *
+ * TODO: finish this documentation
+ */
+void
+QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel);
+
+
+/**
  * @brief Get an item in map by label and type.
  *
  * @param[in] pCtx    The decode context.
@@ -1030,6 +1283,16 @@
  * is more efficient than scanning each individually because the map
  * only needs to be traversed once.
  *
+ * Warning, this does not check that the tag numbers have been
+ * consumed or checked. This can be remedied by checking that
+ * every pItemList.auTagNumbers is empty or has tag numbers that are
+ * expected. While tag numbers were once described as "optional",
+ * they really do have critical information that should not be ignored.
+ * See @ref Tag-Decoding
+ *
+ * This function works well with tag content decoders as described in
+ * QCBORDecode_InstallTagDecoders().
+ *
  * This will return maps and arrays that are in the map, but provides
  * no way to descend into and decode them. Use
  * QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and
@@ -1119,7 +1382,11 @@
                                       QCBORItemCallback   pfCB);
 
 
+QCBORError
+QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint64_t *puTagNumber);
 
+QCBORError
+QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint64_t *puTagNumber);
 
 /**
  * @brief Decode the next item as a Boolean.
@@ -1396,72 +1663,6 @@
 
 
 
-/**
- * @brief Decode the next item as a big number.
- *
- * @param[in] pCtx             The decode context.
- * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pValue          The returned big number.
- * @param[out] pbIsNegative    Is @c true if the big number is negative. This
- *                             is only valid when @c uTagRequirement is
- *                             @ref QCBOR_TAG_REQUIREMENT_TAG.
- *
- * This decodes a standard CBOR big number, integer tag number of 2 or
- * 3, or encoded CBOR that is not a tag, but borrows the content
- * format.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * The big number is in network byte order. The first byte in @c
- * pValue is the most significant byte. There may be leading zeros.
- *
- * The negative value is computed as -1 - n, where n is the postive
- * big number in @c pValue. There is no standard representation for
- * big numbers, positive or negative in C, so this implementation
- * leaves it up to the caller to apply this computation for negative
- * big numbers.
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * Determination of the sign of the big number depends on the tag
- * requirement of the protocol using the big number. If the protocol
- * requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign
- * indication is in the protocol and @c pbIsNegative indicates the
- * sign. If the protocol doesn't use a tag, @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG,
- * then the protocol design must have some way of indicating the sign.
- *
- * See also QCBORDecode_GetInt64ConvertAll(),
- * QCBORDecode_GetUInt64ConvertAll() and
- * QCBORDecode_GetDoubleConvertAll() which can convert big numbers.
- *
- * See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM,
- * QCBOREncode_AddTPositiveBignum(), QCBOREncode_AddTNegativeBignum(),
- * @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM.
- */
-// Improvement: Add function that converts integers and other to big nums
-void
-QCBORDecode_GetBignum(QCBORDecodeContext *pCtx,
-                      uint8_t             uTagRequirement,
-                      UsefulBufC         *pValue,
-                      bool               *pbIsNegative);
-
-void
-QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx,
-                            int64_t             nLabel,
-                            uint8_t             uTagRequirement,
-                            UsefulBufC         *pValue,
-                            bool               *pbIsNegative);
-
-void
-QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx,
-                             const char         *szLabel,
-                             uint8_t             uTagRequirement,
-                             UsefulBufC         *pValue,
-                             bool               *pbIsNegative);
-
-
-
-
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
 /**
  * @brief Decode the next item as a decimal fraction.
@@ -1471,64 +1672,68 @@
  * @param[out] pnMantissa      The mantissa.
  * @param[out] pnExponent      The base 10 exponent.
  *
- * This decodes a standard CBOR decimal fraction, integer tag number
- * of 4, or encoded CBOR that is not a tag, but borrows the content
- * format.
+ * The input to decode must be a decimal fraction as defined in
+ * [RFC 8949 section 3.4.4]
+ * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.4).  That
+ * is, an array of two numbers, the first of which is the exponent and
+ * the second is the mantissa.
  *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ * Depending on @c uTagRequirement, the tag number
+ * @ref CBOR_TAG_DECIMAL_FRACTION (4) may or may not need to be
+ * present before the array. See @ref Tag-Usage.
  *
- * The  value of this is computed by:
+ * The exponent must always be an integer (CBOR type 0 or 1). The
+ * mantissa may be an integer or a big number. If it is a big number,
+ * the tag number 2 or 3 must be present.
+ *
+ * The exponent is limited to between @c INT64_MIN and
+ * @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to @c UINT64_MAX.
+ *
+ * The mantissa is always returned as an @c int64_t.  If the value
+ * won't fit, @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be
+ * set. Use QCBORDecode_GetTDecimalFractionBigMantissa() to avoid the
+ * limit to @c int64_t.
+ *
+ * The value of this is computed by:
  *
  *     mantissa * ( 10 ** exponent )
  *
- * In the encoded CBOR, the mantissa and exponent may be of CBOR type
- * 0 (positive integer), type 1 (negative integer), type 2 tag 2
- * (positive big number) or type 2 tag 3 (negative big number). This
- * implementation will attempt to convert all of these to an @c
- * int64_t. If the value won't fit, @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW
- * or @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA will be set.
- *
- * This implementation limits the exponent to between @c INT64_MIN and
- * @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to
- * @c UINT64_MAX.
- *
- * Various format and type issues will result in
- * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA being set.
- *
- * See @ref Tag-Usage for discussion on tag requirements.
+ * Various format and type issues will result in @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA
+ * being set.  See @ref Decode-Errors-Overview "Decode Errors
+ * Overview".
  *
  * See also QCBORDecode_GetInt64ConvertAll(),
  * QCBORDecode_GetUInt64ConvertAll() and
- * QCBORDecode_GetDoubleConvertAll() which can convert big numbers.
+ * QCBORDecode_GetDoubleConvertAll() which can also decode decimal
+ * fractions.
  *
  * See also @ref CBOR_TAG_DECIMAL_FRACTION,
- * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION
- * and QCBORDecode_GetDecimalFractionBig().
+ * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION.
  *
  * If QCBOR_DISABLE_TAGS is set, the only input this will decode is an
  * array of two integers. It will set an error if the the array is
  * preceded by by a tag number or if the mantissa is a big number.
  */
 void
-QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx,
-                               uint8_t             uTagRequirement,
-                               int64_t            *pnMantissa,
-                               int64_t            *pnExponent);
+QCBORDecode_GetTDecimalFraction(QCBORDecodeContext *pCtx,
+                                uint8_t             uTagRequirement,
+                                int64_t            *pnMantissa,
+                                int64_t            *pnExponent);
 
 void
-QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx,
-                                     int64_t             nLabel,
-                                     uint8_t             uTagRequirement,
-                                     int64_t            *pnMantissa,
-                                     int64_t            *pnExponent);
-
-void
-QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
-                                      const char         *szLabel,
+QCBORDecode_GetTDecimalFractionInMapN(QCBORDecodeContext *pCtx,
+                                      int64_t             nLabel,
                                       uint8_t             uTagRequirement,
                                       int64_t            *pnMantissa,
                                       int64_t            *pnExponent);
 
+void
+QCBORDecode_GetTDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
+                                       const char         *szLabel,
+                                       uint8_t             uTagRequirement,
+                                       int64_t            *pnMantissa,
+                                       int64_t            *pnExponent);
+
 
 /**
  * @brief Decode the next item as a decimal fraction with a big number mantissa.
@@ -1540,7 +1745,7 @@
  * @param[out] pbMantissaIsNegative  Is @c true if @c pMantissa is negative.
  * @param[out] pnExponent      The base 10 exponent.
  *
- * This is the same as QCBORDecode_GetDecimalFraction() except the
+ * This is the same as QCBORDecode_GetTDecimalFraction() except the
  * mantissa is returned as a big number.
  *
  * In the encoded CBOR, the mantissa may be a type 0 (positive
@@ -1549,21 +1754,60 @@
  * will convert all these to a big number. The limit to this
  * conversion is the size of @c MantissaBuffer.
  *
- * The mantissa returned does NOT have the offset
- * of one applied when it is negative. To get the true value
- * one must be added to @c *pMantissa (which requires
- * some big number arithmetic and may increase the length
- * of it by one).
+ * See also QCBORDecode_GetInt64ConvertAll(),
+ * QCBORDecode_GetUInt64ConvertAll() and
+ * QCBORDecode_GetDoubleConvertAll() which can convert decimal
+ * fractions.
  *
- * For QCBOR before v1.5, this function had a bug where
- * by the negative mantissa sometimes had the offset of
- * one applied, making this function somewhat usless for
- * negative mantissas. Specifically if the to-be-decode CBOR
- * was a type 1 integer the offset was applied and when it
- * was a tag 3, the offset was not applied. It is possible
- * that a tag 3 could contain a value in the range of a type 1
- * integer. @ref QCBORExpAndMantissa is
- * correct and can be used instead of this.
+ * See also @ref CBOR_TAG_DECIMAL_FRACTION,
+ * QCBOREncode_AddTDecimalFractionBigMantissa(), @ref QCBOR_TYPE_DECIMAL_FRACTION
+ * and QCBORDecode_GetTDecimalFraction().
+ */
+void
+QCBORDecode_GetTDecimalFractionBigMantissa(QCBORDecodeContext *pCtx,
+                                           uint8_t             uTagRequirement,
+                                           UsefulBuf           MantissaBuffer,
+                                           UsefulBufC         *pMantissa,
+                                           bool               *pbMantissaIsNegative,
+                                           int64_t            *pnExponent);
+
+void
+QCBORDecode_GetTDecimalFractionBigMantissaInMapN(QCBORDecodeContext *pCtx,
+                                                 int64_t             nLabel,
+                                                 uint8_t             uTagRequirement,
+                                                 UsefulBuf           MantissaBuffer,
+                                                 UsefulBufC         *pbMantissaIsNegative,
+                                                 bool               *pbIsNegative,
+                                                 int64_t            *pnExponent);
+
+void
+QCBORDecode_GetTDecimalFractionBigMantissaInMapSZ(QCBORDecodeContext *pCtx,
+                                                  const char         *szLabel,
+                                                  uint8_t             uTagRequirement,
+                                                  UsefulBuf           MantissaBuffer,
+                                                  UsefulBufC         *pMantissa,
+                                                  bool               *pbMantissaIsNegative,
+                                                  int64_t            *pnExponent);
+
+
+/**
+ * @brief Decode the next item as a decimal fraction with a big number mantissa raw.
+ *
+ * @param[in] pCtx             The decode context.
+ * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[in] MantissaBuffer   The buffer in which to put the mantissa.
+ * @param[out] pMantissa       The big num mantissa.
+ * @param[out] pbMantissaIsNegative  Is @c true if @c pMantissa is negative.
+ * @param[out] pnExponent      The base 10 exponent.
+ *
+ * This is the same as QCBORDecode_GetTDecimalFractionBigMantissa() except the
+ * negative mantissas are NOT offset by one and this links in less object code.
+ *
+ * In the encoded CBOR, the mantissa may be a type 0 (positive
+ * integer), type 1 (negative integer), type 2 tag 2 (positive big
+ * number) or type 2 tag 3 (negative big number). This implementation
+ * will convert all these to a big number. The limit to this
+ * conversion is the size of @c MantissaBuffer.
  *
  * See also QCBORDecode_GetInt64ConvertAll(),
  * QCBORDecode_GetUInt64ConvertAll() and
@@ -1571,34 +1815,36 @@
  * fractions.
  *
  * See also @ref CBOR_TAG_DECIMAL_FRACTION,
- * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION
- * and QCBORDecode_GetDecimalFraction().
+ * QCBOREncode_AddTDecimalFractionBigMantissaRaw(), @ref QCBOR_TYPE_DECIMAL_FRACTION
+ * and QCBORDecode_GetTDecimalFractionBigMantissa().
  */
 void
-QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx,
-                                  uint8_t             uTagRequirement,
-                                  UsefulBuf           MantissaBuffer,
-                                  UsefulBufC         *pMantissa,
-                                  bool               *pbMantissaIsNegative,
-                                  int64_t            *pnExponent);
+QCBORDecode_GetTDecimalFractionBigMantissaRaw(QCBORDecodeContext *pCtx,
+                                              uint8_t             uTagRequirement,
+                                              UsefulBuf           MantissaBuffer,
+                                              UsefulBufC         *pMantissa,
+                                              bool               *pbMantissaIsNegative,
+                                              int64_t            *pnExponent);
 
 void
-QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx,
-                                        int64_t             nLabel,
-                                        uint8_t             uTagRequirement,
-                                        UsefulBuf           MantissaBuffer,
-                                        UsefulBufC         *pbMantissaIsNegative,
-                                        bool               *pbIsNegative,
-                                        int64_t            *pnExponent);
+QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(QCBORDecodeContext *pCtx,
+                                                    int64_t             nLabel,
+                                                    uint8_t             uTagRequirement,
+                                                    UsefulBuf           MantissaBuffer,
+                                                    UsefulBufC         *pbMantissaIsNegative,
+                                                    bool               *pbIsNegative,
+                                                    int64_t            *pnExponent);
 
 void
-QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx,
-                                         const char         *szLabel,
-                                         uint8_t             uTagRequirement,
-                                         UsefulBuf           MantissaBuffer,
-                                         UsefulBufC         *pMantissa,
-                                         bool               *pbMantissaIsNegative,
-                                         int64_t            *pnExponent);
+QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ(QCBORDecodeContext *pCtx,
+                                                     const char         *szLabel,
+                                                     uint8_t             uTagRequirement,
+                                                     UsefulBuf           MantissaBuffer,
+                                                     UsefulBufC         *pMantissa,
+                                                     bool               *pbMantissaIsNegative,
+                                                     int64_t            *pnExponent);
+
+
 
 
 /**
@@ -1609,45 +1855,64 @@
  * @param[out] pnMantissa      The mantissa.
  * @param[out] pnExponent      The base 2 exponent.
  *
- * This decodes a standard CBOR big float, integer tag number of 5, or
- * encoded CBOR that is not a tag, but borrows the content format.
+ * The input to decode must be a big float defined in [RFC 8949 section 3.4.4]
+ * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.4).  That
+ * is, an array of two numbers, the first of which is the exponent and
+ * the second is the mantissa.
  *
- * This is the same as QCBORDecode_GetDecimalFraction() with the
- * important distinction that the value is computed by:
+ * Depending on @c uTagRequirement, the tag number
+ * @ref CBOR_TAG_BIG_FLOAT (5) may or may not need to be present
+ * before the array. See @ref Tag-Usage.
+ *
+ * The exponent must always be an integer (CBOR type 0 or 1). The
+ * mantissa may be an integer or a big number. If it is a big number,
+ * the tag number 2 or 3 must be present.
+ *
+ * This implementation limits the exponent to between @c INT64_MIN and
+ * @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to @c UINT64_MAX.
+ *
+ * The mantissa is always returned as an @c int64_t.  If the value
+ * won't fit, @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be
+ * set. Use QCBORDecode_GetBigFloastBigNumber() to avoid the
+ * limit to @c int64_t.
  *
  *     mantissa * ( 2 ** exponent )
  *
- * If the mantissa is a tag that is a positive or negative big number,
- * this will attempt to fit it into the int64_t that @c pnMantissa is
- * and set an overflow error if it doesn't fit.
+ * Various format and type issues will result in
+ * @ref  QCBOR_ERR_BAD_EXP_AND_MANTISSA being set. See
+ * @ref Decode-Errors-Overview "Decode Errors Overview".
  *
  * See also QCBORDecode_GetInt64ConvertAll(),
  * QCBORDecode_GetUInt64ConvertAll() and
  * QCBORDecode_GetDoubleConvertAll() which can convert big floats.
  *
- * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), @ref
- * QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloatBig().
+ * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(),
+ * @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetTBigFloatBigMantissa().
+ *
+ * If QCBOR_DISABLE_TAGS is set, the only input this will decode is an
+ * array of two integers. It will set an error if the the array is
+ * preceded by by a tag number or if the mantissa is a big number.
  */
 void
-QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx,
-                        uint8_t             uTagRequirement,
-                        int64_t            *pnMantissa,
-                        int64_t            *pnExponent);
+QCBORDecode_GetTBigFloat(QCBORDecodeContext *pCtx,
+                         uint8_t             uTagRequirement,
+                         int64_t            *pnMantissa,
+                         int64_t            *pnExponent);
 
 void
-QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx,
-                              int64_t             nLabel,
-                              uint8_t             uTagRequirement,
-                              int64_t            *pnMantissa,
-                              int64_t            *pnExponent);
-
-void
-QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx,
-                               const char         *szLabel,
+QCBORDecode_GetTBigFloatInMapN(QCBORDecodeContext *pCtx,
+                               int64_t             nLabel,
                                uint8_t             uTagRequirement,
                                int64_t            *pnMantissa,
                                int64_t            *pnExponent);
 
+void
+QCBORDecode_GetTBigFloatInMapSZ(QCBORDecodeContext *pCtx,
+                                const char         *szLabel,
+                                uint8_t             uTagRequirement,
+                                int64_t            *pnMantissa,
+                                int64_t            *pnExponent);
+
 
 /**
  * @brief Decode the next item as a big float with a big number mantissa.
@@ -1659,49 +1924,101 @@
  * @param[out] pbMantissaIsNegative  Is @c true if @c pMantissa is negative.
  * @param[out] pnExponent      The base 2 exponent.
  *
- * This is the same as QCBORDecode_GetDecimalFractionBig() with the
- * important distinction that the value is computed by:
+ * This is the same as QCBORDecode_GetTBigFloat() except the mantissa
+ * is returned as a big number. The only limit to precision is the
+ * size of @c MantissaBuffer.
  *
- *     mantissa * ( 2 ** exponent )
+ * The encoded mantissa may be an integer or a big number.  The
+ * standard CBOR offset of 1 for negative is applied, so the mantissa can be used as
+ * returned.
  *
- * This has the same issue with negative mantissas as
- * QCBORDecode_GetDecimalFractionBig().
- *
- * See also QCBORDecode_GetInt64ConvertAll(),
- * QCBORDecode_GetUInt64ConvertAll() and
- * QCBORDecode_GetDoubleConvertAll() which can convert big floats.
- *
- * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(),
- * @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloat().
+ * See also @ref CBOR_TAG_BIGFLOAT,
+ * QCBOREncode_AddTBigFloatBigNumber(), @ref QCBOR_TYPE_BIGFLOAT and
+ * QCBORDecode_GetTBigFloat().
  */
 void
-QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx,
-                           uint8_t             uTagRequirement,
-                           UsefulBuf           MantissaBuffer,
-                           UsefulBufC         *pMantissa,
-                           bool               *pbMantissaIsNegative,
-                           int64_t            *pnExponent);
+QCBORDecode_GetTBigFloatBigMantissa(QCBORDecodeContext *pCtx,
+                                    uint8_t             uTagRequirement,
+                                    UsefulBuf           MantissaBuffer,
+                                    UsefulBufC         *pMantissa,
+                                    bool               *pbMantissaIsNegative,
+                                    int64_t            *pnExponent);
+
 
 void
-QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx,
-                                 int64_t             nLabel,
-                                 uint8_t             uTagRequirement,
-                                 UsefulBuf           MantissaBuffer,
-                                 UsefulBufC         *pMantissa,
-                                 bool               *pbMantissaIsNegative,
-                                 int64_t            *pnExponent);
+QCBORDecode_GetTBigFloatBigMantissaInMapN(QCBORDecodeContext *pCtx,
+                                          int64_t             nLabel,
+                                          uint8_t             uTagRequirement,
+                                          UsefulBuf           MantissaBuffer,
+                                          UsefulBufC         *pMantissa,
+                                          bool               *pbMantissaIsNegative,
+                                          int64_t            *pnExponent);
 
 void
-QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx,
-                                  const char         *szLabel,
-                                  uint8_t             uTagRequirement,
-                                  UsefulBuf           MantissaBuffer,
-                                  UsefulBufC         *pMantissa,
-                                  bool               *pbMantissaIsNegative,
-                                  int64_t            *pnExponent);
-#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */
+QCBORDecode_GetTBigFloatBigMantissaInMapSZ(QCBORDecodeContext *pCtx,
+                                           const char         *szLabel,
+                                           uint8_t             uTagRequirement,
+                                           UsefulBuf           MantissaBuffer,
+                                           UsefulBufC         *pMantissa,
+                                           bool               *pbMantissaIsNegative,
+                                           int64_t            *pnExponent);
 
 
+/**
+ * @brief Decode the next item as a big float with a big number mantissa with out offsetting the mantissa
+ *
+ * @param[in] pCtx             The decode context.
+ * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[in] MantissaBuffer   The buffer in which to put the mantissa.
+ * @param[out] pMantissa       The big num mantissa.
+ * @param[out] pbMantissaIsNegative  Is @c true if @c pMantissa is negative.
+ * @param[out] pnExponent      The base 2 exponent.
+ *
+ * This is the same as QCBORDecode_GetBigFloat() except the mantissa
+ * is returned as a big number. The only limit to precision is the
+ * size of @c MantissaBuffer.
+ *
+ * The encoded mantissa may be an integer or a big number.  The
+ * standard CBOR offset of 1 for negative is NOT applied. If the ma
+ * mantissa is negative, one must be added to get it's actual value.
+ *
+ * Because this doesn't offset the negative big numbers, this links in
+ * a lot less object code. It is suitable for uses where a big number
+ * library is already linked in for other purposes as it can trivially
+ * do the increment by one.
+ *
+ * See also @ref CBOR_TAG_BIGFLOAT,
+ * QCBOREncode_AddTBigFloatBigNumber(), @ref QCBOR_TYPE_BIGFLOAT and
+ * QCBORDecode_GetTBigFloat().
+ */
+void
+QCBORDecode_GetTBigFloatBigMantissaRaw(QCBORDecodeContext *pCtx,
+                                       uint8_t             uTagRequirement,
+                                       UsefulBuf           MantissaBuffer,
+                                       UsefulBufC         *pMantissa,
+                                       bool               *pbMantissaIsNegative,
+                                       int64_t            *pnExponent);
+
+
+void
+QCBORDecode_GetTBigFloatBigMantissaRawInMapN(QCBORDecodeContext *pCtx,
+                                             int64_t             nLabel,
+                                             uint8_t             uTagRequirement,
+                                             UsefulBuf           MantissaBuffer,
+                                             UsefulBufC         *pMantissa,
+                                             bool               *pbMantissaIsNegative,
+                                             int64_t            *pnExponent);
+
+void
+QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ(QCBORDecodeContext *pCtx,
+                                              const char         *szLabel,
+                                              uint8_t             uTagRequirement,
+                                              UsefulBuf           MantissaBuffer,
+                                              UsefulBufC         *pMantissa,
+                                              bool               *pbMantissaIsNegative,
+                                              int64_t            *pnExponent);
+
+#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
 
 
 /**
@@ -1881,13 +2198,13 @@
  * This does no translation of line endings. See QCBOREncode_AddText()
  * for a discussion of line endings in CBOR.
  */
-static void
+void
 QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx,
                            uint8_t             uTagRequirement,
                            UsefulBufC         *pMessage,
                            bool               *pbIsTag257);
 
-static void
+ void
 QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx,
                                  int64_t              nLabel,
                                  uint8_t              uTagRequirement,
@@ -1895,7 +2212,7 @@
                                  bool                *pbIsTag257);
 
 
-static void
+void
 QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx,
                                   const char         *szLabel,
                                   uint8_t             uTagRequirement,
@@ -2026,6 +2343,150 @@
 
 
 
+/* ===========================================================================
+   DEPRECATED methods
+   ========================================================================== */
+
+/* Deprecated. Use QCBORDecode_GetTBigNumberRaw() instead. */
+static void
+QCBORDecode_GetBignum(QCBORDecodeContext *pCtx,
+                      uint8_t             uTagRequirement,
+                      UsefulBufC         *pValue,
+                      bool               *pbIsNegative);
+
+static void
+QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx,
+                            int64_t             nLabel,
+                            uint8_t             uTagRequirement,
+                            UsefulBufC         *pValue,
+                            bool               *pbIsNegative);
+
+static void
+QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx,
+                             const char         *szLabel,
+                             uint8_t             uTagRequirement,
+                             UsefulBufC         *pValue,
+                             bool               *pbIsNegative);
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/* Use QCBORDecode_GetTDecimalFraction() instead */
+static void
+QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx,
+                               uint8_t             uTagRequirement,
+                               int64_t            *pnMantissa,
+                               int64_t            *pnExponent);
+
+/* Use QCBORDecode_GetTDecimalFractionInMapN() instead */
+static void
+QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx,
+                                     int64_t             nLabel,
+                                     uint8_t             uTagRequirement,
+                                     int64_t            *pnMantissa,
+                                     int64_t            *pnExponent);
+/* Use QCBORDecode_GetTDecimalFractionInMapSZ() instead */
+static void
+QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
+                                      const char         *szLabel,
+                                      uint8_t             uTagRequirement,
+                                      int64_t            *pnMantissa,
+                                      int64_t            *pnExponent);
+
+/* Use QCBORDecode_GetTDecimalFractionBigMantissaRaw() instead */
+
+/*
+ TODO: integrate this comment better
+* For QCBOR before v1.5, this function had a bug where
+* by the negative mantissa sometimes had the offset of
+* one applied, making this function somewhat usless for
+* negative mantissas. Specifically if the to-be-decode CBOR
+* was a type 1 integer the offset was applied and when it
+* was a tag 3, the offset was not applied. It is possible
+* that a tag 3 could contain a value in the range of a type 1
+* integer. @ref QCBORExpAndMantissa is
+* correct and can be used instead of this. */
+static void
+QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx,
+                                  uint8_t             uTagRequirement,
+                                  UsefulBuf           MantissaBuffer,
+                                  UsefulBufC         *pMantissa,
+                                  bool               *pbMantissaIsNegative,
+                                  int64_t            *pnExponent);
+
+/* Use QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN() instead */
+static void
+QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx,
+                                        int64_t             nLabel,
+                                        uint8_t             uTagRequirement,
+                                        UsefulBuf           MantissaBuffer,
+                                        UsefulBufC         *pbMantissaIsNegative,
+                                        bool               *pbIsNegative,
+                                        int64_t            *pnExponent);
+
+/* Use QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ() instead */
+static void
+QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx,
+                                         const char         *szLabel,
+                                         uint8_t             uTagRequirement,
+                                         UsefulBuf           MantissaBuffer,
+                                         UsefulBufC         *pMantissa,
+                                         bool               *pbMantissaIsNegative,
+                                         int64_t            *pnExponent);
+
+/* Deprecated. Use QCBORDecode_GetTBigFloat() instead */
+static void
+QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx,
+                        uint8_t             uTagRequirement,
+                        int64_t            *pnMantissa,
+                        int64_t            *pnExponent);
+
+/* Deprecated. Use QCBORDecode_GetTBigFloatInMapN() instead */
+static void
+QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx,
+                              int64_t             nLabel,
+                              uint8_t             uTagRequirement,
+                              int64_t            *pnMantissa,
+                              int64_t            *pnExponent);
+
+/* Deprecated. Use QCBORDecode_GetTBigFloatInMapSZ() instead */
+static void
+QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx,
+                               const char         *szLabel,
+                               uint8_t             uTagRequirement,
+                               int64_t            *pnMantissa,
+                               int64_t            *pnExponent);
+
+/* Deprecated. Use QCBORDecode_GetTBigFloatBigMantissaRaw() instead */
+static void
+QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx,
+                           uint8_t             uTagRequirement,
+                           UsefulBuf           MantissaBuffer,
+                           UsefulBufC         *pMantissa,
+                           bool               *pbMantissaIsNegative,
+                           int64_t            *pnExponent);
+
+/* Deprecated. Use QCBORDecode_GetTBigFloatBigMantissaRawInMapN() instead */
+static void
+QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx,
+                                 int64_t             nLabel,
+                                 uint8_t             uTagRequirement,
+                                 UsefulBuf           MantissaBuffer,
+                                 UsefulBufC         *pMantissa,
+                                 bool               *pbMantissaIsNegative,
+                                 int64_t            *pnExponent);
+
+/* Deprecated. Use QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ() instead */
+static void
+QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx,
+                                  const char         *szLabel,
+                                  uint8_t             uTagRequirement,
+                                  UsefulBuf           MantissaBuffer,
+                                  UsefulBufC         *pMantissa,
+                                  bool               *pbMantissaIsNegative,
+                                  int64_t            *pnExponent);
+#endif /* ! QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+
 
 /* ========================================================================= *
  *    BEGINNING OF PRIVATE INLINE IMPLEMENTATION                             *
@@ -2119,56 +2580,44 @@
 #endif /* !USEFULBUF_DISABLE_ALL_FLOAT */
 
 #define QCBOR_TAGSPEC_NUM_TYPES 4
-/* Semi-private data structure (which might change).
- *
- * See QCBOR_Private_CheckTagRequirement() which uses this to check the
- * type of an item to be decoded as a tag or tag content.
- *
- * Improvement: Carefully understand what compilers do with this,
- * particularly initialization and see if it can be optimized so there
- * is less code and maybe so it can be smaller.
- */
-typedef struct {
-   /* One of QCBOR_TAGSPEC_MATCH_xxx */
-   uint8_t uTagRequirement;
-   /* The tagged type translated into QCBOR_TYPE_XXX. Used to match
-    * explicit tagging */
-   uint8_t uTaggedTypes[QCBOR_TAGSPEC_NUM_TYPES];
-   /* The types of the content, which are used to match implicit
-    * tagging */
-   uint8_t uAllowedContentTypes[QCBOR_TAGSPEC_NUM_TYPES];
-} QCBOR_Private_TagSpec;
+
+
+
+
+
+
 
 
 /* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+
 void
-QCBORDecode_Private_GetTaggedString(QCBORDecodeContext   *pCtx,
-                                    QCBOR_Private_TagSpec TagSpec,
-                                    UsefulBufC           *pBstr);
+QCBORDecode_Private_GetTaggedString(QCBORDecodeContext  *pMe,
+                                    uint8_t              uTagRequirement,
+                                    uint8_t              uQCBOR_Type,
+                                    uint64_t             uTagNumber,
+                                    UsefulBufC          *pBstr);
 
-
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
 void
-QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext   *pCtx,
-                                          int64_t               nLabel,
-                                          QCBOR_Private_TagSpec TagSpec,
-                                          UsefulBufC           *pString);
+QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext  *pMe,
+                                          const int64_t        nLabel,
+                                          const uint8_t        uTagRequirement,
+                                          const uint8_t        uQCBOR_Type,
+                                          const uint64_t       uTagNumber,
+                                          UsefulBufC          *pString);
 
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+
+
+
+
+
+
 void
-QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext   *pCtx,
-                                           const char           *szLabel,
-                                           QCBOR_Private_TagSpec TagSpec,
-                                           UsefulBufC           *pString);
-
-
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
-QCBORError
-QCBORDecode_Private_GetMIME(uint8_t           uTagRequirement,
-                            const QCBORItem  *pItem,
-                            UsefulBufC       *pMessage,
-                            bool             *pbIsTag257);
-
+QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext  *pMe,
+                                           const char          *szLabel,
+                                           uint8_t              uTagRequirement,
+                                           uint8_t              uQCBOR_Type,
+                                           uint64_t             uTagNumber,
+                                           UsefulBufC          *pString);
 
 
 
@@ -2290,7 +2739,7 @@
 
 static inline void
 QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pMe,
-                             int64_t             nLabel,
+                             const int64_t       nLabel,
                              QCBORItem          *pItem,
                              UsefulBufC         *pEncodedCBOR)
 {
@@ -2337,7 +2786,7 @@
 
 static inline void
 QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pMe,
-                           int64_t             nLabel,
+                           const int64_t       nLabel,
                            QCBORItem          *pItem,
                            UsefulBufC         *pEncodedCBOR)
 {
@@ -2514,63 +2963,65 @@
 
 
 
-
 static inline void
-QCBORDecode_GetByteString(QCBORDecodeContext *pMe,  UsefulBufC *pValue)
+QCBORDecode_GetByteString(QCBORDecodeContext *pMe, UsefulBufC *pBytes)
 {
-   // Complier should make this just a 64-bit integer parameter
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         QCBOR_TAG_REQUIREMENT_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS,
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORItem  Item;
 
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue);
+   QCBORDecode_VGetNext(pMe, &Item);
+
+   if(pMe->uLastError == QCBOR_SUCCESS && Item.uDataType == QCBOR_TYPE_BYTE_STRING) {
+      *pBytes = Item.val.string;
+   } else {
+      *pBytes = NULLUsefulBufC;
+   }
 }
 
 static inline void
 QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pMe,
                                 const int64_t       nLabel,
-                                UsefulBufC         *pBstr)
+                                UsefulBufC         *pBytes)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS,
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pBstr);
+   QCBORItem  Item;
+
+   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item);
+
+   if(pMe->uLastError == QCBOR_SUCCESS) {
+      *pBytes = Item.val.string;
+   } else {
+      *pBytes = NULLUsefulBufC;
+   }
 }
 
 static inline void
 QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pMe,
                                  const char         *szLabel,
-                                 UsefulBufC         *pBstr)
+                                 UsefulBufC         *pBytes)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS,
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORItem  Item;
 
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pBstr);
+   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item);
+
+   if(pMe->uLastError == QCBOR_SUCCESS) {
+      *pBytes = Item.val.string;
+   } else {
+      *pBytes = NULLUsefulBufC;
+   }
 }
 
 
 static inline void
-QCBORDecode_GetTextString(QCBORDecodeContext *pMe,  UsefulBufC *pValue)
+QCBORDecode_GetTextString(QCBORDecodeContext *pMe, UsefulBufC *pText)
 {
-   // Complier should make this just 64-bit integer parameter
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS,
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORItem  Item;
 
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue);
+   QCBORDecode_VGetNext(pMe, &Item);
+
+   if(pMe->uLastError == QCBOR_SUCCESS && Item.uDataType == QCBOR_TYPE_TEXT_STRING) {
+      *pText = Item.val.string;
+   } else {
+      *pText = NULLUsefulBufC;
+   }
 }
 
 static inline void
@@ -2578,33 +3029,34 @@
                                 const int64_t       nLabel,
                                 UsefulBufC         *pText)
 {
-   // This TagSpec only matches text strings; it also should optimize down
-   // to passing a 64-bit integer
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS,
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORItem  Item;
 
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText);
+   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_TEXT_STRING, &Item);
+
+   if(pMe->uLastError == QCBOR_SUCCESS) {
+      *pText = Item.val.string;
+   } else {
+      *pText = NULLUsefulBufC;
+   }
 }
 
 static inline void
 QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pMe,
-                                 const               char *szLabel,
+                                 const char         *szLabel,
                                  UsefulBufC         *pText)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS,
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORItem  Item;
 
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText);
+   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_TEXT_STRING, &Item);
+
+   if(pMe->uLastError == QCBOR_SUCCESS) {
+      *pText = Item.val.string;
+   } else {
+      *pText = NULLUsefulBufC;
+   }
 }
 
+
 static inline void
 QCBORDecode_GetNull(QCBORDecodeContext *pMe)
 {
@@ -2666,14 +3118,11 @@
                           const uint8_t       uTagRequirement,
                           UsefulBufC         *pValue)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_DATE_STRING,
+                                       CBOR_TAG_DATE_STRING,
+                                       pValue);
 }
 
 static inline void
@@ -2682,14 +3131,12 @@
                                 const uint8_t       uTagRequirement,
                                 UsefulBufC         *pText)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                              nLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_DATE_STRING,
+                                              CBOR_TAG_DATE_STRING,
+                                              pText);
 }
 
 static inline void
@@ -2698,14 +3145,12 @@
                                  const uint8_t       uTagRequirement,
                                  UsefulBufC         *pText)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText);
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_DATE_STRING,
+                                              CBOR_TAG_DATE_STRING,
+                                              pText);
 }
 
 static inline void
@@ -2713,14 +3158,11 @@
                           const uint8_t       uTagRequirement,
                           UsefulBufC         *pValue)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_DATE_STRING,
+                                       CBOR_TAG_DATE_STRING,
+                                       pValue);
 }
 
 static inline void
@@ -2729,30 +3171,28 @@
                                 const uint8_t       uTagRequirement,
                                 UsefulBufC         *pText)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                             nLabel,
+                                             uTagRequirement,
+                                             QCBOR_TYPE_DAYS_STRING,
+                                             CBOR_TAG_DAYS_STRING,
+                                             pText);
 }
 
+
 static inline void
 QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe,
                                  const char         *szLabel,
                                  const uint8_t       uTagRequirement,
                                  UsefulBufC         *pText)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_DAYS_STRING,
+                                              CBOR_TAG_DAYS_STRING,
+                                              pText);
 
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText);
 }
 
 
@@ -2762,14 +3202,11 @@
                    const uint8_t       uTagRequirement,
                    UsefulBufC         *pUUID)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_URI,
+                                       CBOR_TAG_URI,
+                                       pUUID);
 }
 
 static inline void
@@ -2778,14 +3215,12 @@
                          const uint8_t       uTagRequirement,
                          UsefulBufC         *pUUID)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                              nLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_URI,
+                                              CBOR_TAG_URI,
+                                              pUUID);
 }
 
 static inline void
@@ -2794,14 +3229,12 @@
                           const uint8_t       uTagRequirement,
                           UsefulBufC         *pUUID)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID);
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_URI,
+                                              CBOR_TAG_URI,
+                                              pUUID);
 }
 
 
@@ -2810,14 +3243,11 @@
                    const uint8_t       uTagRequirement,
                    UsefulBufC         *pB64Text)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_BASE64,
+                                       CBOR_TAG_B64,
+                                       pB64Text);
 }
 
 static inline void
@@ -2826,14 +3256,12 @@
                          const uint8_t       uTagRequirement,
                          UsefulBufC         *pB64Text)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                             nLabel,
+                                             uTagRequirement,
+                                             QCBOR_TYPE_BASE64,
+                                             CBOR_TAG_B64,
+                                             pB64Text);
 }
 
 static inline void
@@ -2842,13 +3270,12 @@
                           const uint8_t       uTagRequirement,
                           UsefulBufC         *pB64Text)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text);
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_BASE64,
+                                              CBOR_TAG_B64,
+                                              pB64Text);
 }
 
 
@@ -2857,14 +3284,11 @@
                       const uint8_t       uTagRequirement,
                       UsefulBufC         *pB64Text)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_BASE64URL,
+                                       CBOR_TAG_B64URL,
+                                       pB64Text);
 }
 
 static inline void
@@ -2873,14 +3297,12 @@
                             const uint8_t       uTagRequirement,
                             UsefulBufC         *pB64Text)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                              nLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_BASE64URL,
+                                              CBOR_TAG_B64URL,
+                                              pB64Text);
 }
 
 static inline void
@@ -2889,14 +3311,12 @@
                              const uint8_t       uTagRequirement,
                              UsefulBufC         *pB64Text)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text);
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_BASE64URL,
+                                              CBOR_TAG_B64URL,
+                                              pB64Text);
 }
 
 
@@ -2905,108 +3325,49 @@
                      const uint8_t      uTagRequirement,
                      UsefulBufC         *pRegex)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pRegex);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_REGEX,
+                                       CBOR_TAG_REGEX,
+                                       pRegex);
 }
 
+
+
 static inline void
 QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe,
                            const int64_t       nLabel,
                            const uint8_t       uTagRequirement,
                            UsefulBufC         *pRegex)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pRegex);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                              nLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_REGEX,
+                                              CBOR_TAG_REGEX,
+                                              pRegex);
 }
 
+
 static inline void
 QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe,
                             const char *        szLabel,
                             const uint8_t       uTagRequirement,
                             UsefulBufC         *pRegex)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pRegex);
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_REGEX,
+                                              CBOR_TAG_REGEX,
+                                              pRegex);
 }
 
 
-static inline void
-QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
-                           const uint8_t       uTagRequirement,
-                           UsefulBufC         *pMessage,
-                           bool               *pbIsTag257)
-{
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      /* Already in error state, do nothing */
-      return;
-   }
 
-   QCBORItem  Item;
-   QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
-   if(uError != QCBOR_SUCCESS) {
-      pMe->uLastError = (uint8_t)uError;
-      return;
-   }
 
-   pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement,
-                                                          &Item,
-                                                          pMessage,
-                                                          pbIsTag257);
-}
 
-static inline void
-QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
-                                 const int64_t       nLabel,
-                                 const uint8_t       uTagRequirement,
-                                 UsefulBufC         *pMessage,
-                                 bool               *pbIsTag257)
-{
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
 
-   if(pMe->uLastError == QCBOR_SUCCESS) {
-      pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement,
-                                                             &Item,
-                                                             pMessage,
-                                                             pbIsTag257);
-   }
-}
-
-static inline void
-QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
-                                  const char         *szLabel,
-                                  const uint8_t       uTagRequirement,
-                                  UsefulBufC         *pMessage,
-                                  bool               *pbIsTag257)
-{
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
-
-   if(pMe->uLastError == QCBOR_SUCCESS) {
-      pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement,
-                                                             &Item,
-                                                             pMessage,
-                                                             pbIsTag257);
-   }
-}
 
 
 static inline void
@@ -3014,14 +3375,11 @@
                           const uint8_t       uTagRequirement,
                           UsefulBufC         *pUUID)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID);
+   QCBORDecode_Private_GetTaggedString(pMe,
+                                       uTagRequirement,
+                                       QCBOR_TYPE_UUID,
+                                       CBOR_TAG_BIN_UUID,
+                                       pUUID);
 }
 
 static inline void
@@ -3030,14 +3388,12 @@
                                 const uint8_t       uTagRequirement,
                                 UsefulBufC         *pUUID)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID);
+   QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+                                             nLabel,
+                                             uTagRequirement,
+                                             QCBOR_TYPE_UUID,
+                                             CBOR_TAG_BIN_UUID,
+                                             pUUID);
 }
 
 static inline void
@@ -3046,20 +3402,197 @@
                                  const uint8_t       uTagRequirement,
                                  UsefulBufC         *pUUID)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID);
+   QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+                                              szLabel,
+                                              uTagRequirement,
+                                              QCBOR_TYPE_UUID,
+                                              CBOR_TAG_BIN_UUID,
+                                              pUUID);
 }
 
 /* ======================================================================== *
  *    END OF PRIVATE INLINE IMPLEMENTATION                                  *
  * ======================================================================== */
 
+static inline void
+QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
+                      uint8_t             uTagRequirement,
+                      UsefulBufC         *pBigNumber,
+                      bool               *pbIsNegative)
+{
+   QCBORDecode_GetTBigNumberRaw(pMe, uTagRequirement, pBigNumber, pbIsNegative);
+}
+
+static inline void
+QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
+                            int64_t             nLabel,
+                            uint8_t             uTagRequirement,
+                            UsefulBufC         *pBigNumber,
+                            bool               *pbIsNegative)
+{
+   QCBORDecode_GetTBigNumberRawInMapN(pMe, nLabel, uTagRequirement, pBigNumber, pbIsNegative);
+}
+
+static inline void
+QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
+                             const char         *szLabel,
+                             uint8_t             uTagRequirement,
+                             UsefulBufC         *pBigNumber,
+                             bool               *pbIsNegative)
+{
+   QCBORDecode_GetTBigNumberRawInMapSZ(pMe, szLabel, uTagRequirement, pBigNumber, pbIsNegative);
+}
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+static inline void
+QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
+                               uint8_t             uTagRequirement,
+                               int64_t            *pnMantissa,
+                               int64_t            *pnExponent)
+{
+   QCBORDecode_GetTDecimalFraction(pMe, uTagRequirement, pnMantissa, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
+                                     int64_t             nLabel,
+                                     uint8_t             uTagRequirement,
+                                     int64_t            *pnMantissa,
+                                     int64_t            *pnExponent)
+{
+   QCBORDecode_GetTDecimalFractionInMapN(pMe, nLabel, uTagRequirement, pnMantissa, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
+                                      const char         *szLabel,
+                                      uint8_t             uTagRequirement,
+                                      int64_t            *pnMantissa,
+                                      int64_t            *pnExponent)
+{
+   QCBORDecode_GetTDecimalFractionInMapSZ(pMe, szLabel, uTagRequirement, pnMantissa, pnExponent);
+}
+
+
+static inline void
+QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
+                                  uint8_t             uTagRequirement,
+                                  UsefulBuf           MantissaBuffer,
+                                  UsefulBufC         *pMantissa,
+                                  bool               *pbMantissaIsNegative,
+                                  int64_t            *pnExponent)
+{
+   QCBORDecode_GetTDecimalFractionBigMantissaRaw(pMe, uTagRequirement, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
+                                        int64_t             nLabel,
+                                        uint8_t             uTagRequirement,
+                                        UsefulBuf           MantissaBuffer,
+                                        UsefulBufC         *pMantissa,
+                                        bool               *pbMantissaIsNegative,
+                                        int64_t            *pnExponent)
+{
+   QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(pMe, nLabel, uTagRequirement, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
+                                         const char         *szLabel,
+                                         uint8_t             uTagRequirement,
+                                         UsefulBuf           MantissaBuffer,
+                                         UsefulBufC         *pMantissa,
+                                         bool               *pbMantissaIsNegative,
+                                         int64_t            *pnExponent)
+{
+   QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ(pMe, szLabel, uTagRequirement, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent);
+
+}
+
+static inline void
+QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
+                        uint8_t             uTagRequirement,
+                        int64_t            *pnMantissa,
+                        int64_t            *pnExponent)
+{
+   QCBORDecode_GetTBigFloat(pMe, uTagRequirement, pnMantissa, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
+                              int64_t             nLabel,
+                              uint8_t             uTagRequirement,
+                              int64_t            *pnMantissa,
+                              int64_t            *pnExponent)
+{
+   QCBORDecode_GetTBigFloatInMapN(pMe, nLabel, uTagRequirement, pnMantissa, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
+                               const char         *szLabel,
+                               uint8_t             uTagRequirement,
+                               int64_t            *pnMantissa,
+                               int64_t            *pnExponent)
+{
+   QCBORDecode_GetTBigFloatInMapSZ(pMe, szLabel, uTagRequirement, pnMantissa, pnExponent);
+}
+
+static inline void
+QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
+                           uint8_t             uTagRequirement,
+                           UsefulBuf           MantissaBuffer,
+                           UsefulBufC         *pMantissa,
+                           bool               *pbMantissaIsNegative,
+                           int64_t            *pnExponent)
+{
+   QCBORDecode_GetTBigFloatBigMantissaRaw(pMe,
+                                          uTagRequirement,
+                                          MantissaBuffer,
+                                          pMantissa,
+                                          pbMantissaIsNegative,
+                                          pnExponent);
+}
+
+
+static inline void
+QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
+                                 int64_t             nLabel,
+                                 uint8_t             uTagRequirement,
+                                 UsefulBuf           MantissaBuffer,
+                                 UsefulBufC         *pMantissa,
+                                 bool               *pbMantissaIsNegative,
+                                 int64_t            *pnExponent)
+{
+   QCBORDecode_GetTBigFloatBigMantissaRawInMapN(pMe,
+                                                nLabel,
+                                                uTagRequirement,
+                                                MantissaBuffer,
+                                                pMantissa,
+                                                pbMantissaIsNegative,
+                                                pnExponent);
+}
+
+static inline void
+QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
+                                  const char         *szLabel,
+                                  uint8_t             uTagRequirement,
+                                  UsefulBuf           MantissaBuffer,
+                                  UsefulBufC         *pMantissa,
+                                  bool               *pbMantissaIsNegative,
+                                  int64_t            *pnExponent)
+{
+   QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ(pMe,
+                                                 szLabel,
+                                                 uTagRequirement,
+                                                 MantissaBuffer,
+                                                 pMantissa,
+                                                 pbMantissaIsNegative,
+                                                 pnExponent);
+}
+#endif /* ! QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/inc/qcbor/qcbor_tag_decode.h b/inc/qcbor/qcbor_tag_decode.h
new file mode 100644
index 0000000..137ed35
--- /dev/null
+++ b/inc/qcbor/qcbor_tag_decode.h
@@ -0,0 +1,356 @@
+/* ==========================================================================
+ * qcbor_tag_decode.h -- Tag content decoders
+ *
+ * Copyright (c) 2024, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ *
+ * Created on 9/5/24
+ * ========================================================================== */
+
+#ifndef qcbor_tag_decode_h
+#define qcbor_tag_decode_h
+
+#include "qcbor/qcbor_decode.h"
+
+/**
+ * @file qcbor_tag_decode.h
+ *
+ * This file defines the interface for tag decoders that turn tags
+ * into custom QCBORItems with custom user-defined CBOR_TYPEs using
+ * callbacks.
+ *
+ * This also gives function prototypes for callbacks that are supplied
+ * for standard CBOR data types like dates and big numbers.
+ *
+ * This is one of two main facilities for handling tags in CBOR. The
+ * other is QCBORDecode_GetNextTagNumber().
+ *
+ * This file is new in QCBOR v2.
+ *
+ * @anchor Tag-Decoding
+ *
+ * ## Tags Decoding
+ *
+ * TODO: lots to write here
+ */
+
+
+
+/*
+
+ In v1, some spiffy decode functions ignored tag numbers and
+ some didn't.  For example, GetInt64 ignored and GetString didn't.
+ The "GetXxx" where Xxxx is a tag ignore conditionally based
+ on an argument.
+ (Would be good to verify this with tests)
+
+ Do we fix the behavior of GetString in v1?  Relax so it
+ allows tag numbers like the rest? Probably.
+
+ In v2, the whole mechanism is with GetTagNumbers. They are
+ never ignored and they must always be consumed.
+
+ With v2 in v1 mode, the functions that were ignoring
+ tags must go back to ignoring them.
+
+ How does TagRequirement work in v2?
+
+ GetInt64 and GetString require all tag numbs to be processed
+ to work.
+
+
+ */
+
+
+/**
+ * @brief Prototype for callback for decoding tag content.
+ *
+ * @param[in] pCtx                Decode context.
+ * @param[in] pTagDecodersContext  Optional context for tag decoders.
+ * @param[in] uTagNumber          The tag number indicated for the content.
+ * @param[in,out] pItem           On input, the item for the first and
+ *                                possibly only item for the tag content.
+ *                                On output, holds the decoded tag content.
+ *
+ * This is one of two main facilities for processing CBOR tags. This
+ * allows callbacks to be installed that fire when a particular tag
+ * number is encountered. The callback consumes the tag content and
+ * turns it into a @ref QCBORItem of a new type. The new QCBORItem is
+ * returned in normal decoding with QCBORDecode_VGetNext() and
+ * related.
+ *
+ * The other facility is QCBORDecode_GetNextTagNumber(). Note als that
+ * tag processing is substantially changed in QCBOR v2.
+ *
+ * A CBOR tag consists of a tag number and tag content. The tag
+ * content might be a simple non-aggregate type like an integer or it
+ * may be a complex protocol message. This facility is oriented around
+ * simple tag content as the output of it must be fit into a
+ * @ref QCBORItem.
+ *
+ * When called, the contents of pItem is the first item in the tag
+ * content. If it is an array or map then the items in it can be
+ * fetched by calling QCBORDecode_GetNext() and such.  All the items
+ * in the tag content must be consumed.
+ *
+ * The callback modifies pItem. It puts the output of tag content
+ * decoding in pItem. It assigns a QCBOR_TYPE integer in the range of
+ * @ref QCBOR_TYPE_START_USER_DEFINED to @ref
+ * QCBOR_TYPE_END_USER_DEFINED. Any of the members of the union @c val
+ * may be used to hold the decoded content.  @c val.userDefined is a
+ * 24 byte buffer that can be used.
+ *
+ * The tag number is passed in so as to allow one callback to be
+ * installed for several different tag numbers.
+ *
+ * The callback must be installed with
+ * QCBORDecode_InstallTagDecoders().
+ *
+ * A callback context may given when the callback is installed.  It
+ * will be passed in here as pTagDecodesrContext. There is only one
+ * context for all tag content decoders. None of the standard tag
+ * decoders here use it. The callback context can be used to make a
+ * very elaborite tag content decoder.
+ *
+ * Tags can nest. Callbacks fire first on then inner most tag.  They
+ * are called until all tags are processed or a tag number for which
+ * there is no processor is encountered.
+ *
+ * Standard CBOR defines tags for big numbers, the tag content for
+ * which is a byte string. The standard decoder supplied for this
+ * fires on the tag number for a positive or negative big number,
+ * checks that the tag content is a byte string and changes the CBOR
+ * type of the item from a byte string to either @ref
+ * QCBOR_TYPE_POSBIGNUM or @ref QCBOR_TYPE_NEGBIGNUM.
+ *
+ * Standard CBOR defines a tag for big floats, the tag content of
+ * which is an array of the mantissa and the exponent. The mantissa
+ * may be a big number. Since callbacks fire from the inside out, the
+ * big number content decoder will fire first and the big float
+ * decoder will get @ref QCBOR_TYPE_POSBIGNUM instead of a tag number and
+ * a byte string.
+ */
+typedef QCBORError (QCBORTagContentCallBack)(QCBORDecodeContext *pCtx, 
+                                             void               *pTagDecodersContext,
+                                             uint64_t            uTagNumber,
+                                             QCBORItem          *pItem);
+
+#ifndef QCBOR_DISABLE_TAGS
+
+/**
+ * An entry in the tag decoders table installed with QCBORDecode_InstallTagDecoders().
+ *
+ * The table is searched in order for the first match on
+ * @c uTagNumber. Then @c pfContentDecoder is called.
+ */
+struct QCBORTagDecoderEntry {
+   uint64_t                  uTagNumber;
+   QCBORTagContentCallBack  *pfContentDecoder;
+};
+
+
+/**
+ * @brief Set the custom tag decoders.
+ *
+ * @param[in] pCtx         The decode context.
+ * @param[in] pTagDecoderTable  The table of tag struct QCBORTagDecoderEntry content decoders.
+ *                              The table is terminated by an entry with a @c NULL pfContentDecoder.
+ *
+ * @param[in] pTagDecodersContext  Context passed to tag decoders. May be @c NULL.
+ *
+ * There is only one table of tag decoders at a time. A call to this replaces
+ * the previous table.
+ */
+static void
+QCBORDecode_InstallTagDecoders(QCBORDecodeContext                *pCtx,
+                               const struct QCBORTagDecoderEntry *pTagDecoderTable,
+                               void                              *pTagDecodersContext);
+
+
+/**
+ * A table of tag handlers that provides QCBOR v1 compatibility
+ *
+ * Install this with QCBORDecode_InstallTagDecoders().
+ */
+extern const struct QCBORTagDecoderEntry QCBORDecode_TagDecoderTablev1[];
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+/**
+ * @brief Convert different epoch date formats in to the QCBOR epoch date format.
+ *
+ * @param[in] pDecodeCtx           Decode context.
+ * @param[in] pTagDecodersContext  Optional context for tag decoders.
+ * @param[in] uTagNumber           The tag number indicated for the content.
+ * @param[in,out]  pDecodedItem    The data item to convert.
+ *
+ * @retval QCBOR_ERR_DATE_OVERFLOW              65-bit negative integer.
+ * @retval QCBOR_ERR_FLOAT_DATE_DISABLED        Float-point date in input,
+ *                                              floating-point date disabled.
+ * @retval QCBOR_ERR_ALL_FLOAT_DISABLED         Float-point date in input,
+ *                                              all floating-point disabled.
+ * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT  Unexpected and unrecoverable
+ *                                              error decoding date.
+ *
+ * The epoch date tag defined in QCBOR allows for floating-point
+ * dates. It even allows a protocol to flop between date formats when
+ * ever it wants.  Floating-point dates aren't that useful as they are
+ * only needed for dates beyond the age of the earth.
+ *
+ * This works for the following tag numbers:
+ *   @ref CBOR_TAG_DATE_EPOCH
+ *
+ * This converts all the date formats into one format of an unsigned
+ * integer plus a floating-point fraction.
+ */
+QCBORError
+QCBORDecode_DateEpochTagCB(QCBORDecodeContext *pDecodeCtx,
+                           void               *pTagDecodersContext,
+                           uint64_t            uTagNumber,
+                           QCBORItem          *pDecodedItem);
+
+
+/**
+ * @brief Convert the days epoch date.
+ *
+ * @param[in] pDecodeCtx           Decode context.
+ * @param[in] pTagDecodersContext  Optional context for tag decoders.
+ * @param[in] uTagNumber           The tag number indicated for the content.
+ * @param[in,out]  pDecodedItem    The data item to convert.
+ *
+ * @retval QCBOR_ERR_DATE_OVERFLOW              65-bit negative integer.
+ * @retval QCBOR_ERR_FLOAT_DATE_DISABLED        Float-point date in input,
+ *                                              floating-point date disabled.
+ * @retval QCBOR_ERR_ALL_FLOAT_DISABLED         Float-point date in input,
+ *                                              all floating-point disabled.
+ * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT  Unexpected and unrecoverable
+ *                                              error decoding date.
+ *
+ * This works for the following tag numbers:
+ *   @ref CBOR_TAG_DAYS_EPOCH
+ *
+ * This is much simpler than the other epoch date format because
+ * floating-porint is not allowed. This is mostly a simple type check.
+ */
+QCBORError
+QCBORDecode_DaysEpochTagCB(QCBORDecodeContext *pDecodeCtx,
+                           void               *pTagDecodersContext,
+                           uint64_t            uTagNumber,
+                           QCBORItem          *pDecodedItem);
+
+
+/**
+ * @brief Process standard CBOR tags whose content is a string.
+ *
+ * @param[in] pDecodeCtx           Decode context.
+ * @param[in] pTagDecodersContext  Optional context for tag decoders.
+ * @param[in] uTagNumber           The tag number indicated for the content.
+ * @param[in,out]  pDecodedItem    The data item to convert.
+ *
+ * @returns  This returns QCBOR_SUCCESS if the tag was procssed,
+ *           @ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
+ *           @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
+ *
+ * Process the standard CBOR tags  whose content is a byte string or a text
+ * string and for which the string is just passed on to the caller.
+ *
+ * This works for :
+ *    @ref CBOR_TAG_DATE_STRING,
+ *    @ref CBOR_TAG_POS_BIGNUM,
+ *    @ref CBOR_TAG_NEG_BIGNUM,
+ *    @ref CBOR_TAG_CBOR,
+ *    @ref CBOR_TAG_URI,
+ *    @ref CBOR_TAG_B64URL,
+ *    @ref CBOR_TAG_B64,
+ *    @ref CBOR_TAG_REGEX,
+ *    @ref CBOR_TAG_DAYS_STRING,
+ *    @ref CBOR_TAG_BIN_UUID,
+ *    @ref CBOR_TAG_CBOR_SEQUENCE
+ *
+ * This maps the CBOR tag to the QCBOR type and checks the content
+ * type.  Nothing more. It may not be the most important
+ * functionality, but it part of implementing as much of RFC 8949 as
+ * possible.
+ */
+QCBORError
+QCBORDecode_StringsTagCB(QCBORDecodeContext *pDecodeCtx,
+                         void               *pTagDecodersContext,
+                         uint64_t            uTagNumber,
+                         QCBORItem          *pDecodedItem);
+
+
+/**
+ * @brief Decode the MIME type tag
+ *
+ * @param[in] pDecodeCtx           Decode context.
+ * @param[in] pTagDecodersContext  Optional context for tag decoders.
+ * @param[in] uTagNumber           The tag number indicated for the content.
+ * @param[in,out]  pDecodedItem    The data item to convert.
+ *
+ * Handle the text and binary MIME type tags. Slightly too complicated
+ * for or QCBORDecode_StringsTagCB() because the RFC 7049 MIME type was
+ * incorrectly text-only.
+ *
+ * This works for :
+ *     @ref CBOR_TAG_BINARY_MIME,
+ *     @ref CBOR_TAG_MIME
+ */
+QCBORError
+QCBORDecode_MIMETagCB(QCBORDecodeContext *pDecodeCtx,
+                      void               *pTagDecodersContext,
+                      uint64_t            uTagNumber,
+                      QCBORItem          *pDecodedItem);
+
+/**
+ * @brief Decode decimal fractions and big floats.
+ *
+ * @param[in] pDecodeCtx           Decode context.
+ * @param[in] pTagDecodersContext  Optional context for tag decoders.
+ * @param[in] uTagNumber           The tag number indicated for the content.
+ * @param[in,out]  pDecodedItem    The data item to convert.
+ *
+ * @returns  Decoding errors from getting primitive data items or
+ *           @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
+ *
+ * When called pDecodedItem must be the array with two members, the
+ * exponent and mantissa.
+ *
+ * Fetch and decode the exponent and mantissa and put the result back
+ * into pDecodedItem.
+ *
+ * This stuffs the type of the mantissa into pDecodedItem with the
+ * expectation the caller will process it.
+ *
+ * This works for:
+ *     @ref CBOR_TAG_DECIMAL_FRACTION,
+ *     @ref CBOR_TAG_BIGFLOAT
+ */
+QCBORError
+QCBORDecode_ExpMantissaTagCB(QCBORDecodeContext *pDecodeCtx,
+                             void               *pTagDecodersContext,
+                             uint64_t            uTagNumber,
+                             QCBORItem          *pDecodedItem);
+
+
+
+
+/* ------------------------------------------------------------------------
+ * Inline implementations of public functions defined above.
+ * ---- */
+#ifndef QCBOR_DISABLE_TAGS
+static inline void
+QCBORDecode_InstallTagDecoders(QCBORDecodeContext                *pMe,
+                               const struct QCBORTagDecoderEntry *pTagDecoderTable,
+                               void                              *pTagDecodersContext)
+{
+   pMe->pTagDecoderTable    = pTagDecoderTable;
+   pMe->pTagDecodersContext = pTagDecodersContext;
+}
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+#endif /* qcbor_tag_decode_h */
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index 4a7970f..46b66c6 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,4 +1,4 @@
-/* ==========================================================================
+/*==============================================================================
  * Copyright (c) 2016-2018, The Linux Foundation.
  * Copyright (c) 2018-2024, Laurence Lundblade.
  * All rights reserved.
@@ -46,6 +46,11 @@
  --------    ----         ---------------------------------------------------
  08/08/2024  llundblade   Add UsefulOutBuf_SubString().
  21/05/2024  llundblade   Comment formatting and some code tidiness.
+ 1/7/2024    llundblade   Add UsefulInputBuf_Compare().
+ 28/02/2022  llundblade   Rearrange UsefulOutBuf_Compare().
+ 19/11/2023  llundblade   Add UsefulOutBuf_GetOutput().
+ 19/11/2023  llundblade   Add UsefulOutBuf_Swap().
+ 19/11/2023  llundblade   Add UsefulOutBuf_Compare().
  19/12/2022  llundblade   Don't pass NULL to memmove when adding empty data.
  4/11/2022   llundblade   Add GetOutPlace and Advance to UsefulOutBuf
  3/6/2021    mcr/llundblade  Fix warnings related to --Wcast-qual
@@ -156,6 +161,24 @@
 
 /*
  * Public function -- see UsefulBuf.h
+ */
+UsefulBufC
+UsefulBuf_SkipLeading(UsefulBufC String, uint8_t uByte)
+{
+   for(;String.len; String.len--) {
+      if(*(const uint8_t *)String.ptr != uByte) {
+         break;
+      }
+      String.ptr = (const uint8_t *)String.ptr + 1;
+   }
+
+   return String;
+}
+
+
+
+/*
+ * Public function -- see UsefulBuf.h
  *
  * Code Reviewers: THIS FUNCTION DOES POINTER MATH
  */
@@ -471,3 +494,158 @@
    pMe->cursor += uAmount;
    return result;
 }
+
+
+/*
+ * Public function -- see UsefulBuf.h
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+int
+UsefulInputBuf_Compare(UsefulInputBuf *pUInBuf,
+                       const size_t    uOffset1,
+                       const size_t    uLen1,
+                       const size_t    uOffset2,
+                       const size_t    uLen2)
+{
+   UsefulBufC UB1;
+   UsefulBufC UB2;
+
+   const size_t uInputSize = UsefulInputBuf_GetBufferLength(pUInBuf);
+
+   /* Careful length check that works even if uLen1 + uOffset1 > SIZE_MAX */
+   if(uOffset1 > uInputSize || uLen1 > uInputSize - uOffset1) {
+      return 1;
+   }
+   UB1.ptr = (const uint8_t *)pUInBuf->UB.ptr + uOffset1;
+   UB1.len = uLen1;
+
+   /* Careful length check that works even if uLen2 + uOffset2 > SIZE_MAX */
+   if(uOffset2 > uInputSize || uLen2 > uInputSize - uOffset2) {
+      return -1;
+   }
+   UB2.ptr = (const uint8_t *)pUInBuf->UB.ptr + uOffset2;
+   UB2.len = uLen2;
+
+   return UsefulBuf_Compare(UB1, UB2);
+}
+
+
+/*
+ * Public function -- see UsefulBuf.h
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+int UsefulOutBuf_Compare(UsefulOutBuf *pMe,
+                         const size_t uStart1, const size_t uLen1,
+                         const size_t uStart2, const size_t uLen2)
+{
+   const uint8_t *pBase;
+   const uint8_t *pEnd;
+   const uint8_t *p1;
+   const uint8_t *p2;
+   const uint8_t *p1End;
+   const uint8_t *p2End;
+   int            uComparison;
+
+   pBase = pMe->UB.ptr;
+   pEnd = (const uint8_t *)pBase + pMe->data_len;
+   p1   = pBase + uStart1;
+   p2   = pBase + uStart2;
+   p1End = p1 + uLen1;
+   p2End = p2 + uLen2;
+
+   uComparison = 0;
+   while(p1 < pEnd && p2 < pEnd && p1 < p1End && p2 < p2End) {
+      uComparison = *p2 - *p1;
+      if(uComparison != 0) {
+         break;;
+      }
+      p1++;
+      p2++;
+   }
+
+   if(uComparison == 0 && p1 != p1End && p2 != p2End) {
+      if(uLen1 > uLen2) {
+         uComparison = 1;
+      } else if(uLen2 < uLen1){
+         uComparison = -1;
+      } else  {
+         return 0;
+      }
+   }
+
+   return uComparison;
+}
+
+
+
+/**
+ * @brief Reverse order of bytes in a buffer.
+ *
+ * This reverses bytes starting at pStart, up to, but not including
+ * the byte at pEnd
+ */
+static void
+UsefulOutBuf_Private_ReverseBytes(uint8_t *pStart, uint8_t *pEnd)
+{
+   uint8_t uTmp;
+
+   while(pStart < pEnd) {
+      pEnd--;
+      uTmp    = *pStart;
+      *pStart = *pEnd;
+      *pEnd   = uTmp;
+      pStart++;
+   }
+}
+
+
+/*
+ * Public function -- see UsefulBuf.h
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+void UsefulOutBuf_Swap(UsefulOutBuf *pMe, size_t uStartOffset, size_t uPivotOffset, size_t uEndOffset)
+{
+   uint8_t *pBase;
+
+   if(uStartOffset > pMe->data_len || uPivotOffset > pMe->data_len || uEndOffset > pMe->data_len) {
+      return;
+   }
+
+   if(uStartOffset > uPivotOffset || uStartOffset > uEndOffset || uPivotOffset > uEndOffset) {
+      return;
+   }
+
+   /* This is the "reverse" algorithm to swap two memory regions */
+   pBase = pMe->UB.ptr;
+   UsefulOutBuf_Private_ReverseBytes(pBase + uStartOffset, pBase + uPivotOffset);
+   UsefulOutBuf_Private_ReverseBytes(pBase + uPivotOffset, pBase + uEndOffset);
+   UsefulOutBuf_Private_ReverseBytes(pBase + uStartOffset, pBase + uEndOffset);
+}
+
+
+/*
+ * Public function -- see UsefulBuf.h
+ */
+UsefulBufC
+UsefulOutBuf_OutUBufOffset(UsefulOutBuf *pMe, size_t uOffset)
+{
+   UsefulBufC ReturnValue;
+
+   ReturnValue = UsefulOutBuf_OutUBuf(pMe);
+
+   if(UsefulBuf_IsNULLC(ReturnValue)) {
+      return NULLUsefulBufC;
+   }
+
+   if(uOffset >= ReturnValue.len) {
+      return NULLUsefulBufC;
+   }
+
+   ReturnValue.ptr = (const uint8_t *)ReturnValue.ptr + uOffset;
+   ReturnValue.len -= uOffset;
+
+   return ReturnValue;
+}
diff --git a/src/ieee754.c b/src/ieee754.c
index 1744368..506d5e8 100644
--- a/src/ieee754.c
+++ b/src/ieee754.c
@@ -1,5 +1,5 @@
 /* ==========================================================================
- * ieee754.c -- floating-point conversion between half, double & single-precision
+ * ieee754.c -- floating-point conversion for half, double & single-precision
  *
  * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved.
  * Copyright (c) 2021, Arm Limited. All rights reserved.
@@ -11,20 +11,14 @@
  * Created on 7/23/18
  * ========================================================================== */
 
-/*
- * Include before QCBOR_DISABLE_PREFERRED_FLOAT is checked as
- * QCBOR_DISABLE_PREFERRED_FLOAT might be defined in qcbor/qcbor_common.h
- */
 #include "qcbor/qcbor_common.h"
 
-#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
-
 #include "ieee754.h"
 #include <string.h> /* For memcpy() */
 
 
 /*
- * This code has long lines and is easier to read because of
+ * This has long lines and is easier to read because of
  * them. Some coding guidelines prefer 80 column lines (can they not
  * afford big displays?).
  *
@@ -164,6 +158,10 @@
    return u64;
 }
 
+
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+
+
 static inline double
 CopyUint64ToDouble(uint64_t u64)
 {
@@ -184,7 +182,7 @@
 
 
 /**
- * @brief Assemble sign, significand and exponent into single precision float.
+ * @brief Assemble sign, significand and exponent into double precision float.
  *
  * @param[in] uDoubleSign              0 if positive, 1 if negative
  * @pararm[in] uDoubleSignificand      Bits of the significand
@@ -193,6 +191,7 @@
  * This returns the bits for a single-precision float, a binary64
  * as specified in IEEE754.
  */
+// TODO: make the sign and exponent type int?
 static double
 IEEE754_AssembleDouble(uint64_t uDoubleSign,
                        uint64_t uDoubleSignificand,
@@ -208,6 +207,7 @@
 }
 
 
+/* Public function; see ieee754.h */
 double
 IEEE754_HalfToDouble(uint16_t uHalfPrecision)
 {
@@ -315,7 +315,7 @@
 
 /*  Public function; see ieee754.h */
 IEEE754_union
-IEEE754_SingleToHalf(float f)
+IEEE754_SingleToHalf(const float f, const int bNoNaNPayload)
 {
    IEEE754_union result;
    uint32_t      uDroppedBits;
@@ -357,28 +357,36 @@
          result.uSize  = IEEE754_UNION_IS_HALF;
          result.uValue = IEEE754_AssembleHalf(uSingleSign, 0, HALF_EXPONENT_INF_OR_NAN);
       } else {
-         /* The NaN can only be converted if no payload bits are lost
-          * per RFC 8949 section 4.1 that defines Preferred
-          * Serializaton. Note that Deterministically Encode CBOR in
-          * section 4.2 allows for some variation of this rule, but at
-          * the moment this implementation is of Preferred
-          * Serialization, not CDE. As of December 2023, we are also
-          * expecting an update to CDE. This code may need to be
-          * updated for CDE.
-          */
-         uDroppedBits = uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS);
-         if(uDroppedBits == 0) {
-            /* --- IS CONVERTABLE NAN --- */
-            uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+         if(bNoNaNPayload) {
+            /* --- REQUIRE CANNONICAL NAN --- */
             result.uSize  = IEEE754_UNION_IS_HALF;
             result.uValue = IEEE754_AssembleHalf(uSingleSign,
-                                                 uHalfSignificand,
+                                                 HALF_QUIET_NAN_BIT,
                                                  HALF_EXPONENT_INF_OR_NAN);
-
          } else {
-            /* --- IS UNCONVERTABLE NAN --- */
-            result.uSize   = IEEE754_UNION_IS_SINGLE;
-            result.uValue  = uSingle;
+            /* The NaN can only be converted if no payload bits are lost
+             * per RFC 8949 section 4.1 that defines Preferred
+             * Serializaton. Note that Deterministically Encode CBOR in
+             * section 4.2 allows for some variation of this rule, but at
+             * the moment this implementation is of Preferred
+             * Serialization, not CDE. As of December 2023, we are also
+             * expecting an update to CDE. This code may need to be
+             * updated for CDE.
+             */
+            uDroppedBits = uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS);
+            if(uDroppedBits == 0) {
+               /* --- IS CONVERTABLE NAN --- */
+               uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+               result.uSize  = IEEE754_UNION_IS_HALF;
+               result.uValue = IEEE754_AssembleHalf(uSingleSign,
+                                                    uHalfSignificand,
+                                                    HALF_EXPONENT_INF_OR_NAN);
+
+            } else {
+               /* --- IS UNCONVERTABLE NAN --- */
+               result.uSize   = IEEE754_UNION_IS_SINGLE;
+               result.uValue  = uSingle;
+            }
          }
       }
    } else {
@@ -495,7 +503,7 @@
  * This handles all subnormals and NaN payloads.
  */
 static IEEE754_union
-IEEE754_DoubleToSingle(double d)
+IEEE754_DoubleToSingle(const double d)
 {
    IEEE754_union Result;
    int64_t       nExponentDifference;
@@ -514,7 +522,6 @@
    const uint64_t uDoubleSign             = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT;
    const uint64_t uDoubleSignificand      = uDouble & DOUBLE_SIGNIFICAND_MASK;
 
-
     if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) {
         if(uDoubleSignificand == 0) {
             /* --- IS ZERO --- */
@@ -619,7 +626,9 @@
 
 /* Public function; see ieee754.h */
 IEEE754_union
-IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision)
+IEEE754_DoubleToSmaller(const double d,
+                        const int    bAllowHalfPrecision,
+                        const int    bNoNanPayload)
 {
    IEEE754_union result;
 
@@ -629,15 +638,313 @@
       /* Cast to uint32_t is OK, because value was just successfully
        * converted to single. */
       float uSingle = CopyUint32ToSingle((uint32_t)result.uValue);
-      result = IEEE754_SingleToHalf(uSingle);
+      result = IEEE754_SingleToHalf(uSingle, bNoNanPayload);
    }
 
    return result;
 }
 
 
-#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
 
-int ieee754_dummy_place_holder;
+/* This returns 64 minus the number of zero bits on the right. It is
+ * is the amount of precision in the 64-bit significand passed in.
+ * When used for 52 and 23-bit significands, subtract 12 and 41
+ * to get their precision.
+ *
+ * The value returned is for a *normalized* number like the
+ * significand of a double. When used for precision for a non-normalized
+ * number like a uint64_t, further computation is required.
+ *
+ * If the significand is 0, then 0 is returned as the precision.*/
+static int
+IEEE754_Private_CountPrecisionBits(uint64_t uSignigicand)
+{
+   int      nNonZeroBitsCount;
+   uint64_t uMask;
+
+   for(nNonZeroBitsCount = 64; nNonZeroBitsCount > 0; nNonZeroBitsCount--) {
+      uMask = 0x01UL << (64 - nNonZeroBitsCount);
+      if(uMask & uSignigicand) {
+         break;
+      }
+   }
+
+   return nNonZeroBitsCount;
+}
+
+
+
+/* Public function; see ieee754.h */
+struct IEEE754_ToInt
+IEEE754_DoubleToInt(const double d)
+{
+   int64_t              nPrecisionBits;
+   struct IEEE754_ToInt Result;
+   uint64_t             uInteger;
+
+   /* Pull the three parts out of the double-precision float. Most
+    * work is done with uint64_t which helps avoid integer promotions
+    * and static analyzer complaints.
+    */
+   const uint64_t uDouble                 = CopyDoubleToUint64(d);
+   const uint64_t uDoubleBiasedExponent   = (uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT;
+   /* Cast safe because of mask above; exponents < DOUBLE_EXPONENT_MAX */
+   const int64_t  nDoubleUnbiasedExponent = (int64_t)uDoubleBiasedExponent - DOUBLE_EXPONENT_BIAS;
+   const uint64_t uDoubleSignificand      = uDouble & DOUBLE_SIGNIFICAND_MASK;
+   const uint64_t bIsNegative             = uDouble & DOUBLE_SIGN_MASK;
+
+   if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) {
+      if(uDoubleSignificand == 0) {
+         /* --- POSITIVE AND NEGATIVE ZERO --- */
+         Result.integer.un_signed = 0;
+         Result.type              = IEEE754_ToInt_IS_UINT;
+      } else {
+         /* --- SUBNORMAL --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      }
+   } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
+      if(uDoubleSignificand != 0) {
+         /* --- NAN --- */
+         Result.type = IEEE754_ToInt_NaN; /* dCBOR doesn't care about payload */
+      } else  {
+         /* --- INFINITY --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      }
+   } else if(nDoubleUnbiasedExponent < 0) {
+      /* --- Exponent out of range --- */
+      Result.type = IEEE754_ToInt_NO_CONVERSION;
+   } else if(nDoubleUnbiasedExponent >= 64) {
+      if(nDoubleUnbiasedExponent == 64 && uDoubleSignificand == 0 && bIsNegative) {
+         /* Very special case for -18446744073709551616.0 */
+         Result.integer.un_signed = 0; /* No negative 0, use it to indicate 2^64 */
+         Result.type              = IEEE754_ToInt_IS_65BIT_NEG;
+      } else {
+         /* --- Exponent out of range --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      }
+   } else {
+      /* Conversion only fails when the input is too large or is not a
+       * whole number, never because of lack of precision because
+       * 64-bit integers always have more precision than the 52-bits
+       * of a double.
+       */
+      nPrecisionBits = IEEE754_Private_CountPrecisionBits(uDoubleSignificand) -
+                               (64-DOUBLE_NUM_SIGNIFICAND_BITS);
+
+      if(nPrecisionBits && nPrecisionBits > nDoubleUnbiasedExponent) {
+         /* --- Not a whole number --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      } else {
+         /* --- CONVERTABLE WHOLE NUMBER --- */
+         /* Add in the one that is implied in normal floats */
+         uInteger = uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS);
+         /* Factor in the exponent */
+         if(nDoubleUnbiasedExponent < DOUBLE_NUM_SIGNIFICAND_BITS) {
+            /* Numbers less than 2^52 with up to 52 significant bits */
+            uInteger >>= DOUBLE_NUM_SIGNIFICAND_BITS - nDoubleUnbiasedExponent;
+         } else {
+            /* Numbers greater than 2^52 with at most 52 significant bits */
+            uInteger <<= nDoubleUnbiasedExponent - DOUBLE_NUM_SIGNIFICAND_BITS;
+         }
+         if(bIsNegative) {
+            /* Cast safe because exponent range check above */
+            if(nDoubleUnbiasedExponent == 63) {
+               Result.integer.un_signed = uInteger;
+               Result.type              = IEEE754_ToInt_IS_65BIT_NEG;
+            } else {
+               Result.integer.is_signed = -((int64_t)uInteger);
+               Result.type              = IEEE754_ToInt_IS_INT;
+            }
+         } else {
+            Result.integer.un_signed = uInteger;
+            Result.type              = IEEE754_ToInt_IS_UINT;
+         }
+      }
+   }
+
+   return Result;
+}
+
+
+/* Public function; see ieee754.h */
+struct IEEE754_ToInt
+IEEE754_SingleToInt(const float f)
+{
+   int32_t              nPrecisionBits;
+   struct IEEE754_ToInt Result;
+   uint64_t             uInteger;
+
+   /* Pull the three parts out of the single-precision float. Most
+    * work is done with uint32_t which helps avoid integer promotions
+    * and static analyzer complaints.
+    */
+   const uint32_t uSingle                 = CopyFloatToUint32(f);
+   const uint32_t uSingleBiasedExponent   = (uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT;
+   /* Cast safe because of mask above; exponents < SINGLE_EXPONENT_MAX */
+   const int32_t  nSingleUnbiasedExponent = (int32_t)uSingleBiasedExponent - SINGLE_EXPONENT_BIAS;
+   const uint32_t uSingleleSignificand    = uSingle & SINGLE_SIGNIFICAND_MASK;
+   const uint64_t bIsNegative             = uSingle & SINGLE_SIGN_MASK;
+
+
+   if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) {
+      if(uSingleleSignificand == 0 && !(uSingle & SINGLE_SIGN_MASK)) {
+         /* --- POSITIVE AND NEGATIVE ZERO --- */
+         Result.integer.un_signed = 0;
+         Result.type              = IEEE754_ToInt_IS_UINT;
+      } else {
+         /* --- Subnormal --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      }
+   } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
+      /* --- NAN or INFINITY --- */
+      if(uSingleleSignificand != 0) {
+         Result.type = IEEE754_ToInt_NaN; /* dCBOR doesn't care about payload */
+      } else  {
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      }
+   } else if(nSingleUnbiasedExponent < 0) {
+      /* --- Exponent out of range --- */
+       Result.type = IEEE754_ToInt_NO_CONVERSION;
+   } else if(nSingleUnbiasedExponent >= 64) {
+      if(nSingleUnbiasedExponent == 64 && uSingleleSignificand == 0 && bIsNegative) {
+         /* Very special case for -18446744073709551616.0 */
+         Result.integer.un_signed = 0; /* No negative 0, use it to indicate 2^64 */
+         Result.type              = IEEE754_ToInt_IS_65BIT_NEG;
+      } else {
+         /* --- Exponent out of range --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      }
+    } else {
+      /* Conversion only fails when the input is too large or is not a
+       * whole number, never because of lack of precision because
+       * 64-bit integers always have more precision than the 23 bits
+       * of a single.
+       */
+       nPrecisionBits = IEEE754_Private_CountPrecisionBits(uSingleleSignificand) -
+                           (64 - SINGLE_NUM_SIGNIFICAND_BITS);
+
+      if(nPrecisionBits && nPrecisionBits > nSingleUnbiasedExponent) {
+         /* --- Not a whole number --- */
+         Result.type = IEEE754_ToInt_NO_CONVERSION;
+      } else {
+         /* --- CONVERTABLE WHOLE NUMBER --- */
+         /* Add in the one that is implied in normal floats */
+         uInteger = uSingleleSignificand + (1ULL << SINGLE_NUM_SIGNIFICAND_BITS);
+         /* Factor in the exponent */
+         if(nSingleUnbiasedExponent < SINGLE_NUM_SIGNIFICAND_BITS) {
+            /* Numbers less than 2^23 with up to 23 significant bits */
+            uInteger >>= SINGLE_NUM_SIGNIFICAND_BITS - nSingleUnbiasedExponent;
+         } else {
+            /* Numbers greater than 2^23 with at most 23 significant bits*/
+            uInteger <<= nSingleUnbiasedExponent - SINGLE_NUM_SIGNIFICAND_BITS;
+         }
+         if(bIsNegative) {
+         /* Cast safe because exponent range check above */
+            if(nSingleUnbiasedExponent == 63) {
+               Result.integer.un_signed = uInteger;
+               Result.type              = IEEE754_ToInt_IS_65BIT_NEG;
+            } else {
+               Result.integer.is_signed = -((int64_t)uInteger);
+               Result.type              = IEEE754_ToInt_IS_INT;
+            }
+         } else {
+            Result.integer.un_signed = uInteger;
+            Result.type              = IEEE754_ToInt_IS_UINT;
+         }
+      }
+   }
+
+   return Result;
+}
+
+
+
+/* Public function; see ieee754.h */
+double
+IEEE754_UintToDouble(const uint64_t uInt, const int uIsNegative)
+{
+   int      nDoubleUnbiasedExponent;
+   uint64_t uDoubleSignificand;
+   int      nPrecisionBits;
+
+   if(uInt == 0) {
+      uDoubleSignificand      = 0;
+      nDoubleUnbiasedExponent = DOUBLE_EXPONENT_ZERO;
+
+   } else  {
+      /* Figure out the exponent and normalize the significand. This is
+       * done by shifting out all leading zero bits and counting them. If
+       * none are shifted out, the exponent is 63. */
+      uDoubleSignificand = uInt;
+      nDoubleUnbiasedExponent = 63;
+      while(1) {
+         if(uDoubleSignificand & 0x8000000000000000UL) {
+            break;
+         }
+         uDoubleSignificand <<= 1;
+         nDoubleUnbiasedExponent--;
+      };
+
+      /* Position significand correctly for a double. Only shift 63 bits
+       * because of the 1 that is present by implication in IEEE 754.*/
+      uDoubleSignificand >>= 63 - DOUBLE_NUM_SIGNIFICAND_BITS;
+
+      /* Subtract 1 which is present by implication in IEEE 754 */
+      uDoubleSignificand -= 1ULL << (DOUBLE_NUM_SIGNIFICAND_BITS);
+
+      nPrecisionBits = IEEE754_Private_CountPrecisionBits(uInt) - (64 - nDoubleUnbiasedExponent);
+
+      if(nPrecisionBits > DOUBLE_NUM_SIGNIFICAND_BITS) {
+         /* Will lose precision if converted */
+         return IEEE754_UINT_TO_DOUBLE_OOB;
+      }
+   }
+
+   return IEEE754_AssembleDouble((uint64_t)uIsNegative,
+                                 uDoubleSignificand,
+                                 nDoubleUnbiasedExponent);
+}
 
 #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+
+
+
+/* Public function; see ieee754.h */
+int
+IEEE754_DoubleHasNaNPayload(const double d)
+{
+   const uint64_t uDouble                 = CopyDoubleToUint64(d);
+   const uint64_t uDoubleBiasedExponent   = (uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT;
+   /* Cast safe because of mask above; exponents < DOUBLE_EXPONENT_MAX */
+   const int64_t  nDoubleUnbiasedExponent = (int64_t)uDoubleBiasedExponent - DOUBLE_EXPONENT_BIAS;
+   const uint64_t uDoubleSignificand      = uDouble & DOUBLE_SIGNIFICAND_MASK;
+
+   if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN &&
+      uDoubleSignificand != 0 &&
+      uDoubleSignificand != DOUBLE_QUIET_NAN_BIT) {
+      return 1;
+   } else {
+      return 0;
+   }
+}
+
+
+/* Public function; see ieee754.h */
+int
+IEEE754_SingleHasNaNPayload(const float f)
+{
+   const uint32_t uSingle                 = CopyFloatToUint32(f);
+   const uint32_t uSingleBiasedExponent   = (uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT;
+   /* Cast safe because of mask above; exponents < SINGLE_EXPONENT_MAX */
+   const int32_t  nSingleUnbiasedExponent = (int32_t)uSingleBiasedExponent - SINGLE_EXPONENT_BIAS;
+   const uint32_t uSingleSignificand      = uSingle & SINGLE_SIGNIFICAND_MASK;
+
+   if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN &&
+      uSingleSignificand != 0 &&
+      uSingleSignificand != SINGLE_QUIET_NAN_BIT) {
+      return 1;
+   } else {
+      return 0;
+   }
+}
+
diff --git a/src/ieee754.h b/src/ieee754.h
index 3013dc6..9d3a8f3 100644
--- a/src/ieee754.h
+++ b/src/ieee754.h
@@ -10,11 +10,11 @@
  * Created on 7/23/18
  * ========================================================================== */
 
-#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
 
 #ifndef ieee754_h
 #define ieee754_h
 
+
 #include <stdint.h>
 
 
@@ -25,6 +25,9 @@
  * smaller representation (e.g., double to single) that does not lose
  * precision for CBOR preferred serialization.
  *
+ * This also implements conversion of floats to whole numbers as
+ * is required for dCBOR.
+ *
  * This implementation works entirely with shifts and masks and does
  * not require any floating-point HW or library.
  *
@@ -51,6 +54,7 @@
  * conversion. This version is reduced to what is needed for CBOR.
  */
 
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
 
 /**
  * @brief Convert half-precision float to double-precision float.
@@ -87,6 +91,23 @@
 } IEEE754_union;
 
 
+/** Holds result of an attempt to convert a floating-point
+ * number to an int64_t or uint64_t.
+ */
+struct IEEE754_ToInt {
+   enum {IEEE754_ToInt_IS_INT,
+         IEEE754_ToInt_IS_UINT,
+         IEEE754_ToInt_IS_65BIT_NEG,
+         IEEE754_ToInt_NO_CONVERSION,
+         IEEE754_ToInt_NaN
+   } type;
+   union {
+      uint64_t un_signed;
+      int64_t  is_signed;
+   } integer;
+};
+
+
 /**
  * @brief Convert a double to either single or half-precision.
  *
@@ -102,7 +123,7 @@
  * This handles all subnormals and NaN payloads.
  */
 IEEE754_union
-IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision);
+IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision, int bNoNaNPayload);
 
 
 /**
@@ -118,9 +139,108 @@
  * This handles all subnormals and NaN payloads.
  */
 IEEE754_union
-IEEE754_SingleToHalf(float f);
+IEEE754_SingleToHalf(float f, int bNoNanPayloads);
+
+
+/**
+ * @brief Convert a double-precision float to integer if whole number
+ *
+ * @param[in] d  The value to convert.
+ *
+ * @returns Either converted number or conversion status.
+ *
+ * If the value is a whole number that will fit either in a uint64_t
+ * or an int64_t, it is converted. If it is a NaN, then there is no
+ * conversion and and the fact that it is a NaN is indicated in the
+ * returned structure.  If it can't be converted, then that is
+ * indicated in the returned structure.
+ *
+ * This always returns postive numbers as a uint64_t even if they will
+ * fit in an int64_t.
+ *
+ * This never fails becaue of precision, but may fail because of range.
+ */
+struct IEEE754_ToInt
+IEEE754_DoubleToInt(double d);
+
+
+/**
+ * @brief Convert a single-precision float to integer if whole number
+ *
+ * @param[in] f  The value to convert.
+ *
+ * @returns Either converted number or conversion status.
+ *
+ * If the value is a whole number that will fit either in a uint64_t
+ * or an int64_t, it is converted. If it is a NaN, then there is no
+ * conversion and and the fact that it is a NaN is indicated in the
+ * returned structure.  If it can't be converted, then that is
+ * indicated in the returned structure.
+ *
+ * This always returns postive numbers as a uint64_t even if they will
+ * fit in an int64_t.
+ *
+ * This never fails becaue of precision, but may fail because of range.
+ */
+struct IEEE754_ToInt
+IEEE754_SingleToInt(float f);
+
+
+/**
+ * @brief Convert an unsigned integer to a double with no precision loss.
+ *
+ * @param[in] uInt  The value to convert.
+ * @param[in] uIsNegative   0 if postive, 1 if negative.
+ *
+ * @returns Either the converted number or 0.5 if no conversion.
+ *
+ * The conversion will fail if the input can not be represented in the
+ * 52 bits or precision that a double has. 0.5 is returned to indicate
+ * no conversion. It is out-of-band from non-error results, because
+ * all non-error results are whole integers.
+ */
+#define IEEE754_UINT_TO_DOUBLE_OOB 0.5
+double
+IEEE754_UintToDouble(uint64_t uInt, int uIsNegative);
+
+
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+
+/**
+ * @brief Tests whether NaN is "quiet" vs having a payload.
+ *
+ * @param[in] dNum   Double number to test.
+ *
+ * @returns 0 if a quiet NaN, 1 if it has a payload.
+ *
+ * A quiet NaN is usually represented as 0x7ff8000000000000. That is
+ * the significand bits are 0x8000000000000. If the significand bits
+ * are other than 0x8000000000000 it is considered to have a NaN
+ * payload.
+ *
+ * Note that 0x7ff8000000000000 is not specified in a standard, but it
+ * is commonly implemented and chosen by CBOR as the best way to
+ * represent a NaN.
+ */
+int
+IEEE754_DoubleHasNaNPayload(double dNum);
+
+
+
+/**
+ * @brief Tests whether NaN is "quiet" vs having a payload.
+ *
+ * @param[in] fNum   Float number to test.
+ *
+ * @returns 0 if a quiet NaN, 1 if it has a payload.
+ *
+ * See IEEE754_DoubleHasNaNPayload(). A single precision quiet NaN
+ * is 0x7fc00000.
+ */
+int
+IEEE754_SingleHasNaNPayload(float fNum);
 
 
 #endif /* ieee754_h */
 
-#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 0f4d5c0..2992ce1 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -34,6 +34,7 @@
 
 #include "qcbor/qcbor_decode.h"
 #include "qcbor/qcbor_spiffy_decode.h"
+#include "qcbor/qcbor_tag_decode.h"
 #include "ieee754.h" /* Does not use math.h */
 
 #ifndef QCBOR_DISABLE_FLOAT_HW_USE
@@ -666,9 +667,26 @@
    /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
     * GetNext_TaggedItem() and MapTagNumber(). */
    memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
+
+   pMe->uTagNumberCheckOffset = SIZE_MAX;
 }
 
 
+/*
+ * Public function, see header file
+ */
+void
+QCBORDecode_CompatibilityV1(QCBORDecodeContext *pMe)
+{
+   pMe->uDecodeMode |= QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS;
+#ifndef QCBOR_DISABLE_TAGS
+   QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
+#endif /* ! QCBOR_DISABLE_TAGS */
+}
+
+
+
+
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
 
 /*
@@ -689,19 +707,6 @@
 
 
 
-/*
- * Deprecated public function, see header file
- */
-void
-QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext   *pMe,
-                                       const QCBORTagListIn *pTagList)
-{
-   /* This does nothing now. It is retained for backwards compatibility */
-   (void)pMe;
-   (void)pTagList;
-}
-
-
 
 
 /*
@@ -768,6 +773,7 @@
  * @brief Decode the CBOR head, the type and argument.
  *
  * @param[in] pUInBuf            The input buffer to read from.
+ * @param[in] bRequirePreferred  Require preferred serialization for argument.
  * @param[out] pnMajorType       The decoded major type.
  * @param[out] puArgument        The decoded argument.
  * @param[out] pnAdditionalInfo  The decoded Lower 5 bits of initial byte.
@@ -776,11 +782,10 @@
  * @retval QCBOR_ERR_HIT_END Unexpected end of input
  *
  * This decodes the CBOR "head" that every CBOR data item has. See
- * longer explaination of the head in documentation for
- * QCBOREncode_EncodeHead().
+ * longer description in QCBOREncode_EncodeHead().
  *
- * This does the network->host byte order conversion. The conversion
- * here also results in the conversion for floats in addition to that
+ * This does the network to host byte order conversion. The conversion
+ * here also provides the conversion for floats in addition to that
  * for lengths, tags and integer values.
  *
  * The int type is preferred to uint8_t for some variables as this
@@ -789,21 +794,21 @@
  */
 static QCBORError
 QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+                         bool            bRequirePreferred,
+#endif
                          int            *pnMajorType,
                          uint64_t       *puArgument,
                          int            *pnAdditionalInfo)
 {
    QCBORError uReturn;
+   uint64_t   uArgument;
 
-   /* Get the initial byte that every CBOR data item has and break it
-    * down. */
+   /* Get and break down initial byte that every CBOR data item has */
    const int nInitialByte    = (int)UsefulInputBuf_GetByte(pUInBuf);
    const int nTmpMajorType   = nInitialByte >> 5;
    const int nAdditionalInfo = nInitialByte & 0x1f;
 
-   /* Where the argument accumulates */
-   uint64_t uArgument;
-
    if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= 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.
@@ -813,14 +818,46 @@
       /* Loop getting all the bytes in the argument */
       uArgument = 0;
       for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
-         /* This shift and add gives the endian conversion. */
+         /* This shift-and-add gives the endian conversion. */
          uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
       }
+
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+      /* If requested, check that argument is in preferred form */
+      if(bRequirePreferred) {
+         uint64_t uMinArgument;
+
+         if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
+            if(uArgument < 24) {
+               uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
+               goto Done;
+            }
+         } else {
+            if(nTmpMajorType != CBOR_MAJOR_TYPE_SIMPLE) {
+               /* Check only if not a floating-point number */
+               int nArgLen = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE - 1];
+               uMinArgument = UINT64_MAX >> ((int)sizeof(uint64_t) - nArgLen) * 8;
+               if(uArgument <= uMinArgument) {
+                  uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
+                  goto Done;
+               }
+            }
+         }
+      }
+#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
+
    } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
       /* The reserved and thus-far unused additional info values */
       uReturn = QCBOR_ERR_UNSUPPORTED;
       goto Done;
    } else {
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+      if(bRequirePreferred && nAdditionalInfo == LEN_IS_INDEFINITE) {
+         uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
+         goto Done;
+      }
+#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
+
       /* Less than 24, additional info is argument or 31, an
        * indefinite-length.  No more bytes to get.
        */
@@ -858,12 +895,18 @@
  *
  * 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
+ * so. All integers in encoded CBOR are unsigned and the CBOR 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.
+ * integers up to 2^64 - 1 negative integers down to -2^64.  Note that
+ * negative numbers can be one more
+ * away from zero than positive because there is no negative zero.
+ *
+ * The "65-bit negs" are values CBOR can encode that can't fit
+ * into an int64_t or uint64_t. They decoded as a special type
+ * QCBOR_TYPE_65BIT_NEG_INT. Not that this type does NOT
+ * take into account the offset of one for CBOR negative integers.
+ * It must be applied to get the correct value. Applying this offset
+ * would overflow a uint64_t.
  */
 static QCBORError
 QCBOR_Private_DecodeInteger(const int      nMajorType,
@@ -890,19 +933,14 @@
 
    } else {
       if(uArgument <= INT64_MAX) {
-         /* CBOR's representation of negative numbers lines up with
-          * the two-compliment representation. A negative integer has
-          * one more in range than a positive integer. INT64_MIN is
-          * equal to (-INT64_MAX) - 1.
-          */
+         /* INT64_MIN is one further away from 0 than INT64_MAX
+          * so the -1 here doesn't overflow. */
          pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
          pDecodedItem->uDataType = QCBOR_TYPE_INT64;
 
       } else {
-         /* C can't represent a negative integer in this range so it
-          * is an error.
-          */
-         uReturn = QCBOR_ERR_INT_OVERFLOW;
+         pDecodedItem->val.uint64 = uArgument;
+         pDecodedItem->uDataType  = QCBOR_TYPE_65BIT_NEG_INT;
       }
    }
 
@@ -1016,7 +1054,7 @@
 /**
  * @brief Decode array or map.
  *
- * @param[in] uMode            Decoder mode.
+ * @param[in] uDecodeMode3Bit            Decoder mode.
  * @param[in] nMajorType       Whether it is a byte or text string.
  * @param[in] uItemCount       The length of the string.
  * @param[in] nAdditionalInfo  Whether it is an indefinite-length.
@@ -1035,7 +1073,7 @@
  * QCBOR_DISABLE_NON_INTEGER_LABELS.
  */
 static QCBORError
-QCBOR_Private_DecodeArrayOrMap(const uint8_t  uMode,
+QCBOR_Private_DecodeArrayOrMap(const uint8_t  uDecodeMode3Bit,
                                const int      nMajorType,
                                uint64_t       uItemCount,
                                const int      nAdditionalInfo,
@@ -1053,11 +1091,11 @@
    #endif
    pDecodedItem->uDataType = (uint8_t)nMajorType;
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-   if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
+   if(uDecodeMode3Bit == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
       pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
    }
 #else
-   (void)uMode;
+   (void)uDecodeMode3Bit;
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
 
    uReturn = QCBOR_SUCCESS;
@@ -1076,7 +1114,7 @@
 
       } else {
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-         if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
+         if(uDecodeMode3Bit == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
             /* ------ Map as array ------ */
             uItemCount *= 2;
          }
@@ -1105,16 +1143,16 @@
  * error in nAdditionalInfo.
  */
 static QCBORError
-QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
-                        const int      nAdditionalInfo,
-                        QCBORItem     *pDecodedItem)
+QCBOR_Private_DecodeTagNumber(const uint64_t uTagNumber,
+                              const int      nAdditionalInfo,
+                              QCBORItem     *pDecodedItem)
 {
 #ifndef QCBOR_DISABLE_TAGS
    if(nAdditionalInfo == LEN_IS_INDEFINITE) {
       return QCBOR_ERR_BAD_INT;
    } else {
-      pDecodedItem->val.uTagV = uTagNumber;
-      pDecodedItem->uDataType = QCBOR_TYPE_TAG;
+      pDecodedItem->val.uTagNumber = uTagNumber;
+      pDecodedItem->uDataType = QCBOR_TYPE_TAG_NUMBER;
       return QCBOR_SUCCESS;
    }
 #else /* QCBOR_DISABLE_TAGS */
@@ -1126,6 +1164,205 @@
 }
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+
+#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+
+static QCBORError
+QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode3Bit)
+{
+   struct IEEE754_ToInt ToInt;
+
+   /* Only need to check for conversion to integer because
+    * half-precision is always preferred serialization. Don't
+    * need special checker for half-precision because whole
+    * numbers always convert perfectly from half to double.
+    *
+    * This catches half-precision with NaN payload too.
+    *
+    * The only thing allowed here is a double/half-precision that
+    * can't be converted to anything but a double.
+    */
+   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
+      ToInt = IEEE754_DoubleToInt(d);
+      if(ToInt.type != QCBOR_TYPE_DOUBLE) {
+         return QCBOR_ERR_DCBOR_CONFORMANCE;
+      }
+   }
+
+   return QCBOR_SUCCESS;
+}
+
+
+static QCBORError
+QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode3Bit)
+{
+   struct IEEE754_ToInt ToInt;
+   IEEE754_union        ToSmaller;
+
+   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
+      /* See if it could have been encoded as an integer */
+      ToInt = IEEE754_SingleToInt(f);
+      if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
+         return QCBOR_ERR_DCBOR_CONFORMANCE;
+      }
+
+      /* Make sure there is no NaN payload */
+      if(IEEE754_SingleHasNaNPayload(f)) {
+         return QCBOR_ERR_DCBOR_CONFORMANCE;
+      }
+   }
+
+   /* See if it could have been encoded shorter */
+   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
+      ToSmaller = IEEE754_SingleToHalf(f, true);
+      if(ToSmaller.uSize != sizeof(float)) {
+         return QCBOR_ERR_PREFERRED_CONFORMANCE;
+      }
+   }
+
+   return QCBOR_SUCCESS;
+}
+
+
+static QCBORError
+QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
+{
+   struct IEEE754_ToInt ToInt;
+   IEEE754_union        ToSmaller;
+
+   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
+      /* See if it could have been encoded as an integer */
+      ToInt = IEEE754_DoubleToInt(d);
+      if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
+         return QCBOR_ERR_DCBOR_CONFORMANCE;
+      }
+      /* Make sure there is no NaN payload */
+      if(IEEE754_DoubleHasNaNPayload(d)) {
+         return QCBOR_ERR_DCBOR_CONFORMANCE;
+      }
+   }
+
+   /* See if it could have been encoded shorter */
+   if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
+      ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
+      if(ToSmaller.uSize != sizeof(double)) {
+         return QCBOR_ERR_PREFERRED_CONFORMANCE;
+      }
+   }
+
+   return QCBOR_SUCCESS;
+}
+#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+static QCBORError
+QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode3Bit)
+{
+   (void)f;
+   if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
+      return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
+   } else {
+      return QCBOR_SUCCESS;
+   }
+}
+
+static QCBORError
+QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
+{
+   (void)d;
+   if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
+      return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
+   } else {
+      return QCBOR_SUCCESS;
+   }
+}
+#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+
+/*
+ * Decode a float
+ */
+static QCBORError
+QCBOR_Private_DecodeFloat(const uint8_t  uDecodeMode3Bit,
+                          const int      nAdditionalInfo,
+                          const uint64_t uArgument,
+                          QCBORItem     *pDecodedItem)
+{
+   QCBORError uReturn = QCBOR_SUCCESS;
+   float      single;
+
+   (void)single; /* Avoid unused error from various #ifndefs */
+
+   switch(nAdditionalInfo) {
+      case HALF_PREC_FLOAT: /* 25 */
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         /* Half-precision is returned as a double. The cast to
+          * uint16_t is safe because the encoded value was 16 bits. It
+          * was widened to 64 bits to be passed in here.
+          */
+         pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
+         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+
+         uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
+         if(uReturn != QCBOR_SUCCESS) {
+            break;
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
+         break;
+
+      case SINGLE_PREC_FLOAT: /* 26 */
+         /* Single precision is normally returned as a double since
+          * double is widely supported, there is no loss of precision,
+          * it makes it easy for the caller in most cases and it can
+          * be converted back to single with no loss of precision
+          *
+          * The cast to uint32_t is safe because the encoded value was
+          * 32 bits. It was widened to 64 bits to be passed in here.
+          */
+         single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
+         uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode3Bit);
+         if(uReturn != QCBOR_SUCCESS) {
+            break;
+         }
+
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+         /* In the normal case, use HW to convert float to
+          * double. */
+         pDecodedItem->val.dfnum = (double)single;
+         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+#else /* QCBOR_DISABLE_FLOAT_HW_USE */
+         /* Use of float HW is disabled, return as a float. */
+         pDecodedItem->val.fnum  = single;
+         pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
+
+         /* IEEE754_FloatToDouble() could be used here to return as
+          * a double, but it adds object code and most likely
+          * anyone disabling FLOAT HW use doesn't care about floats
+          * and wants to save object code.
+          */
+#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
+         uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
+         break;
+
+      case DOUBLE_PREC_FLOAT: /* 27 */
+         pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
+         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+
+         uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
+         if(uReturn != QCBOR_SUCCESS) {
+            break;
+         }
+         uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
+         break;
+   }
+
+   return uReturn;
+}
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
+
+
+
 /* 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
@@ -1155,7 +1392,6 @@
 #error QCBOR_TYPE_FLOAT macro value wrong
 #endif
 
-
 /**
  * @brief Decode major type 7 -- true, false, floating-point, break...
  *
@@ -1171,7 +1407,8 @@
  *                                           type in input.
  */
 static QCBORError
-QCBOR_Private_DecodeType7(const int      nAdditionalInfo,
+QCBOR_Private_DecodeType7(const uint8_t  uDecodeMode3Bit,
+                          const int      nAdditionalInfo,
                           const uint64_t uArgument,
                           QCBORItem     *pDecodedItem)
 {
@@ -1190,55 +1427,13 @@
        */
 
       case HALF_PREC_FLOAT: /* 25 */
-#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
-         /* Half-precision is returned as a double.  The cast to
-          * uint16_t is safe because the encoded value was 16 bits. It
-          * was widened to 64 bits to be passed in here.
-          */
-         pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
-         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
-#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
-         uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
-         break;
       case SINGLE_PREC_FLOAT: /* 26 */
-#ifndef USEFULBUF_DISABLE_ALL_FLOAT
-         /* Single precision is normally returned as a double since
-          * double is widely supported, there is no loss of precision,
-          * it makes it easy for the caller in most cases and it can
-          * be converted back to single with no loss of precision
-          *
-          * The cast to uint32_t is safe because the encoded value was
-          * 32 bits. It was widened to 64 bits to be passed in here.
-          */
-         {
-            const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
-            /* In the normal case, use HW to convert float to
-             * double. */
-            pDecodedItem->val.dfnum = (double)f;
-            pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
-            /* Use of float HW is disabled, return as a float. */
-            pDecodedItem->val.fnum = f;
-            pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
-
-            /* IEEE754_FloatToDouble() could be used here to return as
-             * a double, but it adds object code and most likely
-             * anyone disabling FLOAT HW use doesn't care about floats
-             * and wants to save object code.
-             */
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
-         }
-#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
-         uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
-         break;
-
       case DOUBLE_PREC_FLOAT: /* 27 */
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-         pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
-         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
-#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
-         uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
+         uReturn = QCBOR_Private_DecodeFloat(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
+#else
+         uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
          break;
 
       case CBOR_SIMPLEV_FALSE: /* 20 */
@@ -1246,12 +1441,19 @@
       case CBOR_SIMPLEV_NULL:  /* 22 */
       case CBOR_SIMPLEV_UNDEF: /* 23 */
       case CBOR_SIMPLE_BREAK:  /* 31 */
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+         if(uDecodeMode3Bit >= QCBOR_ENCODE_MODE_DCBOR &&
+            nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
+            uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
+            goto Done;
+         }
+#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
          break; /* nothing to do */
 
       case CBOR_SIMPLEV_ONEBYTE: /* 24 */
          if(uArgument <= CBOR_SIMPLE_BREAK) {
             /* This takes out f8 00 ... f8 1f which should be encoded
-             * as e0 … f7
+             * as e0 … f7 -- preferred serialization check for simple values.
              */
             uReturn = QCBOR_ERR_BAD_TYPE_7;
             goto Done;
@@ -1259,8 +1461,16 @@
          /* FALLTHROUGH */
 
       default: /* 0-19 */
-         pDecodedItem->uDataType   = QCBOR_TYPE_UKNOWN_SIMPLE;
-         /* DecodeHead() will make uArgument equal to
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+         if(uDecodeMode3Bit >= QCBOR_ENCODE_MODE_DCBOR &&
+            (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
+            uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
+            goto Done;
+         }
+#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
+
+         pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
+         /* QCBOR_Private_DecodeHead() will make uArgument equal to
           * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
           * safe because the 2, 4 and 8 byte lengths of uNumber are in
           * the double/float cases above
@@ -1310,16 +1520,25 @@
                                    QCBORItem           *pDecodedItem)
 {
    QCBORError uReturn;
-   int        nMajorType = 0;
-   uint64_t   uArgument = 0;
-   int        nAdditionalInfo = 0;
+   int       nMajorType = 0;
+   uint64_t  uArgument = 0;
+   int       nAdditionalInfo = 0;
+   uint8_t   uDecodeMode3Bit = pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK;
 
    memset(pDecodedItem, 0, sizeof(QCBORItem));
 
    /* Decode the "head" that every CBOR item has into the major type,
     * argument and the additional info.
     */
-   uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
+   uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+                                      // TODO: make this prettier; will optimizer take out stuff without ifdef?
+                                      uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED,
+#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
+                                      &nMajorType,
+                                      &uArgument,
+                                      &nAdditionalInfo);
+
    if(uReturn != QCBOR_SUCCESS) {
       return uReturn;
    }
@@ -1341,16 +1560,16 @@
 
       case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
       case CBOR_MAJOR_TYPE_MAP:   /* Major type 5 */
-         return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
+         return QCBOR_Private_DecodeArrayOrMap(uDecodeMode3Bit, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
          break;
 
       case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
-         return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
+         return QCBOR_Private_DecodeTagNumber(uArgument, nAdditionalInfo, pDecodedItem);
          break;
 
       case CBOR_MAJOR_TYPE_SIMPLE:
          /* Major type 7: float, double, true, false, null... */
-         return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
+         return QCBOR_Private_DecodeType7(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
          break;
 
       default:
@@ -1431,7 +1650,6 @@
       goto Done;
    }
 
-
    /* This is where out-of-place break is detected for the whole
     * decoding stack. Break is an error for everything that calls
     * QCBORDecode_Private_GetNextFullString(), so the check is
@@ -1530,9 +1748,9 @@
 /**
  * @brief This converts a tag number to a shorter mapped value for storage.
  *
- * @param[in] pMe                The decode context.
- * @param[in] uUnMappedTag       The tag number to map
- * @param[out] puMappedTagNumer  The stored tag number.
+ * @param[in] pMe                 The decode context.
+ * @param[in] uUnMappedTag        The tag number to map
+ * @param[out] puMappedTagNumber  The stored tag number.
  *
  * @return error code.
  *
@@ -1548,7 +1766,7 @@
 static QCBORError
 QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
                                  const uint64_t      uUnMappedTag,
-                                 uint16_t           *puMappedTagNumer)
+                                 uint16_t           *puMappedTagNumber)
 {
    if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
       unsigned uTagMapIndex;
@@ -1567,10 +1785,10 @@
 
       /* Covers the cases where tag is new and were it is already in the map */
       pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
-      *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
+      *puMappedTagNumber = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
 
    } else {
-      *puMappedTagNumer = (uint16_t)uUnMappedTag;
+      *puMappedTagNumber = (uint16_t)uUnMappedTag;
    }
 
    return QCBOR_SUCCESS;
@@ -1604,7 +1822,31 @@
       return pMe->auMappedTags[uIndex];
    }
 }
-#endif /* QCBOR_DISABLE_TAGS */
+
+
+static const struct QCBORTagDecoderEntry *
+QCBORDecode_Private_LookUpTagDecoder(const struct QCBORTagDecoderEntry *pTagContentTable,
+                                     const uint64_t                     uTagNumber)
+{
+   const struct QCBORTagDecoderEntry *pTE;
+
+   if(pTagContentTable == NULL) {
+      return NULL;
+   }
+
+   for(pTE = pTagContentTable; pTE->uTagNumber != CBOR_TAG_INVALID64; pTE++) {
+      if(pTE->uTagNumber == uTagNumber || pTE->uTagNumber == CBOR_TAG_ANY) {
+         break;
+      }
+   }
+
+   if(pTE->uTagNumber == CBOR_TAG_INVALID64) {
+      return NULL;
+   }
+
+   return pTE;
+}
+#endif /* ! QCBOR_DISABLE_TAGS */
 
 
 /**
@@ -1645,70 +1887,68 @@
                                      QCBORItem          *pDecodedItem)
 {
 #ifndef QCBOR_DISABLE_TAGS
-   /* Accummulate the tags from multiple items here and then copy them
-    * into the last item, the non-tag item.
+   int         nIndex;
+   QCBORError  uErr;
+   uint16_t    uMappedTagNumber;
+   QCBORError  uReturn;
+
+   /* Accummulate the tag numbers from multiple items here and then
+    * copy them into the last item, the non-tag-number item.
     */
-   uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
+   QCBORMappedTagNumbers  auTagNumbers;;
 
    /* Initialize to CBOR_TAG_INVALID16 */
    #if CBOR_TAG_INVALID16 != 0xffff
-   /* Be sure the memset does the right thing. */
+   /* Be sure the memset is initializing to CBOR_TAG_INVALID16 */
    #err CBOR_TAG_INVALID16 tag not defined as expected
    #endif
-   memset(auItemsTags, 0xff, sizeof(auItemsTags));
+   memset(auTagNumbers, 0xff, sizeof(auTagNumbers));
 
-   QCBORError uReturn = QCBOR_SUCCESS;
-
-   /* Loop fetching data items until the item fetched is not a tag */
-   for(;;) {
-      QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
+   /* Loop fetching data items until the item fetched is not a tag number */
+   uReturn = QCBOR_SUCCESS;
+   for(nIndex = 0; ; nIndex++) {
+      uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
       if(uErr != QCBOR_SUCCESS) {
          uReturn = uErr;
-         goto Done;
-      }
-
-      if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
-         /* Successful exit from loop; maybe got some tags, maybe not */
-         memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
          break;
       }
 
-      if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
-         /* No room in the tag list */
+      if(pDecodedItem->uDataType != QCBOR_TYPE_TAG_NUMBER) {
+         /* Successful exit from loop; maybe got some tags, maybe not */
+         memcpy(pDecodedItem->auTagNumbers, auTagNumbers, sizeof(auTagNumbers));
+         break;
+      }
+
+      if(nIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+         /* No room in the item's tag number array */
          uReturn = QCBOR_ERR_TOO_MANY_TAGS;
-         /* Continue on to get all tags wrapping this item even though
-          * it is erroring out in the end. This allows decoding to
-          * continue. This is a resource limit error, not a problem
-          * with being well-formed CBOR.
+         /* Continue on to get all tag numbers wrapping this item even
+          * though it is erroring out in the end. This allows decoding
+          * to continue. This is a QCBOR resource limit error, not a
+          * problem with being well-formed CBOR.
           */
          continue;
       }
-      /* Slide tags over one in the array to make room at index 0.
-       * Must use memmove because the move source and destination
-       * overlap.
-       */
-      memmove(&auItemsTags[1],
-              auItemsTags,
-              sizeof(auItemsTags) - sizeof(auItemsTags[0]));
 
-      /* Map the tag */
-      uint16_t uMappedTagNumber = 0;
-      uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
-      /* Continue even on error so as to consume all tags wrapping
-       * this data item so decoding can go on. If MapTagNumber()
-       * errors once it will continue to error.
+      /* Map the tag number */
+      uMappedTagNumber = 0;
+      uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagNumber, &uMappedTagNumber);
+      /* Continue even on error so as to consume all tag numbers
+       * wrapping this data item so decoding can go on. If
+       * QCBORDecode_Private_MapTagNumber() errors once it will
+       * continue to error.
        */
-      auItemsTags[0] = uMappedTagNumber;
+
+      auTagNumbers[nIndex] = uMappedTagNumber;
    }
 
-Done:
    return uReturn;
 
-#else /* QCBOR_DISABLE_TAGS */
+#else /* ! QCBOR_DISABLE_TAGS */
 
    return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
 
-#endif /* QCBOR_DISABLE_TAGS */
+#endif /* ! QCBOR_DISABLE_TAGS */
 }
 
 
@@ -1751,13 +1991,13 @@
  * This also implements maps-as-array mode where a map is treated like
  * an array to allow caller to do their own label processing.
  */
-
 static QCBORError
 QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
-                                    QCBORItem          *pDecodedItem)
+                                    QCBORItem          *pDecodedItem,
+                                    uint32_t           *puLabelEndOffset)
 {
    QCBORItem  LabelItem;
-   QCBORError uErr;
+   QCBORError uErr, uErr2;
 
    uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
    if(QCBORDecode_IsUnrecoverableError(uErr)) {
@@ -1776,21 +2016,32 @@
    /* Decoding a map entry, so the item decoded above was the label */
    LabelItem = *pDecodedItem;
 
+   if(puLabelEndOffset != NULL) {
+       /* Cast is OK because lengths are all 32-bit in QCBOR */
+       *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
+    }
+
    /* Get the value of the map item */
-   uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
-   if(QCBORDecode_IsUnrecoverableError(uErr)) {
+   uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
+   if(QCBORDecode_IsUnrecoverableError(uErr2)) {
+      uErr = uErr2;
       goto Done;
    }
+   if(uErr2 != QCBOR_SUCCESS) {
+      /* The recoverable error for the value overrides the recoverable
+       * error for the label, if there was an error for the label */
+      uErr = uErr2;
+   }
 
    /* Combine the label item and value item into one */
    pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
    pDecodedItem->uLabelType  = LabelItem.uDataType;
 
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-   /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
+   /* TODO: QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
     * get rid of it in QCBOR 2.0
     */
-   if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
+   if((pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
       LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
       uErr = QCBOR_ERR_MAP_LABEL_TYPE;
       goto Done;
@@ -1814,8 +2065,15 @@
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
 
       default:
-         uErr = QCBOR_ERR_MAP_LABEL_TYPE;
-         goto Done;
+         /* It is possible to skip over labels that are non-aggregate
+          * types like floats, but not to skip over labels that are
+          * arrays or maps. We might eventually handle more label
+          * types like floats as they are not too hard and we now
+          * have QCBOR_DISABLE_NON_INTEGER_LABELS */
+         if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
+            uErr = QCBOR_ERR_MAP_LABEL_TYPE;
+            goto Done;
+         }
    }
 
 Done:
@@ -2013,7 +2271,8 @@
 static QCBORError
 QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
                                       bool               *pbBreak,
-                                      QCBORItem          *pDecodedItem)
+                                      QCBORItem          *pDecodedItem,
+                                      uint32_t           *puLabelEndOffset)
 {
    QCBORError uReturn;
    /* ==== First: figure out if at the end of a traversal ==== */
@@ -2041,7 +2300,7 @@
    }
 
    /* ==== Next: not at the end, so get another item ==== */
-   uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
+   uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
    if(QCBORDecode_IsUnrecoverableError(uReturn)) {
       /* Error is so bad that traversal is not possible. */
       goto Done;
@@ -2122,478 +2381,6 @@
 }
 
 
-#ifndef QCBOR_DISABLE_TAGS
-/**
- * @brief Shift 0th tag out of the tag list.
- *
- * pDecodedItem[in,out]  The data item to convert.
- *
- * The 0th tag is discarded. @ref CBOR_TAG_INVALID16 is
- * shifted into empty slot at the end of the tag list.
- */
-static void
-QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
-{
-   for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
-      pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
-   }
-   pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
-}
-#endif /* QCBOR_DISABLE_TAGS */
-
-
-/**
- * @brief Convert different epoch date formats in to the QCBOR epoch date format
- *
- * pDecodedItem[in,out]  The data item to convert.
- *
- * @retval QCBOR_ERR_DATE_OVERFLOW              65-bit negative integer.
- * @retval QCBOR_ERR_FLOAT_DATE_DISABLED        Float-point date in input,
- *                                              floating-point date disabled.
- * @retval QCBOR_ERR_ALL_FLOAT_DISABLED         Float-point date in input,
- *                                              all floating-point disabled.
- * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT  Unexpected and unrecoverable
- *                                              error decoding date.
- *
- * The epoch date tag defined in QCBOR allows for floating-point
- * dates. It even allows a protocol to flop between date formats when
- * ever it wants.  Floating-point dates aren't that useful as they are
- * only needed for dates beyond the age of the earth.
- *
- * This converts all the date formats into one format of an unsigned
- * integer plus a floating-point fraction.
- */
-static QCBORError
-QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
-{
-   QCBORError uReturn = QCBOR_SUCCESS;
-
-#ifndef USEFULBUF_DISABLE_ALL_FLOAT
-   pDecodedItem->val.epochDate.fSecondsFraction = 0;
-#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
-
-   switch (pDecodedItem->uDataType) {
-
-      case QCBOR_TYPE_INT64:
-         pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
-         break;
-
-      case QCBOR_TYPE_UINT64:
-         /* This only happens for CBOR type 0 > INT64_MAX so it is
-          * always an overflow.
-          */
-         uReturn = QCBOR_ERR_DATE_OVERFLOW;
-         goto Done;
-         break;
-
-      case QCBOR_TYPE_DOUBLE:
-      case QCBOR_TYPE_FLOAT:
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
-      {
-         /* Convert working value to double if input was a float */
-         const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
-                   pDecodedItem->val.dfnum :
-                   (double)pDecodedItem->val.fnum;
-
-         /* The conversion from float to integer requires overflow
-          * detection since floats can be much larger than integers.
-          * This implementation errors out on these large float values
-          * since they are beyond the age of the earth.
-          *
-          * These constants for the overflow check are computed by the
-          * compiler. They are not computed at run time.
-          *
-          * The factor of 0x7ff is added/subtracted to avoid a
-          * rounding error in the wrong direction when the compiler
-          * computes these constants. There is rounding because a
-          * 64-bit integer has 63 bits of precision where a double
-          * only has 53 bits. Without the 0x7ff factor, the compiler
-          * may round up and produce a double for the bounds check
-          * that is larger than can be stored in a 64-bit integer. The
-          * amount of 0x7ff is picked because it has 11 bits set.
-          *
-          * Without the 0x7ff there is a ~30 minute range of time
-          * values 10 billion years in the past and in the future
-          * where this code could go wrong. Some compilers
-          * generate a warning or error without the 0x7ff.
-          */
-         const double dDateMax = (double)(INT64_MAX - 0x7ff);
-         const double dDateMin = (double)(INT64_MIN + 0x7ff);
-
-         if(isnan(d) || d > dDateMax || d < dDateMin) {
-            uReturn = QCBOR_ERR_DATE_OVERFLOW;
-            goto Done;
-         }
-
-         /* The actual conversion */
-         pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
-         pDecodedItem->val.epochDate.fSecondsFraction =
-                           d - (double)pDecodedItem->val.epochDate.nSeconds;
-      }
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
-
-         uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
-         goto Done;
-
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
-         break;
-
-      default:
-         /* It's the arrays and maps that are unrecoverable because
-          * they are not consumed here. Since this is just an error
-          * condition, no extra code is added here to make the error
-          * recoverable for non-arrays and maps like strings. */
-         uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
-         goto Done;
-   }
-
-   pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
-
-Done:
-   return uReturn;
-}
-
-
-/**
- * @brief Convert the days epoch date.
- *
- * pDecodedItem[in,out]  The data item to convert.
- *
- * @retval QCBOR_ERR_DATE_OVERFLOW              65-bit negative integer.
- * @retval QCBOR_ERR_FLOAT_DATE_DISABLED        Float-point date in input,
- *                                              floating-point date disabled.
- * @retval QCBOR_ERR_ALL_FLOAT_DISABLED         Float-point date in input,
- *                                              all floating-point disabled.
- * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT  Unexpected and unrecoverable
- *                                              error decoding date.
- *
- * This is much simpler than the other epoch date format because
- * floating-porint is not allowed. This is mostly a simple type check.
- */
-static QCBORError
-QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
-{
-   QCBORError uReturn = QCBOR_SUCCESS;
-
-   switch (pDecodedItem->uDataType) {
-
-      case QCBOR_TYPE_INT64:
-         pDecodedItem->val.epochDays = pDecodedItem->val.int64;
-         break;
-
-      case QCBOR_TYPE_UINT64:
-         /* This only happens for CBOR type 0 > INT64_MAX so it is
-          * always an overflow.
-          */
-         uReturn = QCBOR_ERR_DATE_OVERFLOW;
-         goto Done;
-         break;
-
-      default:
-         /* It's the arrays and maps that are unrecoverable because
-          * they are not consumed here. Since this is just an error
-          * condition, no extra code is added here to make the error
-          * recoverable for non-arrays and maps like strings. */
-         uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
-         goto Done;
-         break;
-   }
-
-   pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
-
-Done:
-   return uReturn;
-}
-
-
-#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
-
-/* Forward declaration is necessary for
- * QCBORDecode_MantissaAndExponent().  to be able to decode bignum
- * tags in the mantissa. If the mantissa is a decimal fraction or big
- * float in error, this will result in a recurive call to
- * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
- * correctly and the correct error is returned.
- */
-static QCBORError
-QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
-                                      QCBORItem          *pDecodedItem);
-
-
-/**
- * @brief Decode decimal fractions and big floats.
- *
- * @param[in] pMe               The decode context.
- * @param[in,out] pDecodedItem  On input the array data item that
- *                              holds the mantissa and exponent.  On
- *                              output the decoded mantissa and
- *                              exponent.
- *
- * @returns  Decoding errors from getting primitive data items or
- *           @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
- *
- * When called pDecodedItem must be the array with two members, the
- * exponent and mantissa.
- *
- * This will fetch and decode the exponent and mantissa and put the
- * result back into pDecodedItem.
- *
- * This does no checking or processing of tag numbers. That is to be
- * done by the code that calls this.
- *
- * This stuffs the type of the mantissa into pDecodedItem with the expectation
- * the caller will process it.
- */
-static QCBORError
-QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
-                                QCBORItem          *pDecodedItem)
-{
-   QCBORError uReturn;
-
-   /* --- Make sure it is an array; track nesting level of members --- */
-   if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
-      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
-      goto Done;
-   }
-
-   /* A check for pDecodedItem->val.uCount == 2 would work for
-    * definite-length arrays, but not for indefinite. Instead remember
-    * the nesting level the two integers must be at, which is one
-    * deeper than that of the array.
-    */
-   const int nNestLevel = pDecodedItem->uNestingLevel + 1;
-
-   /* --- Get the exponent --- */
-   QCBORItem exponentItem;
-   uReturn = QCBORDecode_GetNext(pMe, &exponentItem);
-   if(uReturn != QCBOR_SUCCESS) {
-      goto Done;
-   }
-   if(exponentItem.uNestingLevel != nNestLevel) {
-      /* Array is empty or a map/array encountered when expecting an int */
-      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
-      goto Done;
-   }
-   if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
-     /* Data arriving as an unsigned int < INT64_MAX has been
-      * converted to QCBOR_TYPE_INT64 and thus handled here. This is
-      * also means that the only data arriving here of type
-      * QCBOR_TYPE_UINT64 data will be too large for this to handle
-      * and thus an error that will get handled in the next else.
-      */
-     pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
-   } else {
-      /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
-      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
-      goto Done;
-   }
-
-   /* --- Get the mantissa --- */
-   QCBORItem mantissaItem;
-   uReturn = QCBORDecode_GetNext(pMe, &mantissaItem);
-   if(uReturn != QCBOR_SUCCESS) {
-      goto Done;
-   }
-   if(mantissaItem.uNestingLevel != nNestLevel) {
-      /* Mantissa missing or map/array encountered when expecting number */
-      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
-      goto Done;
-   }
-   /* Stuff the mantissa data type into the item to send it up to the
-    * the next level. */
-   pDecodedItem->uDataType = mantissaItem.uDataType;
-   if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
-      /* Data arriving as an unsigned int < INT64_MAX has been
-       * converted to QCBOR_TYPE_INT64 and thus handled here. This is
-       * also means that the only data arriving here of type
-       * QCBOR_TYPE_UINT64 data will be too large for this to handle
-       * and thus an error that will get handled in an else below.
-       */
-      pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
-#ifndef QCBOR_DISABLE_TAGS
-      /* With tags fully disabled a big number mantissa will error out
-       * in the call to QCBORDecode_GetNextWithTags() because it has
-       * a tag number.
-       */
-   }  else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
-              mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
-      /* Got a good big num mantissa */
-      pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
-#endif /* QCBOR_DISABLE_TAGS */
-   } else {
-      /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
-      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
-      goto Done;
-   }
-
-   /* --- Check that array only has the two numbers --- */
-   if(mantissaItem.uNextNestLevel == nNestLevel) {
-      /* Extra items in the decimal fraction / big float */
-      /* Improvement: this should probably be an unrecoverable error. */
-      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
-      goto Done;
-   }
-   pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
-
-Done:
-  return uReturn;
-}
-#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
-
-
-#ifndef QCBOR_DISABLE_TAGS
-
-#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
-/**
- * @brief Decode the MIME type tag
- *
- * @param[in,out] pDecodedItem   The item to decode.
- *
- *  Handle the text and binary MIME type tags. Slightly too complicated
- *  f or ProcessTaggedString() because the RFC 7049 MIME type was
- *  incorreclty text-only.
- */
-static QCBORError
-QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
-{
-   if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
-      pDecodedItem->uDataType = QCBOR_TYPE_MIME;
-   } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
-      pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
-   } else {
-      /* It's the arrays and maps that are unrecoverable because
-       * they are not consumed here. Since this is just an error
-       * condition, no extra code is added here to make the error
-       * recoverable for non-arrays and maps like strings. */
-      return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
-   }
-
-   return QCBOR_SUCCESS;
-}
-#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
-
-/**
- * Table of CBOR tags whose content is either a text string or a byte
- * string. The table maps the CBOR tag to the QCBOR type. The high-bit
- * of uQCBORtype indicates the content should be a byte string rather
- * than a text string
- */
-struct StringTagMapEntry {
-   uint16_t uTagNumber;
-   uint8_t  uQCBORtype;
-};
-
-#define IS_BYTE_STRING_BIT 0x80
-#define QCBOR_TYPE_MASK   ~IS_BYTE_STRING_BIT
-
-static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
-   {CBOR_TAG_DATE_STRING,   QCBOR_TYPE_DATE_STRING},
-   {CBOR_TAG_DAYS_STRING,   QCBOR_TYPE_DAYS_STRING},
-   {CBOR_TAG_POS_BIGNUM,    QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
-   {CBOR_TAG_NEG_BIGNUM,    QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
-   {CBOR_TAG_CBOR,          QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
-   {CBOR_TAG_URI,           QCBOR_TYPE_URI},
-#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
-   {CBOR_TAG_B64URL,        QCBOR_TYPE_BASE64URL},
-   {CBOR_TAG_B64,           QCBOR_TYPE_BASE64},
-   {CBOR_TAG_REGEX,         QCBOR_TYPE_REGEX},
-   {CBOR_TAG_BIN_UUID,      QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
-#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
-   {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
-   {CBOR_TAG_INVALID16,     QCBOR_TYPE_NONE}
-};
-
-
-/**
- * @brief Process standard CBOR tags whose content is a string
- *
- * @param[in] uTag              The tag.
- * @param[in,out] pDecodedItem  The data item.
- *
- * @returns  This returns QCBOR_SUCCESS if the tag was procssed,
- *           @ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
- *           @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
- *
- * Process the CBOR tags that whose content is a byte string or a text
- * string and for which the string is just passed on to the caller.
- *
- * This maps the CBOR tag to the QCBOR type and checks the content
- * type.  Nothing more. It may not be the most important
- * functionality, but it part of implementing as much of RFC 8949 as
- * possible.
- */
-static QCBORError
-QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
-{
-   /* This only works on tags that were not mapped; no need for other yet */
-   if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
-      return QCBOR_ERR_UNSUPPORTED;
-   }
-
-   unsigned uIndex;
-   for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
-      if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
-         break;
-      }
-   }
-
-   const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
-   if(uQCBORType == QCBOR_TYPE_NONE) {
-      /* repurpose this error to mean not handled here */
-      return QCBOR_ERR_UNSUPPORTED;
-   }
-
-   uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
-   if(uQCBORType & IS_BYTE_STRING_BIT) {
-      uExpectedType = QCBOR_TYPE_BYTE_STRING;
-   }
-
-   if(pDecodedItem->uDataType != uExpectedType) {
-      /* It's the arrays and maps that are unrecoverable because
-       * they are not consumed here. Since this is just an error
-       * condition, no extra code is added here to make the error
-       * recoverable for non-arrays and maps like strings. */
-      return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
-   }
-
-   pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
-   return QCBOR_SUCCESS;
-}
-#endif /* QCBOR_DISABLE_TAGS */
-
-
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
-/**
- * @brief Figures out data type for exponent mantissa tags.
- *
- * @param[in] uTagToProcess  Either @ref CBOR_TAG_DECIMAL_FRACTION or
- *                           @ref CBOR_TAG_BIG_FLOAT.
- * @param[in] pDecodedItem   Item being decoded.
- *
- * @returns One of the 6 values between @ref QCBOR_TYPE_DECIMAL_FRACTION
- *          and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
- *
- * Does mapping between a CBOR tag number and a QCBOR type.  with a
- * little bit of logic and arithmatic.
- *
- * Used in serveral contexts. Does the work where sometimes the data
- * item is explicitly tagged and sometimes not.
- */
-static uint8_t
-QCBOR_Private_ExpMantissaDataType(const uint16_t   uTagToProcess,
-                                  const QCBORItem *pDecodedItem)
-{
-   uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
-                                       QCBOR_TYPE_DECIMAL_FRACTION :
-                                       QCBOR_TYPE_BIGFLOAT;
-   if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
-      uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
-   }
-   return uBase;
-}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
-
-
 /**
  * @brief Decode tag content for select tags (decoding layer 1).
  *
@@ -2604,88 +2391,309 @@
  *
  * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
  * but the whole tag was not decoded. Here, the whole tags (tag number
- * and tag content) that are supported by QCBOR are decoded. This is a
+ * and tag content) are decoded. This is a
  * quick pass through for items that are not tags.
  */
 static QCBORError
 QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
                                       QCBORItem          *pDecodedItem)
 {
-   QCBORError uReturn;
+   QCBORError uErr;
 
-   uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
-   if(uReturn != QCBOR_SUCCESS) {
+   uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
+
+#ifndef QCBOR_DISABLE_TAGS
+   uint64_t   uTagNumber;
+   int        nTagIndex;
+   const struct QCBORTagDecoderEntry *pTagDecoder;
+
+   if(uErr != QCBOR_SUCCESS) {
       goto Done;
    }
 
-#ifndef QCBOR_DISABLE_TAGS
-   /* When there are no tag numbers for the item, this exits first
-    * thing and effectively does nothing.
-    *
-    * This loops over all the tag numbers accumulated for this item
-    * trying to decode and interpret them. This stops at the end of
-    * the list or at the first tag number that can't be interpreted by
-    * this code. This is effectively a recursive processing of the
-    * tags number list that handles nested tags.
-    */
-   while(1) {
-      /* Don't bother to unmap tags via QCBORITem.uTags since this
-       * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
+   /* Loop over tag numbers in reverse, those closest to content first */
+   for(nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >= 0; nTagIndex--) {
+
+      if(pDecodedItem->auTagNumbers[nTagIndex] == CBOR_TAG_INVALID16) {
+         continue; /* Empty slot, skip to next */
+      }
+
+      /* See if there's a content decoder for it */
+      uTagNumber  = QCBORDecode_Private_UnMapTagNumber(pMe, pDecodedItem->auTagNumbers[nTagIndex]);
+      pTagDecoder = QCBORDecode_Private_LookUpTagDecoder(pMe->pTagDecoderTable, uTagNumber);
+      if(pTagDecoder == NULL) {
+         break; /* Successful exist -- a tag that we can't decode */
+      }
+
+      /* Call the content decoder */
+      uErr = pTagDecoder->pfContentDecoder(pMe, pMe->pTagDecodersContext, pTagDecoder->uTagNumber, pDecodedItem);
+      if(uErr != QCBOR_SUCCESS) {
+         break; /* Error exit from the loop */
+      }
+
+      /* Remove tag number from list since its content was decoded */
+      pDecodedItem->auTagNumbers[nTagIndex] = CBOR_TAG_INVALID16;
+   }
+
+Done:
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+   return uErr;
+}
+
+
+/**
+ * @brief Consume an entire map or array including its contents.
+ *
+ * @param[in]  pMe              The decoder context.
+ * @param[in]  pItemToConsume   The array/map whose contents are to be
+ *                              consumed.
+ * @param[out] puNextNestLevel  The next nesting level after the item was
+ *                              fully consumed.
+ *
+ * This may be called when @c pItemToConsume is not an array or
+ * map. In that case, this is just a pass through for @c puNextNestLevel
+ * since there is nothing to do.
+ */
+static QCBORError
+QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
+                                const QCBORItem    *pItemToConsume,
+                                bool               *pbBreak,
+                                uint8_t            *puNextNestLevel)
+{
+   QCBORError uReturn;
+   QCBORItem  Item;
+
+   /* If it is a map or array, this will tell if it is empty. */
+   const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
+
+   if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
+      /* There is only real work to do for non-empty maps and arrays */
+
+      /* This works for definite- and indefinite-length maps and
+       * arrays by using the nesting level
        */
-      const uint16_t uTagToProcess = pDecodedItem->uTags[0];
+      do {
+         uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
+         if(QCBORDecode_IsUnrecoverableError(uReturn) ||
+            uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
+            goto Done;
+         }
+      } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
 
-      if(uTagToProcess == CBOR_TAG_INVALID16) {
-         /* Hit the end of the tag list. A successful exit. */
+      *puNextNestLevel = Item.uNextNestLevel;
+
+      uReturn = QCBOR_SUCCESS;
+
+   } else {
+      /* pItemToConsume is not a map or array. Just pass the nesting
+       * level through. */
+      *puNextNestLevel = pItemToConsume->uNextNestLevel;
+
+      uReturn = QCBOR_SUCCESS;
+   }
+
+Done:
+    return uReturn;
+}
+
+
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+/*
+ * This consumes the next item. It returns the starting position of
+ * the label and the length of the label. It also returns the nest
+ * level of the item consumed.
+ */
+static QCBORError
+QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
+                                       uint8_t            *puNestLevel,
+                                       size_t             *puLabelStart,
+                                       size_t             *puLabelLen)
+{
+   QCBORError uErr;
+   QCBORItem  Item;
+   uint8_t    uLevel;
+   uint32_t   uLabelOffset;
+
+   /* Get the label and consume it should it be complex */
+   *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+   uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
+   if(uErr != QCBOR_SUCCESS) {
+      goto Done;
+   }
+   *puLabelLen = uLabelOffset - *puLabelStart;
+   *puNestLevel = Item.uNestingLevel;
+   uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
+
+Done:
+   return uErr;
+}
+
+
+/* Loop over items in a map until the end of the map looking for
+ * duplicates. This starts at the current position in the map, not at
+ * the beginning of the map.
+ *
+ * This saves and restores the traversal cursor and nest tracking so
+ * they are the same on exit as they were on entry.
+ */
+static QCBORError
+QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
+                              const uint8_t       uNestLevel,
+                              const size_t        uCompareLabelStart,
+                              const size_t        uCompareLabelLen)
+{
+   QCBORError uErr;
+   size_t     uLabelStart;
+   size_t     uLabelLen;
+   uint8_t    uLevel;
+   int        nCompare;
+
+   const QCBORDecodeNesting SaveNesting = pMe->nesting;
+   const UsefulInputBuf     Save        = pMe->InBuf;
+
+   do {
+      uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
+      if(uErr != QCBOR_SUCCESS) {
+         if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
+            uErr = QCBOR_SUCCESS; /* Successful end */
+         }
          break;
+      }
 
-      } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
-         uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
+      if(uLevel != uNestLevel) {
+         break; /* Successful end of loop */
+      }
 
-      } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
-         uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
+      /* This check for dups works for labels that are preferred
+       * serialization and are not maps. If the labels are not in
+       * preferred serialization, then the check has to be more
+       * complicated and is type-specific because it uses the decoded
+       * value, not the encoded CBOR. It is further complicated for
+       * maps because the order of items in a map that is a label
+       * doesn't matter when checking that is is the duplicate of
+       * another map that is a label. QCBOR so far only turns on this
+       * dup checking as part of CDE checking which requires preferred
+       * serialization.  See 5.6 in RFC 8949.
+       */
+      nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
+                                         uCompareLabelStart, uCompareLabelLen,
+                                         uLabelStart, uLabelLen);
+      if(nCompare == 0) {
+         uErr = QCBOR_ERR_DUPLICATE_LABEL;
+         break;
+      }
+   } while (1);
 
-#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
-      } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
-                uTagToProcess == CBOR_TAG_BIGFLOAT) {
-         uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
-         /* --- Which is it, decimal fraction or a bigfloat? --- */
-         pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
+   pMe->nesting = SaveNesting;
+   pMe->InBuf   = Save;
 
-#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
-#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
-      } else if(uTagToProcess == CBOR_TAG_MIME ||
-                uTagToProcess == CBOR_TAG_BINARY_MIME) {
-         uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
-#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
+   return uErr;
+}
 
-      } else {
-         /* See if it is a passthrough byte/text string tag; process if so */
-         uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
 
-         if(uReturn == QCBOR_ERR_UNSUPPORTED) {
-            /* It wasn't a passthrough byte/text string tag so it is
-             * an unknown tag. This is the exit from the loop on the
-             * first unknown tag.  It is a successful exit.
-             */
-            uReturn = QCBOR_SUCCESS;
+/* This does sort order and duplicate detection on a map. The and all
+ * it's members must be in preferred serialization so the comparisons
+ * work correctly.
+ */
+static QCBORError
+QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
+{
+   QCBORError uErr;
+   uint8_t    uNestLevel;
+   size_t     offset2, offset1, length2, length1;
+
+   const QCBORDecodeNesting SaveNesting = pMe->nesting;
+   const UsefulInputBuf Save = pMe->InBuf;
+   pMe->bAllowAllLabels = 1;
+
+   /* This loop runs over all the items in the map once, comparing
+    * each adjacent pair for correct ordering. It also calls CheckDup
+    * on each one which also runs over the remaining items in the map
+    * checking for duplicates. So duplicate checking runs in n^2.
+    */
+
+   offset2 = SIZE_MAX;
+   length2 = SIZE_MAX; // To avoid uninitialized warning
+   while(1) {
+      uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
+      if(uErr != QCBOR_SUCCESS) {
+         if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
+            uErr = QCBOR_SUCCESS; /* Successful exit from loop */
+         }
+         break;
+      }
+
+      if(uNestLevel < pMapToCheck->uNextNestLevel) {
+         break; /* Successful exit from loop */
+      }
+
+      if(offset2 != SIZE_MAX) {
+         /* Check that the labels are ordered. Check is not done the
+          * first time through the loop when offset2 is unset. Since
+          * this does comparison of the items in encoded form they
+          * must be preferred serialization encoded. See RFC 8949
+          * 4.2.1.
+          */
+         if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
+            uErr = QCBOR_ERR_UNSORTED;
             break;
          }
       }
 
-      if(uReturn != QCBOR_SUCCESS) {
-         /* Error exit from the loop */
+      uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
+      if(uErr != QCBOR_SUCCESS) {
          break;
       }
 
-      /* A tag was successfully processed, shift it out of the list of
-       * tags returned. This is the loop increment.
-       */
-      QCBOR_Private_ShiftTags(pDecodedItem);
+      offset2 = offset1;
+      length2 = length1;
    }
-#endif /* QCBOR_DISABLE_TAGS */
 
-Done:
-   return uReturn;
+   pMe->bAllowAllLabels = 0;
+   pMe->nesting = SaveNesting;
+   pMe->InBuf = Save;
+
+   return uErr;
+}
+#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
+
+static QCBORError
+QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
+                                  QCBORError          uErr,
+                                  const size_t        uOffset,
+                                  QCBORItem          *pDecodedItem)
+{
+   (void)pMe; /* Avoid warning for next two ifdefs */
+   (void)uOffset;
+
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+   if(uErr == QCBOR_SUCCESS &&
+      (pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) >= QCBOR_ENCODE_MODE_CDE &&
+      pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
+      /* Traverse map checking sort order and for duplicates */
+      uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
+   }
+#endif /* ! QCBOR_DISABLE_CONFORMANCE */
+
+#ifndef QCBOR_DISABLE_TAGS
+   if(uErr == QCBOR_SUCCESS &&
+      !(pMe->uDecodeMode & QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS) &&
+      pDecodedItem->auTagNumbers[0] != CBOR_TAG_INVALID16) {
+      /*  Not QCBOR v1; there are tag numbers -- check they were consumed */
+      if(uOffset != pMe->uTagNumberCheckOffset || pMe->uTagNumberIndex != 255) {
+         uErr = QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+      }
+   }
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+   if(uErr != QCBOR_SUCCESS) {
+      pDecodedItem->uDataType  = QCBOR_TYPE_NONE;
+      pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
+   }
+
+   return uErr;
 }
 
 
@@ -2696,11 +2704,11 @@
 QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
 {
    QCBORError uErr;
-   uErr =  QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
-   if(uErr != QCBOR_SUCCESS) {
-      pDecodedItem->uDataType  = QCBOR_TYPE_NONE;
-      pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
-   }
+   size_t     uOffset;
+
+   uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+   uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
+   uErr = QCBORDecode_Private_GetItemChecks(pMe, uErr, uOffset, pDecodedItem);
    return uErr;
 }
 
@@ -2740,10 +2748,10 @@
 
 
 static void
-QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
+QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
 {
 #ifndef QCBOR_DISABLE_TAGS
-   memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
+   memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
 #else
    (void)pMe;
    (void)pItem;
@@ -2763,77 +2771,7 @@
    }
 
    pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
-   QCBORDecode_Private_CopyTags(pMe, pDecodedItem);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
-                            QCBORItem          *pDecodedItem,
-                            QCBORTagListOut    *pTags)
-{
-#ifndef QCBOR_DISABLE_TAGS
-
-   QCBORError uReturn;
-
-   uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
-   if(uReturn != QCBOR_SUCCESS) {
-      return uReturn;
-   }
-
-   if(pTags != NULL) {
-      pTags->uNumUsed = 0;
-      /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
-      for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
-         if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
-            continue;
-         }
-         if(pTags->uNumUsed >= pTags->uNumAllocated) {
-            return QCBOR_ERR_TOO_MANY_TAGS;
-         }
-         pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
-         pTags->uNumUsed++;
-      }
-   }
-
-   return QCBOR_SUCCESS;
-
-#else /* QCBOR_DISABLE_TAGS */
-   (void)pMe;
-   (void)pDecodedItem;
-   (void)pTags;
-   return QCBOR_ERR_TAGS_DISABLED;
-#endif /* QCBOR_DISABLE_TAGS */
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-bool
-QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
-                     const QCBORItem   *pItem,
-                     uint64_t           uTag)
-{
-#ifndef QCBOR_DISABLE_TAGS
-   for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
-      if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
-         break;
-      }
-      if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
-         return true;
-      }
-   }
-#else /* QCBOR_TAGS_DISABLED */
-   (void)pMe;
-   (void)pItem;
-   (void)uTag;
-#endif /* QCBOR_TAGS_DISABLED */
-
-   return false;
+   QCBORDecode_Private_SaveTagNumbers(pMe, pDecodedItem);
 }
 
 
@@ -2886,30 +2824,81 @@
 }
 
 
+#ifndef QCBOR_DISABLE_TAGS
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+uint64_t
+QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
+                            const QCBORItem          *pItem,
+                            uint8_t                   uIndex)
+{
+   if(pItem->uDataType == QCBOR_TYPE_NONE) {
+      return CBOR_TAG_INVALID64;
+   }
+   if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+      return CBOR_TAG_INVALID64;
+   }
+
+   return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+uint64_t
+QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
+                                  uint8_t             uIndex)
+{
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return CBOR_TAG_INVALID64;
+   }
+   if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+      return CBOR_TAG_INVALID64;
+   }
+
+   return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+static uint64_t
+QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
+                                           const uint16_t            puTagNumbers[],
+                                           const uint32_t            uIndex)
+{
+   uint32_t uArrayIndex;
+
+   /* Find number of tag numbers */
+   for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
+      if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
+         break;
+      }
+   }
+   if(uIndex > uArrayIndex) {
+      return CBOR_TAG_INVALID64;
+   }
+
+   return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
+}
+
+
 /*
  * Public function, see header qcbor/qcbor_decode.h file
  */
 uint64_t
 QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
                       const QCBORItem    *pItem,
-                      uint32_t            uIndex)
+                      const uint32_t      uIndex)
 {
-#ifndef QCBOR_DISABLE_TAGS
    if(pItem->uDataType == QCBOR_TYPE_NONE) {
       return CBOR_TAG_INVALID64;
    }
-   if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
-      return CBOR_TAG_INVALID64;
-   } else {
-      return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
-   }
-#else /* QCBOR_DISABLE_TAGS */
-   (void)pMe;
-   (void)pItem;
-   (void)uIndex;
 
-   return CBOR_TAG_INVALID64;
-#endif /* QCBOR_DISABLE_TAGS */
+   return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
 }
 
 
@@ -2920,26 +2909,67 @@
 QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
                             uint32_t                  uIndex)
 {
-#ifndef QCBOR_DISABLE_TAGS
-
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return CBOR_TAG_INVALID64;
    }
    if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
       return CBOR_TAG_INVALID64;
-   } else {
-      return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
    }
-#else /* QCBOR_DISABLE_TAGS */
-   (void)pMe;
-   (void)uIndex;
 
-   return CBOR_TAG_INVALID64;
-#endif /* QCBOR_DISABLE_TAGS */
+   return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
 }
 
 
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+QCBORError
+QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+{
+   QCBORItem   Item;
+   size_t      uOffset;
+   QCBORError  uErr;
 
+   const QCBORDecodeNesting SaveNesting = pMe->nesting;
+   const UsefulInputBuf Save = pMe->InBuf;
+
+   uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+   if(uOffset == pMe->uTagNumberCheckOffset) {
+      pMe->uTagNumberIndex++;
+   } else {
+      pMe->uTagNumberIndex = 0;
+   }
+
+   *puTagNumber = CBOR_TAG_INVALID64;
+   uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
+   if(uErr) {
+      return uErr;
+   }
+
+   *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
+   if(*puTagNumber == CBOR_TAG_INVALID64 ||
+      QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+      pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
+   }
+   pMe->uTagNumberCheckOffset = uOffset;
+
+   pMe->nesting = SaveNesting;
+   pMe->InBuf = Save;
+
+   return QCBOR_SUCCESS;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+{
+   pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
+}
+
+#endif /* ! QCBOR_DISABLE_TAGS */
 
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
 
@@ -3132,63 +3162,6 @@
 
 
 
-
-/**
- * @brief Consume an entire map or array including its contents.
- *
- * @param[in]  pMe              The decoder context.
- * @param[in]  pItemToConsume   The array/map whose contents are to be
- *                              consumed.
- * @param[out] puNextNestLevel  The next nesting level after the item was
- *                              fully consumed.
- *
- * This may be called when @c pItemToConsume is not an array or
- * map. In that case, this is just a pass through for @c puNextNestLevel
- * since there is nothing to do.
- */
-static QCBORError
-QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
-                                const QCBORItem    *pItemToConsume,
-                                bool               *pbBreak,
-                                uint8_t            *puNextNestLevel)
-{
-   QCBORError uReturn;
-   QCBORItem  Item;
-
-   /* If it is a map or array, this will tell if it is empty. */
-   const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
-
-   if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
-      /* There is only real work to do for non-empty maps and arrays */
-
-      /* This works for definite- and indefinite-length maps and
-       * arrays by using the nesting level
-       */
-      do {
-         uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
-         if(QCBORDecode_IsUnrecoverableError(uReturn) ||
-            uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
-            goto Done;
-         }
-      } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
-
-      *puNextNestLevel = Item.uNextNestLevel;
-
-      uReturn = QCBOR_SUCCESS;
-
-   } else {
-      /* pItemToConsume is not a map or array. Just pass the nesting
-       * level through. */
-      *puNextNestLevel = pItemToConsume->uNextNestLevel;
-
-      uReturn = QCBOR_SUCCESS;
-   }
-
-Done:
-    return uReturn;
-}
-
-
 /*
  * Public function, see header qcbor/qcbor_decode.h file
  */
@@ -3516,38 +3489,152 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
-                          int64_t             nLabel,
-                          uint8_t             uQcborType,
-                          QCBORItem          *pItem)
+QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
 {
+   MapSearchInfo Info;
+   QCBORItem     OneItemSeach[2];
+
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return;
    }
 
+   OneItemSeach[0].uLabelType  = QCBOR_TYPE_INT64;
+   OneItemSeach[0].label.int64 = nLabel;
+   OneItemSeach[0].uDataType   = QCBOR_TYPE_ANY;
+   OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE; // Indicates end of array
+
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+   if(pMe->uLastError == QCBOR_SUCCESS) {
+      UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+   }
+}
+
+
+void
+QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+   MapSearchInfo  Info;
+   QCBORItem      OneItemSeach[2];
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   OneItemSeach[0].uLabelType   = QCBOR_TYPE_TEXT_STRING;
+   OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+   OneItemSeach[0].uDataType    = QCBOR_TYPE_ANY;
+   OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE; // Indicates end of array
+
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+   if(pMe->uLastError == QCBOR_SUCCESS) {
+      UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+   }
+#else
+   (void)pMe;
+   (void)szLabel;
+   pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+void
+QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
+                                        QCBORItem          *OneItemSeach,
+                                        QCBORItem          *pItem,
+                                        size_t             *puOffset)
+{
+   QCBORError    uErr;
+   MapSearchInfo SearchInfo;
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
+
+   if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
+      uErr = QCBOR_ERR_LABEL_NOT_FOUND;
+   }
+   *pItem = OneItemSeach[0];
+   *puOffset = SearchInfo.uStartOffset;
+
+   if(uErr == QCBOR_SUCCESS) {
+      QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
+   }
+
+   pMe->uLastError = (uint8_t)uErr;
+}
+
+
+static void
+QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
+{
+   QCBORError  uErr;
+   size_t      uOffset;
+
+   QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
+
+   uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
+   if(uErr != QCBOR_SUCCESS) {
+      goto Done;
+   }
+
+   QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
+
+Done:
+   pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
+                          const int64_t       nLabel,
+                          const uint8_t       uQcborType,
+                          QCBORItem          *pItem)
+{
    QCBORItem OneItemSeach[2];
+
    OneItemSeach[0].uLabelType  = QCBOR_TYPE_INT64;
    OneItemSeach[0].label.int64 = nLabel;
    OneItemSeach[0].uDataType   = uQcborType;
    OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE; // Indicates end of array
 
-   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
+   QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
+}
 
-   if(uReturn != QCBOR_SUCCESS) {
-      pItem->uDataType  = QCBOR_TYPE_NONE;
-      pItem->uLabelType = QCBOR_TYPE_NONE;
-      goto Done;
-   }
 
-   if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
-      uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
-   }
+/**
+ * @brief Get an item by label by type.
+ *
+ * @param[in] pMe         The decode context.
+ * @param[in] nLabel      The label to search map for.
+ * @param[in] uQcborType  The QCBOR type to look for.
+ * @param[out] pItem      The item found.
+ * @param[out] puOffset   The offset of item for tag consumption check.
+ *
+ * This finds the item with the given label in currently open
+ * map. This does not call QCBORDecode_Private_GetItemChecks()
+ * to check tag number consumption or decode conformance.
+ */
+static void
+QCBORDecode_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
+                                 const int64_t       nLabel,
+                                 const uint8_t       uQcborType,
+                                 QCBORItem          *pItem,
+                                 size_t             *puOffset)
+{
+   QCBORItem OneItemSeach[2];
 
-   *pItem = OneItemSeach[0];
-   QCBORDecode_Private_CopyTags(pMe, pItem);
+   OneItemSeach[0].uLabelType  = QCBOR_TYPE_INT64;
+   OneItemSeach[0].label.int64 = nLabel;
+   OneItemSeach[0].uDataType   = uQcborType;
+   OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE; // Indicates end of array
 
- Done:
-   pMe->uLastError = (uint8_t)uReturn;
+   QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach,  pItem, puOffset);
 }
 
 
@@ -3557,47 +3644,69 @@
 void
 QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
                            const char         *szLabel,
-                           uint8_t             uQcborType,
+                           const uint8_t       uQcborType,
                            QCBORItem          *pItem)
 {
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      return;
-   }
-
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
    QCBORItem OneItemSeach[2];
+
    OneItemSeach[0].uLabelType   = QCBOR_TYPE_TEXT_STRING;
    OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
    OneItemSeach[0].uDataType    = uQcborType;
    OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE; // Indicates end of array
 
-   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
+   QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
 
-   if(uReturn != QCBOR_SUCCESS) {
-      pItem->uDataType  = QCBOR_TYPE_NONE;
-      pItem->uLabelType = QCBOR_TYPE_NONE;
-      goto Done;
-   }
-   if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
-      uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
-      goto Done;
-   }
-
-   *pItem = OneItemSeach[0];
-   QCBORDecode_Private_CopyTags(pMe, pItem);
-
-Done:
 #else
    (void)pMe;
    (void)szLabel;
    (void)uQcborType;
    (void)pItem;
-   QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
+   pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
-   pMe->uLastError = (uint8_t)uReturn;
 }
 
+/**
+ * @brief Get an item by string label of a particular type
+ *
+ * @param[in] pMe         The decode context.
+ * @param[in] szLabel     The label to search map for.
+ * @param[in] uQcborType  The QCBOR type to look for.
+ * @param[out] pItem      The item found.
+ * @param[out] puOffset   The offset of item for tag consumption check.
+ *
+ * This finds the item with the given label in currently open
+ * map. This does not call QCBORDecode_Private_GetItemChecks()
+ * to check tag number consumption or decode conformance.
+ */
+static void
+QCBORDecode_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
+                                  const char         *szLabel,
+                                  const uint8_t       uQcborType,
+                                  QCBORItem          *pItem,
+                                  size_t             *puOffset)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+   QCBORItem OneItemSeach[2];
+
+   OneItemSeach[0].uLabelType   = QCBOR_TYPE_TEXT_STRING;
+   OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+   OneItemSeach[0].uDataType    = uQcborType;
+   OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE; // Indicates end of array
+
+   QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
+
+#else
+   (void)pMe;
+   (void)szLabel;
+   (void)uQcborType;
+   (void)pItem;
+   (void)puOffset;
+   pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
 
 
 /**
@@ -3637,8 +3746,8 @@
    bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
 
    /* Could call GetNext here, but don't need to because this
-    * is only interested in arrays and maps. */
-   uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
+    * is only interested in arrays and maps. TODO: switch to GetNext()? */
+   uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
    if(uErr != QCBOR_SUCCESS) {
       pMe->uLastError = (uint8_t)uErr;
       return;
@@ -3728,6 +3837,10 @@
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return;
    }
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
 
    /* Save the whole position of things so they can be restored.
     * so the cursor position is unchanged by this operation, like
@@ -3746,183 +3859,50 @@
 
 
 
-/**
- * @brief Is a QCBOR_TYPE in the type list?
- *
- * @param[in] uDataType  Type to check for.
- * @param[in] puTypeList  List to check.
- *
- * @retval  QCBOR_SUCCESS             If in the list.
- * @retval QCBOR_ERR_UNEXPECTED_TYPE  Not in the list.
- */
-static QCBORError
-QCBOR_Private_CheckTypeList(const int     uDataType,
-                            const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
-{
-   for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
-      if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
-         return QCBOR_SUCCESS;
-      }
-   }
-   return QCBOR_ERR_UNEXPECTED_TYPE;
-}
-
-
-/**
- * Match a tag/type specification against the type of the item.
- *
- * @param[in] TagSpec  Specification for matching tags.
- * @param[in] pItem    The item to check.
- *
- * @retval QCBOR_SUCCESS   @c uDataType is allowed by @c TagSpec
- * @retval QCBOR_ERR_UNEXPECTED_TYPE @c uDataType is not allowed by @c TagSpec
- *
- * This checks the item data type of untagged items as well as of
- * tagged items against a specification to see if decoding should
- * proceed.
- *
- * This relies on the automatic tag decoding done by QCBOR that turns
- * tag numbers into particular QCBOR_TYPEs so there is no actual
- * comparsion of tag numbers, just of QCBOR_TYPEs.
- *
- * This checks the data item type as possibly representing the tag
- * number or as the tag content type.
- *
- * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
- * data type against the allowed tag content types, but also checks
- * against the tagged types. The QCBOR_TYPEs checked will never be
- * associated with tag numbers, but this checking is needed for the
- * text and byte string use cases .
- */
-static QCBORError
-QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
-                                  const QCBORItem            *pItem)
-{
-   const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
-   const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
-
-#ifndef QCBOR_DISABLE_TAGS
-   /* -Wmaybe-uninitialized falsly warns here */
-   if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
-      pItem->uTags[0] != CBOR_TAG_INVALID16) {
-      /* There are tags that QCBOR couldn't process on this item and
-       * the caller has told us there should not be.
-       */
-      return QCBOR_ERR_UNEXPECTED_TYPE;
-   }
-
-   if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
-      /* Must match the tag number and only the tag */
-      return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
-   }
-
-   QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
-   if(uReturn == QCBOR_SUCCESS) {
-      return QCBOR_SUCCESS;
-   }
-
-   if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
-      /* Must match the content type and only the content type.
-       * There was no match just above so it is a fail. */
-      return QCBOR_ERR_UNEXPECTED_TYPE;
-   }
-
-   /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either
-    * the tag or the content and it hasn't matched the content, so the
-    * end result is whether it matches the tag. This is the tag
-    * optional case that the CBOR standard discourages.
-    */
-
-   return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
-
-#else /* QCBOR_DISABLE_TAGS */
-   if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
-      /* This is only checking base QCBOR types, not those associated
-       * with tag numbers since you can get here with tag numbers.
-       */
-      return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
-   }
-
-   return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
-
-#endif /* QCBOR_DISABLE_TAGS */
-}
-
-
-/**
- * @brief Get an item by label to match a tag specification.
- *
- * @param[in] pMe      The decode context.
- * @param[in] nLabel   The label to search map for.
- * @param[in] TagSpec  The tag number specification to match.
- * @param[out] pItem   The item found.
- *
- * This finds the item with the given label in currently open
- * map. Then checks that its tag number and types matches the tag
- * specification. If not, an error is set in the decode context.
- */
 static void
-QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext         *pMe,
-                                const int64_t               nLabel,
-                                const QCBOR_Private_TagSpec TagSpec,
-                                QCBORItem                  *pItem)
-{
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      return;
-   }
-
-   pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
-}
-
-
-/**
- * @brief Get an item by label to match a tag specification.
- *
- * @param[in] pMe      The decode context.
- * @param[in] szLabel   The label to search map for.
- * @param[in] TagSpec  The tag number specification to match.
- * @param[out] pItem   The item found.
- *
- * This finds the item with the given label in currently open
- * map. Then checks that its tag number and types matches the tag
- * specification. If not, an error is set in the decode context.
- */
-static void
-QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext          *pMe,
-                                 const char                  *szLabel,
-                                 const QCBOR_Private_TagSpec  TagSpec,
-                                 QCBORItem                   *pItem)
-{
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      return;
-   }
-
-   pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
-}
-
+QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext      *pMe,
+                                  QCBORItem               *pItem,
+                                  const uint8_t            uTagRequirement,
+                                  const uint8_t            uQCBORType,
+                                  const uint64_t           uTagNumber,
+                                  QCBORTagContentCallBack *pfCB,
+                                  size_t                   uOffset);
 
 /**
  * @brief Semi-private to get an string by label to match a tag specification.
  *
- * @param[in] pMe      The decode context.
- * @param[in] nLabel   The label to search map for.
- * @param[in] TagSpec  The tag number specification to match.
- * @param[out] pString   The string found.
+ * @param[in] pMe              The decode context.
+ * @param[in] nLabel           Label to search map for.
+ * @param[in] uTagRequirement  Whether or not tag number is required.
+ *                             See @ref QCBOR_TAG_REQUIREMENT_TAG.
+ * @param[in] uQCBOR_Type      QCBOR type to search for.
+ * @param[in] uTagNumber       Tag number to match.
+ * @param[out] pString         The string found.
  *
  * This finds the string  with the given label in currently open
  * map. Then checks that its tag number and types matches the tag
  * specification. If not, an error is set in the decode context.
  */
 void
-QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext         *pMe,
-                                          const int64_t               nLabel,
-                                          const QCBOR_Private_TagSpec TagSpec,
-                                          UsefulBufC                 *pString)
+QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext  *pMe,
+                                          const int64_t        nLabel,
+                                          const uint8_t        uTagRequirement,
+                                          const uint8_t        uQCBOR_Type,
+                                          const uint64_t       uTagNumber,
+                                          UsefulBufC          *pString)
 {
-   QCBORItem Item;
-   QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                    &Item,
+                                     uTagRequirement,
+                                     uQCBOR_Type,
+                                     uTagNumber,
+                                     QCBORDecode_StringsTagCB,
+                                     uOffset);
+
    if(pMe->uLastError == QCBOR_SUCCESS) {
       *pString = Item.val.string;
    }
@@ -3932,22 +3912,39 @@
 /**
  * @brief Semi-private to get an string by label to match a tag specification.
  *
- * @param[in] pMe      The decode context.
- * @param[in] szLabel   The label to search map for.
- * @param[in] TagSpec  The tag number specification to match.
- * @param[out] pString   The string found.
+ * @param[in] pMe              The decode context.
+ * @param[in] szLabel           Label to search map for.
+ * @param[in] uTagRequirement  Whether or not tag number is required.
+ *                             See @ref QCBOR_TAG_REQUIREMENT_TAG.
+ * @param[in] uQCBOR_Type      QCBOR type to search for.
+ * @param[in] uTagNumber       Tag number to match.
+ * @param[out] pString         The string found.
  *
  * This finds the string  with the given label in currently open
  * map. Then checks that its tag number and types matches the tag
  * specification. If not, an error is set in the decode context.
- */void
-QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext         *pMe,
-                                           const char *                szLabel,
-                                           const QCBOR_Private_TagSpec TagSpec,
-                                           UsefulBufC                 *pString)
+  */
+void
+QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext  *pMe,
+                                           const char          *szLabel,
+                                           uint8_t              uTagRequirement,
+                                           uint8_t              uQCBOR_Type,
+                                           uint64_t             uTagNumber,
+                                           UsefulBufC          *pString)
 {
    QCBORItem Item;
-   QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
+   size_t    uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                   &Item,
+                                   uTagRequirement,
+                                   uQCBOR_Type,
+                                   uTagNumber,
+                                   QCBORDecode_StringsTagCB,
+                                   uOffset);
+
+
    if(pMe->uLastError == QCBOR_SUCCESS) {
       *pString = Item.val.string;
    }
@@ -3960,8 +3957,7 @@
 void
 QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
 {
-   QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
-   pMe->uLastError = (uint8_t)uErr;
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
 }
 
 /*
@@ -3974,15 +3970,106 @@
                                       QCBORItemCallback   pfCB)
 {
    MapSearchCallBack CallBack;
+
    CallBack.pCBContext = pCallbackCtx;
    CallBack.pfCallback = pfCB;
 
-   QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
-
-   pMe->uLastError = (uint8_t)uErr;
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
 }
 
 
+#ifndef QCBOR_DISABLE_TAGS
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+QCBORError
+QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
+{
+   size_t         uOffset;
+   MapSearchInfo  Info;
+   QCBORItem      OneItemSeach[2];
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return pMe->uLastError;
+   }
+
+   OneItemSeach[0].uLabelType  = QCBOR_TYPE_INT64;
+   OneItemSeach[0].label.int64 = nLabel;
+   OneItemSeach[0].uDataType   = QCBOR_TYPE_ANY;
+   OneItemSeach[1].uLabelType  = QCBOR_TYPE_NONE; // Indicates end of array
+
+   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+
+   uOffset = Info.uStartOffset;
+   if(uOffset == pMe->uTagNumberCheckOffset) {
+      pMe->uTagNumberIndex++;
+   } else {
+      pMe->uTagNumberIndex = 0;
+   }
+
+   *puTagNumber = CBOR_TAG_INVALID64;
+
+   *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
+   if(*puTagNumber == CBOR_TAG_INVALID64 ||
+      QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+      pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
+   }
+   pMe->uTagNumberCheckOffset = uOffset;
+
+   return uReturn;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+QCBORError
+QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+   size_t         uOffset;
+   MapSearchInfo  Info;
+   QCBORItem      OneItemSeach[2];
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return pMe->uLastError;
+   }
+
+   OneItemSeach[0].uLabelType   = QCBOR_TYPE_TEXT_STRING;
+   OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+   OneItemSeach[0].uDataType    = QCBOR_TYPE_ANY;
+   OneItemSeach[1].uLabelType   = QCBOR_TYPE_NONE; // Indicates end of array
+
+   QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+
+
+   uOffset = Info.uStartOffset;
+   if(uOffset == pMe->uTagNumberCheckOffset) {
+      pMe->uTagNumberIndex++;
+   } else {
+      pMe->uTagNumberIndex = 0;
+   }
+
+   *puTagNumber = CBOR_TAG_INVALID64;
+
+   *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
+   if(*puTagNumber == CBOR_TAG_INVALID64 ||
+      QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+      pMe->uTagNumberIndex = 255; /* All tags clear for this item */
+   }
+   pMe->uTagNumberCheckOffset = uOffset;
+
+   return uReturn;
+#else
+   (void)pMe;
+   (void)szLabel;
+   (void)puTagNumber;
+   return QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
 /**
  * @brief Search for a map/array by label and enter it
  *
@@ -3999,6 +4086,9 @@
 static void
 QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
 {
+   QCBORError     uErr;
+   MapSearchInfo  SearchInfo;
+
    // The first item in pSearch is the one that is to be
    // entered. It should be the only one filled in. Any other
    // will be ignored unless it causes an error.
@@ -4006,8 +4096,10 @@
       return;
    }
 
-   MapSearchInfo Info;
-   pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
+   uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
+
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
+
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return;
    }
@@ -4037,7 +4129,7 @@
     * to be used to get one item and MapSearch() has already found it
     * confirming it exists.
     */
-   UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+   UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
 
    DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
 
@@ -4164,7 +4256,7 @@
       goto Done;
    }
 
-   QCBORDecode_Private_CopyTags(pMe, &Item);
+   QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
 
 
    const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
@@ -4304,6 +4396,16 @@
 }
 
 
+// TODO: re order this file with tags stuff last. bstr is a tag thing
+static QCBORError
+QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
+                                  const QCBORItem *pItem,
+                                  const size_t uOffset,
+                                  const uint8_t *uQCBORTypes,
+                                  const uint64_t *uTagNumbers,
+                                  const uint8_t uTagRequirement,
+                                  bool *bTypeMatched);
+
 /**
  * @brief The main work of entering some byte-string wrapped CBOR.
  *
@@ -4322,31 +4424,41 @@
 QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
                                      const QCBORItem    *pItem,
                                      const uint8_t       uTagRequirement,
+                                     const size_t        uOffset,
                                      UsefulBufC         *pBstr)
 {
+   bool       bTypeMatched;
+   QCBORError uError;
+
+   const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
+   const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
+
+
    if(pBstr) {
       *pBstr = NULLUsefulBufC;
    }
 
    if(pMe->uLastError != QCBOR_SUCCESS) {
-      /* Already in error state; do nothing. */
       return pMe->uLastError;
    }
 
-   QCBORError uError;
-
-   const QCBOR_Private_TagSpec TagSpec =
-      {
-         uTagRequirement,
-         {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-
-   uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
-   if(uError != QCBOR_SUCCESS) {
-      goto Done;
+   if(pItem->uDataAlloc) {
+      return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
    }
 
+   uError = QCBORDecode_Private_CheckTagNType(pMe,
+                                              pItem,
+                                              uOffset,
+                                              uTypes, // TODO: maybe this should be empty
+                                              uTagNumbers,
+                                              uTagRequirement,
+                                             &bTypeMatched);
+
+   if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
+      uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
+   }
+
+
    if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
       /* Reverse the decrement done by GetNext() for the bstr so the
        * increment in QCBORDecode_NestLevelAscender() called by
@@ -4398,6 +4510,23 @@
 }
 
 
+static void
+QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
+{
+#ifndef QCBOR_DISABLE_TAGS
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   *uOffset = QCBORDecode_Tell(pMe);
+#else
+   *uOffset = SIZE_MAX;
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+   pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
+}
+
+
 /*
  * Public function, see header qcbor/qcbor_decode.h file
  */
@@ -4406,26 +4535,14 @@
                              const uint8_t       uTagRequirement,
                              UsefulBufC         *pBstr)
 {
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      // Already in error state; do nothing.
-      return;
-   }
-
-   /* Get the data item that is the byte string being entered */
    QCBORItem Item;
-   pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      return;
-   }
+   size_t    uOffset;
 
-   if(Item.uDataAlloc) {
-      pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
-      return;
-   }
-
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
    pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
                                                                   &Item,
                                                                    uTagRequirement,
+                                                                   uOffset,
                                                                    pBstr);
 }
 
@@ -4440,11 +4557,13 @@
                                      UsefulBufC         *pBstr)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+   size_t    uOffset;
 
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
    pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
                                                                   &Item,
                                                                    uTagRequirement,
+                                                                   uOffset,
                                                                    pBstr);
 }
 
@@ -4459,11 +4578,13 @@
                                       UsefulBufC         *pBstr)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+   size_t    uOffset;
 
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
    pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
                                                                   &Item,
                                                                    uTagRequirement,
+                                                                   uOffset,
                                                                    pBstr);
 }
 
@@ -4665,56 +4786,214 @@
 
 
 
-/**
- * @brief Common processing for an epoch date.
- *
- * @param[in] pMe              The decode context.
- * @param[in] pItem            The item with the date.
- * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pnTime          The returned date.
- *
- * Common processing for the date tag. Mostly make sure the tag
- * content is correct and copy forward any further other tag numbers.
- */
-static void
-QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
-                                     QCBORItem          *pItem,
-                                     const uint8_t       uTagRequirement,
-                                     int64_t            *pnTime)
+
+#ifndef QCBOR_DISABLE_TAGS
+// TODO:  uTagNumber might be better a list than calling this multiple times
+static QCBORError
+QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
+                                    const QCBORItem          *pItem,
+                                    const uint64_t            uTagNumber,
+                                    const size_t              uOffset)
 {
+   if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
+      /* There are no tag numbers at all, so no unprocessed */
+      return QCBOR_SUCCESS;
+   }
+
+   /* There are some tag numbers, so keep checking. This check passes
+    * if there is one and only one tag number that matches uTagNumber
+    */
+
+   // TODO: behave different in v1 and v2?
+
+   const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
+
+   if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
+      /* The only tag number is the one we are processing so no unprocessed */
+      return QCBOR_SUCCESS;
+   }
+
+   if(uOffset != pMe->uTagNumberCheckOffset) {
+      /* processed tag numbers are for some other item, not us */
+      return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+   }
+
+   if(pMe->uTagNumberIndex != 1) {
+      return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+   }
+
+   return QCBOR_SUCCESS;
+}
+#endif
+
+
+static QCBORError
+QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
+                                  const QCBORItem    *pItem,
+                                  const size_t        uOffset,
+                                  const uint8_t      *uQCBORTypes,
+                                  const uint64_t     *uTagNumbers,
+                                  const uint8_t       uTagRequirement,
+                                  bool               *bTypeMatched)
+{
+   const int      nTagReq   = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
+
+   *bTypeMatched = false;
+   for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
+      if(pItem->uDataType == *pTNum) {
+         *bTypeMatched = true;
+         break;
+      }
+   }
+
+#ifndef QCBOR_DISABLE_TAGS
+   bool        bTagNumberMatched;
+   QCBORError  uErr;
+   const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
+
+   bTagNumberMatched = false;
+   for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
+      if(uInnerTag == *pQType) {
+         bTagNumberMatched = true;
+         break;
+      }
+   }
+
+
+   if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
+      /* There must be a tag number */
+      if(!bTagNumberMatched && !*bTypeMatched) {
+         return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
+      }
+
+   } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
+      if(bTagNumberMatched || *bTypeMatched) {
+         return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
+      }
+
+   } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
+      /* No check necessary */
+   }
+
+   /* Now check if there are extra tags and if there's an error in them */
+   if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
+      /* The flag to ignore extra is not set, so keep checking */
+      for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
+         uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
+         if(uErr != QCBOR_SUCCESS) {
+            return uErr;
+         }
+      }
+   }
+
+   return QCBOR_SUCCESS;
+#else
+   (void)pMe;
+   (void)uOffset;
+   (void)uTagNumbers;
+
+   if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
+      return QCBOR_SUCCESS;
+   } else {
+      return QCBOR_ERR_UNEXPECTED_TYPE;
+   }
+
+#endif
+
+}
+
+
+static void
+QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext      *pMe,
+                                        QCBORItem               *pItem,
+                                        const uint8_t            uTagRequirement,
+                                        const uint8_t            uQCBORTypes[],
+                                        const uint64_t           uTagNumbers[],
+                                        QCBORTagContentCallBack *pfCB,
+                                        size_t                   uOffset)
+{
+   QCBORError uErr;
+   bool       bTypeMatched;
+
    if(pMe->uLastError != QCBOR_SUCCESS) {
-      // Already in error state, do nothing
       return;
    }
 
-   QCBORError uErr;
-
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
-   };
-
-   uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
+   uErr = QCBORDecode_Private_CheckTagNType(pMe,
+                                            pItem,
+                                            uOffset,
+                                            uQCBORTypes,
+                                            uTagNumbers,
+                                            uTagRequirement,
+                                            &bTypeMatched);
    if(uErr != QCBOR_SUCCESS) {
       goto Done;
    }
 
-   if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
-      uErr = QCBOR_Private_DecodeDateEpoch(pItem);
+   if(!bTypeMatched) {
+      /* Tag content wasn't previously processed, do it now */
+      uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
       if(uErr != QCBOR_SUCCESS) {
          goto Done;
       }
    }
 
-   *pnTime = pItem->val.epochDate.nSeconds;
-
 Done:
    pMe->uLastError = (uint8_t)uErr;
 }
 
 
+/*
+ **/
+static void
+QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext      *pMe,
+                                   QCBORItem               *pItem,
+                                   const uint8_t            uTagRequirement,
+                                   const uint8_t            uQCBORTypes[],
+                                   const uint64_t           uTagNumber,
+                                   QCBORTagContentCallBack *pfCB,
+                                   size_t                   uOffset)
+{
+   uint64_t auTagNumbers[2];
+
+   auTagNumbers[0] = uTagNumber;
+   auTagNumbers[1] = CBOR_TAG_INVALID64;
+
+   QCBORDecode_Private_ProcessTagItemMulti(pMe,
+                                           pItem,
+                                           uTagRequirement,
+                                           uQCBORTypes,
+                                           auTagNumbers,
+                                           pfCB,
+                                           uOffset);
+}
+
+
+static void
+QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext     *pMe,
+                                  QCBORItem               *pItem,
+                                  const uint8_t            uTagRequirement,
+                                  const uint8_t            uQCBORType,
+                                  const uint64_t           uTagNumber,
+                                  QCBORTagContentCallBack *pfCB,
+                                  const size_t             uOffset)
+{
+   uint8_t auQCBORType[2];
+
+   auQCBORType[0] = uQCBORType;
+   auQCBORType[1] = QCBOR_TYPE_NONE;
+
+   QCBORDecode_Private_ProcessTagItem(pMe,
+                                      pItem,
+                                      uTagRequirement,
+                                      auQCBORType,
+                                      uTagNumber,
+                                      pfCB,
+                                      uOffset);
+}
+
+
+
 
 /*
  * Public function, see header qcbor/qcbor_spiffy_decode.h file
@@ -4725,8 +5004,17 @@
                          int64_t            *pnTime)
 {
    QCBORItem  Item;
-   QCBORDecode_VGetNext(pMe, &Item);
-   QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                     &Item,
+                                     uTagRequirement,
+                                     QCBOR_TYPE_DATE_EPOCH,
+                                     CBOR_TAG_DATE_EPOCH,
+                                     QCBORDecode_DateEpochTagCB,
+                                     uOffset);
+   *pnTime = Item.val.epochDate.nSeconds;
 }
 
 
@@ -4740,8 +5028,17 @@
                                int64_t            *pnTime)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
-   QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
+   size_t uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                     &Item,
+                                     uTagRequirement,
+                                     QCBOR_TYPE_DATE_EPOCH,
+                                     CBOR_TAG_DATE_EPOCH,
+                                     QCBORDecode_DateEpochTagCB,
+                                     uOffset);
+   *pnTime = Item.val.epochDate.nSeconds;
 }
 
 
@@ -4755,60 +5052,17 @@
                                 int64_t            *pnTime)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
-   QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
-}
+   size_t uOffset;
 
-
-
-/**
- * @brief Common processing for an epoch date.
- *
- * @param[in] pMe              The decode context.
- * @param[in] pItem            The item with the date.
- * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pnDays          The returned day count.
- *
- * Common processing for the RFC 8943 day-count tag. Mostly make sure
- * the tag content is correct and copy forward any further other tag
- * numbers.
- */
-static void
-QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
-                                     QCBORItem          *pItem,
-                                     uint8_t             uTagRequirement,
-                                     int64_t            *pnDays)
-{
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      /* Already in error state, do nothing */
-      return;
-   }
-
-   QCBORError uErr;
-
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
-   if(uErr != QCBOR_SUCCESS) {
-      goto Done;
-   }
-
-   if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
-      uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
-      if(uErr != QCBOR_SUCCESS) {
-         goto Done;
-      }
-   }
-
-   *pnDays = pItem->val.epochDays;
-
-Done:
-   pMe->uLastError = (uint8_t)uErr;
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                     &Item,
+                                     uTagRequirement,
+                                     QCBOR_TYPE_DATE_EPOCH,
+                                     CBOR_TAG_DATE_EPOCH,
+                                     QCBORDecode_DateEpochTagCB,
+                                     uOffset);
+   *pnTime = Item.val.epochDate.nSeconds;
 }
 
 
@@ -4821,8 +5075,17 @@
                          int64_t            *pnDays)
 {
    QCBORItem  Item;
-   QCBORDecode_VGetNext(pMe, &Item);
-   QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                     &Item,
+                                     uTagRequirement,
+                                     QCBOR_TYPE_DAYS_EPOCH,
+                                     CBOR_TAG_DAYS_EPOCH,
+                                     QCBORDecode_DaysEpochTagCB,
+                                     uOffset);
+   *pnDays = Item.val.epochDays;
 }
 
 
@@ -4836,8 +5099,17 @@
                                int64_t            *pnDays)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
-   QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
+   size_t uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                     &Item,
+                                     uTagRequirement,
+                                     QCBOR_TYPE_DAYS_EPOCH,
+                                     CBOR_TAG_DAYS_EPOCH,
+                                     QCBORDecode_DaysEpochTagCB,
+                                     uOffset);
+   *pnDays = Item.val.epochDays;
 }
 
 
@@ -4851,33 +5123,45 @@
                                 int64_t            *pnDays)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
-   QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
+   size_t    uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                      &Item,
+                                      uTagRequirement,
+                                      QCBOR_TYPE_DAYS_EPOCH,
+                                      CBOR_TAG_DAYS_EPOCH,
+                                      QCBORDecode_DaysEpochTagCB,
+                                      uOffset);
+   *pnDays = Item.val.epochDays;
 }
 
 
 
-/*
- * @brief Get a string that matches the type/tag specification.
- */
+
 void
-QCBORDecode_Private_GetTaggedString(QCBORDecodeContext         *pMe,
-                                    const QCBOR_Private_TagSpec TagSpec,
-                                    UsefulBufC                 *pBstr)
+QCBORDecode_Private_GetTaggedString(QCBORDecodeContext  *pMe,
+                                    const uint8_t        uTagRequirement,
+                                    const uint8_t        uQCBOR_Type,
+                                    const uint64_t       uTagNumber,
+                                    UsefulBufC          *pStr)
 {
    QCBORItem  Item;
+   size_t uOffset;
 
-   QCBORDecode_VGetNext(pMe, &Item);
-   if(pMe->uLastError) {
-      return;
-   }
-
-   pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ProcessTagOne(pMe,
+                                     &Item,
+                                      uTagRequirement,
+                                      uQCBOR_Type,
+                                      uTagNumber,
+                                      QCBORDecode_StringsTagCB,
+                                      uOffset);
 
    if(pMe->uLastError == QCBOR_SUCCESS) {
-      *pBstr = Item.val.string;
+      *pStr = Item.val.string;
    } else {
-      *pBstr = NULLUsefulBufC;
+      *pStr = NULLUsefulBufC;
    }
 }
 
@@ -4889,85 +5173,140 @@
  *
  * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
  * @param[in] pItem            The item with the date.
- * @param[out] pValue          The returned big number
+ * @param[out] pBignumber          The returned big number
  * @param[out] pbIsNegative  The returned sign of the big number.
  *
  * Common processing for the big number tag. Mostly make sure
  * the tag content is correct and copy forward any further other tag
  * numbers.
  */
-static QCBORError
-QCBOR_Private_ProcessBigNum(const uint8_t   uTagRequirement,
-                            const QCBORItem *pItem,
-                            UsefulBufC      *pValue,
-                            bool            *pbIsNegative)
+static void
+QCBORDecode_Private_BigNumberRawMain(QCBORDecodeContext *pMe,
+                                     const uint8_t       uTagRequirement,
+                                     QCBORItem          *pItem,
+                                     UsefulBufC         *pBignumber,
+                                     bool               *pbIsNegative,
+                                     size_t              uOffset)
 {
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
+   // TODO: refer to the static const ones instead
 
-   QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
-   if(uErr != QCBOR_SUCCESS) {
-      return uErr;
+   const uint8_t puTypes[] = {QCBOR_TYPE_POSBIGNUM,QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE};
+
+   const uint64_t puTNs[] = {CBOR_TAG_POS_BIGNUM, CBOR_TAG_NEG_BIGNUM, CBOR_TAG_INVALID64};
+
+   QCBORDecode_Private_ProcessTagItemMulti(pMe,
+                                           pItem,
+                                           uTagRequirement,
+                                           puTypes,
+                                           puTNs,
+                                           QCBORDecode_StringsTagCB,
+                                           uOffset);
+   if(pMe->uLastError) {
+      return;
    }
 
-   *pValue = pItem->val.string;
-
    if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
       *pbIsNegative = false;
    } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
       *pbIsNegative = true;
    }
-
-   return QCBOR_SUCCESS;
+   *pBignumber = pItem->val.bigNum;
 }
 
 
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h
- */
-void
-QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
-                      const uint8_t       uTagRequirement,
-                      UsefulBufC         *pValue,
-                      bool               *pbIsNegative)
+static void
+QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
+                            const uint8_t       uTagRequirement,
+                            QCBORItem          *pItem,
+                            UsefulBufC         *pValue,
+                            bool               *pbIsTag257,
+                            size_t              uOffset)
 {
-   QCBORItem  Item;
-   QCBORDecode_VGetNext(pMe, &Item);
+   QCBORError uErr;
+
+   const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
+
+   const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
+
+   QCBORDecode_Private_ProcessTagItemMulti(pMe,
+                                           pItem,
+                                           uTagRequirement,
+                                           puTypes,
+                                           puTNs,
+                                           QCBORDecode_MIMETagCB,
+                                           uOffset);
    if(pMe->uLastError) {
       return;
    }
 
-   pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
-                                                          &Item,
-                                                          pValue,
-                                                          pbIsNegative);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h
- */
-void
-QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
-                            const int64_t       nLabel,
-                            const uint8_t       uTagRequirement,
-                            UsefulBufC         *pValue,
-                            bool               *pbIsNegative)
-{
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      return;
+   if(pItem->uDataType == QCBOR_TYPE_MIME) {
+      *pbIsTag257 = false;
+   } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
+      *pbIsTag257 = true;
    }
+   *pValue = pItem->val.string;
 
-   pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
-                                                          &Item,
-                                                          pValue,
-                                                          pbIsNegative);
+
+   uErr = QCBOR_SUCCESS;
+
+   pMe->uLastError = (uint8_t)uErr;
+}
+
+
+void
+QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
+                           const uint8_t       uTagRequirement,
+                           UsefulBufC         *pMessage,
+                           bool               *pbIsTag257)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_GetMIME(pMe,
+                               uTagRequirement,
+                              &Item,
+                               pMessage,
+                               pbIsTag257,
+                               uOffset);
+}
+
+void
+QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
+                                 const int64_t       nLabel,
+                                 const uint8_t       uTagRequirement,
+                                 UsefulBufC         *pMessage,
+                                 bool               *pbIsTag257)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_GetMIME(pMe,
+                                uTagRequirement,
+                               &Item,
+                                pMessage,
+                                pbIsTag257,
+                                uOffset);
+}
+
+void
+QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
+                                  const char         *szLabel,
+                                  const uint8_t       uTagRequirement,
+                                  UsefulBufC         *pMessage,
+                                  bool               *pbIsTag257)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_GetMIME(pMe,
+                                uTagRequirement,
+                               &Item,
+                                pMessage,
+                                pbIsTag257,
+                                uOffset);
 }
 
 
@@ -4975,79 +5314,69 @@
  * Public function, see header qcbor/qcbor_spiffy_decode.h
  */
 void
-QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
-                             const char         *szLabel,
+QCBORDecode_GetTBigNumberRaw(QCBORDecodeContext *pMe,
                              const uint8_t       uTagRequirement,
-                             UsefulBufC         *pValue,
+                             UsefulBufC         *pBignumber,
                              bool               *pbIsNegative)
 {
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
-   if(pMe->uLastError != QCBOR_SUCCESS) {
-      return;
-   }
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
-                                                          &Item,
-                                                          pValue,
-                                                          pbIsNegative);
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberRawMain(pMe,
+                                        uTagRequirement,
+                                       &Item,
+                                        pBignumber,
+                                        pbIsNegative,
+                                        uOffset);
 }
 
-
-
-/**
- * @brief Common processing for MIME tag (semi-private).
- *
- * @param[in] uTagRequirement  One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[in] pItem            The item with the date.
- * @param[out] pMessage        The returned MIME message.
- * @param[out] pbIsTag257      If true, binary MIME, if not, text MIME.
- *
- * Common processing for the MIME tag. Mostly make sure the tag
- * content is correct and copy forward any further other tag
- * numbers. See QCBORDecode_GetMIMEMessage().
+/*
+ * Public function, see header qcbor/qcbor_spiffy_decode.h
  */
-QCBORError
-QCBORDecode_Private_GetMIME(const uint8_t     uTagRequirement,
-                            const QCBORItem  *pItem,
-                            UsefulBufC       *pMessage,
-                            bool             *pbIsTag257)
+void
+QCBORDecode_GetTBigNumberRawInMapN(QCBORDecodeContext *pMe,
+                                   const int64_t       nLabel,
+                                   const uint8_t       uTagRequirement,
+                                   UsefulBufC         *pBigNumber,
+                                   bool               *pbIsNegative)
 {
-   const QCBOR_Private_TagSpec TagSpecText =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
-   const QCBOR_Private_TagSpec TagSpecBinary =
-      {
-         uTagRequirement,
-         {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
-         {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-      };
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   QCBORError uReturn;
-
-   if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
-      *pMessage = pItem->val.string;
-      if(pbIsTag257 != NULL) {
-         *pbIsTag257 = false;
-      }
-      uReturn = QCBOR_SUCCESS;
-   } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
-      *pMessage = pItem->val.string;
-      if(pbIsTag257 != NULL) {
-         *pbIsTag257 = true;
-      }
-      uReturn = QCBOR_SUCCESS;
-
-   } else {
-      uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
-   }
-
-   return uReturn;
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberRawMain(pMe,
+                                        uTagRequirement,
+                                       &Item,
+                                        pBigNumber,
+                                        pbIsNegative,
+                                        uOffset);
 }
 
+/*
+ * Public function, see header qcbor/qcbor_spiffy_decode.h
+ */
+void
+QCBORDecode_GetTBigNumberRawInMapSZ(QCBORDecodeContext *pMe,
+                                    const char         *szLabel,
+                                    const uint8_t       uTagRequirement,
+                                    UsefulBufC         *pBigNumber,
+                                    bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberRawMain(pMe,
+                                        uTagRequirement,
+                                       &Item,
+                                        pBigNumber,
+                                        pbIsNegative,
+                                        uOffset);
+}
+
+
+
 // Improvement: add methods for wrapped CBOR, a simple alternate
 // to EnterBstrWrapped
 
@@ -5410,6 +5739,8 @@
                                             int64_t         *pnResult)
 {
    uint64_t uResult;
+   QCBORError uError;
+
    /* The negative integer furthest from zero for a C int64_t is
     * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
     * negative number in CBOR is computed as -n - 1 where n is the
@@ -5422,9 +5753,7 @@
     *   -n - 1 <= -INT64_MAX - 1
     *    n     <= INT64_MAX.
     */
-   QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
-                                                             INT64_MAX,
-                                                             &uResult);
+   uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
    if(uError != QCBOR_SUCCESS) {
       return uError;
    }
@@ -5509,6 +5838,12 @@
          }
          break;
 
+      case QCBOR_TYPE_65BIT_NEG_INT:
+         /* This type occurs if the value won't fit into int64_t
+          * so this is always an error. */
+         return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
+         break;
+
       default:
          return  QCBOR_ERR_UNEXPECTED_TYPE;
    }
@@ -5912,12 +6247,15 @@
 
       case QCBOR_TYPE_UINT64:
          if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
-            *puValue =  pItem->val.uint64;
+            *puValue = pItem->val.uint64;
          } else {
             return QCBOR_ERR_UNEXPECTED_TYPE;
          }
          break;
 
+      case QCBOR_TYPE_65BIT_NEG_INT:
+         return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
+
       default:
          return QCBOR_ERR_UNEXPECTED_TYPE;
    }
@@ -6297,6 +6635,15 @@
          return QCBOR_ERR_HW_FLOAT_DISABLED;
 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
 
+      case QCBOR_TYPE_65BIT_NEG_INT:
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+         // TODO: don't use float HW. We have the function to do it.
+         *pdValue = -(double)pItem->val.uint64 - 1;
+         break;
+#else
+         return QCBOR_ERR_HW_FLOAT_DISABLED;
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+
       default:
          return QCBOR_ERR_UNEXPECTED_TYPE;
    }
@@ -6669,79 +7016,8 @@
    return UsefulOutBuf_OutUBuf(&UOB);
 }
 
-
-/**
- * @brief Check and/or complete exponent and mantissa item.
- *
- * @param[in] pMe        The decoder context.
- * @param[in] TagSpec    Expected type(s).
- * @param[in,out] pItem  See below.
- *
- * This is for decimal fractions and big floats, both of which are an
- * exponent and mantissa.
- *
- * If the item item had a tag number indicating it was a
- * decimal fraction or big float, then the input @c pItem will
- * have been decoded as exponent and mantissa. If there was
- * no tag number, the caller is asking this be decoded as a
- * big float or decimal fraction and @c pItem just has the
- * first item in an exponent and mantissa.
- *
- * On output, the item is always a fully decoded decimal fraction or
- * big float.
- *
- * This errors out if the input type does not meet the TagSpec.
- */
-static QCBORError
-QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext         *pMe,
-                                     const QCBOR_Private_TagSpec TagSpec,
-                                     QCBORItem                  *pItem)
-{
-   QCBORError uErr;
-
-   /* pItem could either be a decoded exponent and mantissa or
-    * the opening array of an undecoded exponent and mantissa. This
-    * check will succeed on either, but doesn't say which it was.
-    */
-   uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
-   if(uErr != QCBOR_SUCCESS) {
-      goto Done;
-   }
-
-   if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
-      /* The item is an array, which means is is an undecoded exponent
-       * and mantissa. This call consumes the items in the array and
-       * results in a decoded exponent and mantissa in pItem. This is
-       * the case where there was no tag.
-       */
-      uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
-      if(uErr != QCBOR_SUCCESS) {
-         goto Done;
-      }
-
-      /* The above decode didn't determine whether it is a decimal
-       * fraction or big num. Which of these two depends on what the
-       * caller wants it decoded as since there is no tag, so fish the
-       * type out of the TagSpec. */
-      pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
-
-      /* No need to check the type again. All that we need to know was
-       * that it decoded correctly as a exponent and mantissa. The
-       * QCBOR type is set out by what was requested.
-       */
-   }
-
-   /* If the item was not an array and the check passed, then
-    * it is a fully decoded big float or decimal fraction and
-    * matches what is requested.
-    */
-
-Done:
-   return uErr;
-}
-
-
 /* Some notes from the work to disable tags.
+ * Some are out of date since tag refactoring.
  *
  * The API for big floats and decimal fractions seems good.
  * If there's any issue with it it's that the code size to
@@ -6772,11 +7048,30 @@
  * vary by a TagSpec.
  */
 
+
+static const uint8_t QCBORDecode_Private_DecimalFractionTypes[] = {
+   QCBOR_TYPE_DECIMAL_FRACTION,
+   QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
+   QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
+   QCBOR_TYPE_DECIMAL_FRACTION_POS_U64,
+   QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64,
+   QCBOR_TYPE_NONE};
+
+static const uint8_t QCBORDecode_Private_BigFloatTypes[] = {
+   QCBOR_TYPE_BIGFLOAT,
+   QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
+   QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM,
+   QCBOR_TYPE_BIGFLOAT_POS_U64,
+   QCBOR_TYPE_BIGFLOAT_NEG_U64,
+   QCBOR_TYPE_NONE};
+
 /**
- * @brief Common processor for exponent and mantissa.
+ * @brief Common processor for exponent and int64_t mantissa.
  *
  * @param[in] pMe          The decode context.
- * @param[in] TagSpec      The expected/allowed tags.
+ * @param[in] uTagRequirement  Whether tag number must be present or not.
+ * @param[in] uTagNumber   The tag number for which content is expected.
+ * @param[in] uOffset   Cursor offset for  tag number consumption checking.
  * @param[in] pItem        The data item to process.
  * @param[out] pnMantissa  The returned mantissa as an int64_t.
  * @param[out] pnExponent  The returned exponent as an int64_t.
@@ -6784,25 +7079,51 @@
  * This handles exponent and mantissa for base 2 and 10. This
  * is limited to a mantissa that is an int64_t. See also
  * QCBORDecode_Private_ProcessExpMantissaBig().
+ *
+ * On output, the item is always a fully decoded decimal fraction or
+ * big float.
+ *
+ * This errors out if the input tag and type aren't as required.
+ *
+ * This always provides the correctly offset mantissa, even when the
+ * input CBOR is a negative big number. This works the
+ * same in QCBOR v1 and v2.
  */
 static void
-QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext         *pMe,
-                                 const QCBOR_Private_TagSpec TagSpec,
-                                 QCBORItem                  *pItem,
-                                 int64_t                    *pnMantissa,
-                                 int64_t                    *pnExponent)
+QCBORDecode_Private_ExpIntMantissaMain(QCBORDecodeContext  *pMe,
+                                       const uint8_t        uTagRequirement,
+                                       const uint64_t       uTagNumber,
+                                       const size_t         uOffset,
+                                       QCBORItem           *pItem,
+                                       int64_t             *pnMantissa,
+                                       int64_t             *pnExponent)
 {
-   QCBORError uErr;
+   QCBORError     uErr;
+   const uint8_t *qTypes;
 
    if(pMe->uLastError) {
       return;
    }
 
-   uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
-   if(uErr != QCBOR_SUCCESS) {
-      goto Done;
+   if(uTagNumber == CBOR_TAG_BIGFLOAT) {
+      qTypes = QCBORDecode_Private_BigFloatTypes;
+   } else {
+      qTypes = QCBORDecode_Private_DecimalFractionTypes;
    }
 
+   QCBORDecode_Private_ProcessTagItem(pMe,
+                                      pItem,
+                                      uTagRequirement,
+                                      qTypes,
+                                      uTagNumber,
+                                      QCBORDecode_ExpMantissaTagCB,
+                                      uOffset);
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   uErr = QCBOR_SUCCESS;
    switch (pItem->uDataType) {
 
       case QCBOR_TYPE_DECIMAL_FRACTION:
@@ -6826,50 +7147,58 @@
          break;
 #endif /* QCBOR_DISABLE_TAGS */
 
+      case QCBOR_TYPE_BIGFLOAT_NEG_U64:
+      case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
+      case QCBOR_TYPE_BIGFLOAT_POS_U64:
+      case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
+         uErr = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
+         break;
+
       default:
          uErr = QCBOR_ERR_UNEXPECTED_TYPE;
    }
 
-   Done:
-      pMe->uLastError = (uint8_t)uErr;
+   pMe->uLastError = (uint8_t)uErr;
 }
 
-
-/**
- * @brief Decode exponent and mantissa into a big number.
- *
- * @param[in] pMe                The decode context.
- * @param[in] TagSpec            The expected/allowed tags.
- * @param[in] pItem              Item to decode and convert.
- * @param[in] BufferForMantissa  Buffer to output mantissa into.
- * @param[out] pMantissa         The output mantissa.
- * @param[out] pbIsNegative      The sign of the output.
- * @param[out] pnExponent        The mantissa of the output.
- *
- * This is the common processing of a decimal fraction or a big float
- * into a big number. This will decode and consume all the CBOR items
- * that make up the decimal fraction or big float.
- */
 static void
-QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext          *pMe,
-                                          const QCBOR_Private_TagSpec  TagSpec,
-                                          QCBORItem                   *pItem,
-                                          const UsefulBuf              BufferForMantissa,
-                                          UsefulBufC                  *pMantissa,
-                                          bool                        *pbIsNegative,
-                                          int64_t                     *pnExponent)
+QCBORDecode_Private_ExpBigMantissaRawMain(QCBORDecodeContext  *pMe,
+                                          const uint8_t        uTagRequirement,
+                                          const uint64_t       uTagNumber,
+                                          const size_t         uOffset,
+                                          QCBORItem           *pItem,
+                                          const UsefulBuf      BufferForMantissa,
+                                          UsefulBufC          *pMantissa,
+                                          bool                *pbIsNegative,
+                                          int64_t             *pnExponent)
 {
-   QCBORError uErr;
-   uint64_t   uMantissa;
+   QCBORError     uErr;
+   uint64_t       uMantissa;
+   const uint8_t *qTypes;
+
+   if(pMe->uLastError) {
+      return;
+   }
+
+   if(uTagNumber == CBOR_TAG_BIGFLOAT) {
+      qTypes = QCBORDecode_Private_BigFloatTypes;
+   } else {
+      qTypes = QCBORDecode_Private_DecimalFractionTypes;
+   }
+
+   QCBORDecode_Private_ProcessTagItem(pMe,
+                                      pItem,
+                                      uTagRequirement,
+                                      qTypes,
+                                      uTagNumber,
+                                      QCBORDecode_ExpMantissaTagCB,
+                                      uOffset);
 
    if(pMe->uLastError != QCBOR_SUCCESS) {
       return;
    }
 
-   uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
-   if(uErr != QCBOR_SUCCESS) {
-      goto Done;
-   }
+   uErr = QCBOR_SUCCESS;
 
    switch (pItem->uDataType) {
 
@@ -6918,7 +7247,108 @@
          uErr = QCBOR_ERR_UNEXPECTED_TYPE;
    }
 
-Done:
+   pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/**
+ * @brief Decode exponent and mantissa into a big number with negative offset of 1.
+ *
+ * @param[in] pMe                The decode context.
+ * @param[in] uTagRequirement  Whether a tag number must be present or not.
+ * @param[in] pItem              Item to decode and convert.
+ * @param[in] BufferForMantissa  Buffer to output mantissa into.
+ * @param[out] pMantissa         The output mantissa.
+ * @param[out] pbIsNegative      The sign of the output.
+ * @param[out] pnExponent        The mantissa of the output.
+ *
+ * This is the common processing of a decimal fraction or a big float
+ * into a big number. This will decode and consume all the CBOR items
+ * that make up the decimal fraction or big float.
+ *
+ * This performs the subtraction of 1 from the negative value so the
+ * caller doesn't need to. This links more object code than QCBORDecode_Private_ProcessExpMantissaBig().
+ */
+static void
+QCBORDecode_Private_ExpBigMantissaMain(QCBORDecodeContext  *pMe,
+                                       const uint8_t        uTagRequirement,
+                                       const uint64_t       uTagNumber,
+                                       const size_t         uOffset,
+                                       QCBORItem           *pItem,
+                                       const UsefulBuf      BufferForMantissa,
+                                       UsefulBufC          *pMantissa,
+                                       bool                *pbIsNegative,
+                                       int64_t             *pnExponent)
+{
+   QCBORError     uErr;
+   QCBORItem      TempMantissa;
+   const uint8_t *qTypes;
+
+   if(pMe->uLastError) {
+      return;
+   }
+
+   if(uTagNumber == CBOR_TAG_BIGFLOAT) {
+      qTypes = QCBORDecode_Private_BigFloatTypes;
+   } else {
+      qTypes = QCBORDecode_Private_DecimalFractionTypes;
+   }
+
+   QCBORDecode_Private_ProcessTagItem(pMe,
+                                      pItem,
+                                      uTagRequirement,
+                                      qTypes,
+                                      uTagNumber,
+                                      QCBORDecode_ExpMantissaTagCB,
+                                      uOffset);
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   memset(&TempMantissa, 0, sizeof(TempMantissa));
+
+   switch (pItem->uDataType) {
+
+      case QCBOR_TYPE_DECIMAL_FRACTION:
+      case QCBOR_TYPE_BIGFLOAT:
+         TempMantissa.uDataType = QCBOR_TYPE_INT64;
+         TempMantissa.val.int64 = pItem->val.expAndMantissa.Mantissa.nInt;
+         break;
+
+      case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
+      case QCBOR_TYPE_BIGFLOAT_POS_U64:
+         TempMantissa.uDataType = QCBOR_TYPE_UINT64;
+         TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
+         break;
+
+      case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
+      case QCBOR_TYPE_BIGFLOAT_NEG_U64:
+         TempMantissa.uDataType = QCBOR_TYPE_65BIT_NEG_INT;
+         TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
+         break;
+
+#ifndef QCBOR_DISABLE_TAGS
+         /* If tags are disabled, mantissas can never be big nums */
+      case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
+      case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
+         TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
+         TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
+         *pbIsNegative = false;
+         break;
+
+      case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
+      case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
+         TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
+         TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
+         *pbIsNegative = true;
+         break;
+#endif /* ! QCBOR_DISABLE_TAGS */
+   }
+
+   *pnExponent = pItem->val.expAndMantissa.nExponent;
+   uErr = QCBORDecode_ProcessBigNumber(TempMantissa, BufferForMantissa, pMantissa, pbIsNegative);
+
    pMe->uLastError = (uint8_t)uErr;
 }
 
@@ -6927,27 +7357,22 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
-                               const uint8_t       uTagRequirement,
-                               int64_t             *pnMantissa,
-                               int64_t             *pnExponent)
+QCBORDecode_GetTDecimalFraction(QCBORDecodeContext *pMe,
+                                const uint8_t       uTagRequirement,
+                                int64_t             *pnMantissa,
+                                int64_t             *pnExponent)
 {
-   QCBORItem Item;
-   QCBORDecode_VGetNext(pMe, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
-         QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBOR_Private_ProcessExpMantissa(pMe,
-                                    TagSpec,
-                                   &Item,
-                                    pnMantissa,
-                                    pnExponent);
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ExpIntMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          uOffset,
+                                         &Item,
+                                          pnMantissa,
+                                          pnExponent);
 }
 
 
@@ -6955,57 +7380,24 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
-                                     const int64_t       nLabel,
-                                     const uint8_t       uTagRequirement,
-                                     int64_t             *pnMantissa,
-                                     int64_t             *pnExponent)
-{
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
-
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
-         QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBOR_Private_ProcessExpMantissa(pMe,
-                                    TagSpec,
-                                   &Item,
-                                    pnMantissa,
-                                    pnExponent);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
-                                      const char         *szLabel,
+QCBORDecode_GetTDecimalFractionInMapN(QCBORDecodeContext *pMe,
+                                      const int64_t       nLabel,
                                       const uint8_t       uTagRequirement,
                                       int64_t             *pnMantissa,
                                       int64_t             *pnExponent)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+   size_t    uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
-         QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpIntMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          uOffset,
+                                         &Item,
+                                          pnMantissa,
+                                          pnExponent);
 
-   QCBOR_Private_ProcessExpMantissa(pMe,
-                                    TagSpec,
-                                   &Item,
-                                    pnMantissa,
-                                    pnExponent);
 }
 
 
@@ -7013,26 +7405,127 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
-                                  const uint8_t       uTagRequirement,
-                                  const UsefulBuf     MantissaBuffer,
-                                  UsefulBufC         *pMantissa,
-                                  bool               *pbMantissaIsNegative,
-                                  int64_t            *pnExponent)
+QCBORDecode_GetTDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
+                                       const char         *szLabel,
+                                       const uint8_t       uTagRequirement,
+                                       int64_t             *pnMantissa,
+                                       int64_t             *pnExponent)
 {
-   QCBORItem Item;
-   QCBORDecode_VGetNext(pMe, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
-         QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpIntMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          uOffset,
+                                         &Item,
+                                          pnMantissa,
+                                          pnExponent);
+}
 
-   QCBORDecode_Private_ProcessExpMantissaBig(pMe,
-                                             TagSpec,
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTDecimalFractionBigMantissa(QCBORDecodeContext *pMe,
+                                           const uint8_t       uTagRequirement,
+                                           const UsefulBuf     MantissaBuffer,
+                                           UsefulBufC         *pMantissa,
+                                           bool               *pbMantissaIsNegative,
+                                           int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          uOffset,
+                                         &Item,
+                                          MantissaBuffer,
+                                          pMantissa,
+                                          pbMantissaIsNegative,
+                                          pnExponent);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTDecimalFractionBigMantissaInMapN(QCBORDecodeContext *pMe,
+                                                 const int64_t       nLabel,
+                                                 const uint8_t       uTagRequirement,
+                                                 const UsefulBuf     BufferForMantissa,
+                                                 UsefulBufC         *pMantissa,
+                                                 bool               *pbIsNegative,
+                                                 int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          uOffset,
+                                         &Item,
+                                          BufferForMantissa,
+                                          pMantissa,
+                                          pbIsNegative,
+                                          pnExponent);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTDecimalFractionBigMantissaInMapSZ(QCBORDecodeContext *pMe,
+                                                  const char         *szLabel,
+                                                  const uint8_t       uTagRequirement,
+                                                  const UsefulBuf     BufferForMantissa,
+                                                  UsefulBufC         *pMantissa,
+                                                  bool               *pbIsNegative,
+                                                  int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_DECIMAL_FRACTION,
+                                          uOffset,
+                                         &Item,
+                                          BufferForMantissa,
+                                          pMantissa,
+                                          pbIsNegative,
+                                          pnExponent);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTDecimalFractionBigMantissaRaw(QCBORDecodeContext *pMe,
+                                              const uint8_t       uTagRequirement,
+                                              const UsefulBuf     MantissaBuffer,
+                                              UsefulBufC         *pMantissa,
+                                              bool               *pbMantissaIsNegative,
+                                              int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_DECIMAL_FRACTION,
+                                             uOffset,
                                             &Item,
                                              MantissaBuffer,
                                              pMantissa,
@@ -7045,28 +7538,22 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
-                                        const int64_t       nLabel,
-                                        const uint8_t       uTagRequirement,
-                                        const UsefulBuf     BufferForMantissa,
-                                        UsefulBufC         *pMantissa,
-                                        bool               *pbIsNegative,
-                                        int64_t            *pnExponent)
+QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(QCBORDecodeContext *pMe,
+                                                    const int64_t       nLabel,
+                                                    const uint8_t       uTagRequirement,
+                                                    const UsefulBuf     BufferForMantissa,
+                                                    UsefulBufC         *pMantissa,
+                                                    bool               *pbIsNegative,
+                                                    int64_t            *pnExponent)
 {
-
    QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+   size_t    uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
-         QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBORDecode_Private_ProcessExpMantissaBig(pMe,
-                                             TagSpec,
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_DECIMAL_FRACTION,
+                                             uOffset,
                                             &Item,
                                              BufferForMantissa,
                                              pMantissa,
@@ -7079,27 +7566,22 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
-                                         const char         *szLabel,
-                                         const uint8_t       uTagRequirement,
-                                         const UsefulBuf     BufferForMantissa,
-                                         UsefulBufC         *pMantissa,
-                                         bool               *pbIsNegative,
-                                         int64_t            *pnExponent)
+QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
+                                                     const char         *szLabel,
+                                                     const uint8_t       uTagRequirement,
+                                                     const UsefulBuf     BufferForMantissa,
+                                                     UsefulBufC         *pMantissa,
+                                                     bool               *pbIsNegative,
+                                                     int64_t            *pnExponent)
 {
    QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+   size_t    uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
-         QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBORDecode_Private_ProcessExpMantissaBig(pMe,
-                                             TagSpec,
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_DECIMAL_FRACTION,
+                                             uOffset,
                                             &Item,
                                              BufferForMantissa,
                                              pMantissa,
@@ -7112,27 +7594,22 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
-                        const uint8_t       uTagRequirement,
-                        int64_t             *pnMantissa,
-                        int64_t             *pnExponent)
+QCBORDecode_GetTBigFloat(QCBORDecodeContext *pMe,
+                         const uint8_t       uTagRequirement,
+                         int64_t             *pnMantissa,
+                         int64_t             *pnExponent)
 {
-   QCBORItem Item;
-   QCBORDecode_VGetNext(pMe, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
-         QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBOR_Private_ProcessExpMantissa(pMe,
-                                    TagSpec,
-                                   &Item,
-                                    pnMantissa,
-                                    pnExponent);
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ExpIntMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          uOffset,
+                                         &Item,
+                                          pnMantissa,
+                                          pnExponent);
 }
 
 
@@ -7140,57 +7617,23 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
-                              const int64_t       nLabel,
-                              const uint8_t       uTagRequirement,
-                              int64_t            *pnMantissa,
-                              int64_t            *pnExponent)
-{
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
-
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
-         QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBOR_Private_ProcessExpMantissa(pMe,
-                                    TagSpec,
-                                   &Item,
-                                    pnMantissa,
-                                    pnExponent);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
-                               const char         *szLabel,
+QCBORDecode_GetTBigFloatInMapN(QCBORDecodeContext *pMe,
+                               const int64_t       nLabel,
                                const uint8_t       uTagRequirement,
                                int64_t            *pnMantissa,
                                int64_t            *pnExponent)
 {
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
-         QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBOR_Private_ProcessExpMantissa(pMe,
-                                    TagSpec,
-                                   &Item,
-                                    pnMantissa,
-                                    pnExponent);
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpIntMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          uOffset,
+                                         &Item,
+                                          pnMantissa,
+                                          pnExponent);
 }
 
 
@@ -7198,26 +7641,126 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
-                           const uint8_t       uTagRequirement,
-                           const UsefulBuf     MantissaBuffer,
-                           UsefulBufC         *pMantissa,
-                           bool               *pbMantissaIsNegative,
-                           int64_t            *pnExponent)
+QCBORDecode_GetTBigFloatInMapSZ(QCBORDecodeContext *pMe,
+                                const char         *szLabel,
+                                const uint8_t       uTagRequirement,
+                                int64_t            *pnMantissa,
+                                int64_t            *pnExponent)
 {
-   QCBORItem Item;
-   QCBORDecode_VGetNext(pMe, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
-         QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpIntMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          uOffset,
+                                         &Item,
+                                          pnMantissa,
+                                          pnExponent);
+}
 
-   QCBORDecode_Private_ProcessExpMantissaBig(pMe,
-                                             TagSpec,
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTBigFloatBigMantissa(QCBORDecodeContext *pMe,
+                                    const uint8_t       uTagRequirement,
+                                    const UsefulBuf     MantissaBuffer,
+                                    UsefulBufC         *pMantissa,
+                                    bool               *pbMantissaIsNegative,
+                                    int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          uOffset,
+                                         &Item,
+                                          MantissaBuffer,
+                                          pMantissa,
+                                          pbMantissaIsNegative,
+                                          pnExponent);
+}
+
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTBigFloatBigMantissaInMapN(QCBORDecodeContext *pMe,
+                                          const int64_t       nLabel,
+                                          const uint8_t       uTagRequirement,
+                                          const UsefulBuf     BufferForMantissa,
+                                          UsefulBufC         *pMantissa,
+                                          bool               *pbIsNegative,
+                                          int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          uOffset,
+                                         &Item,
+                                          BufferForMantissa,
+                                          pMantissa,
+                                          pbIsNegative,
+                                          pnExponent);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetTBigFloatBigMantissaInMapSZ(QCBORDecodeContext *pMe,
+                                           const char         *szLabel,
+                                           const uint8_t       uTagRequirement,
+                                           const UsefulBuf     BufferForMantissa,
+                                           UsefulBufC         *pMantissa,
+                                           bool               *pbIsNegative,
+                                           int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaMain(pMe,
+                                          uTagRequirement,
+                                          CBOR_TAG_BIGFLOAT,
+                                          uOffset,
+                                         &Item,
+                                          BufferForMantissa,
+                                          pMantissa,
+                                          pbIsNegative,
+                                          pnExponent);
+}
+
+
+void
+QCBORDecode_GetTBigFloatBigMantissaRaw(QCBORDecodeContext *pMe,
+                                       const uint8_t       uTagRequirement,
+                                       const UsefulBuf     MantissaBuffer,
+                                       UsefulBufC         *pMantissa,
+                                       bool               *pbMantissaIsNegative,
+                                       int64_t            *pnExponent)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_BIGFLOAT,
+                                             uOffset,
                                             &Item,
                                              MantissaBuffer,
                                              pMantissa,
@@ -7226,31 +7769,28 @@
 }
 
 
+
+
 /*
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
-                                 const int64_t       nLabel,
-                                 const uint8_t       uTagRequirement,
-                                 const UsefulBuf     BufferForMantissa,
-                                 UsefulBufC         *pMantissa,
-                                 bool               *pbIsNegative,
-                                 int64_t            *pnExponent)
+QCBORDecode_GetTBigFloatBigMantissaRawInMapN(QCBORDecodeContext *pMe,
+                                             const int64_t       nLabel,
+                                             const uint8_t       uTagRequirement,
+                                             const UsefulBuf     BufferForMantissa,
+                                             UsefulBufC         *pMantissa,
+                                             bool               *pbIsNegative,
+                                             int64_t            *pnExponent)
 {
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+   QCBORItem  Item;
+   size_t     uOffset;
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
-         QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBORDecode_Private_ProcessExpMantissaBig(pMe,
-                                             TagSpec,
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_BIGFLOAT,
+                                             uOffset,
                                             &Item,
                                              BufferForMantissa,
                                              pMantissa,
@@ -7263,32 +7803,552 @@
  * Public function, see header qcbor/qcbor_decode.h file
  */
 void
-QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
-                                  const char         *szLabel,
+QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
+                                              const char         *szLabel,
+                                              const uint8_t       uTagRequirement,
+                                              const UsefulBuf     BufferForMantissa,
+                                              UsefulBufC         *pMantissa,
+                                              bool               *pbIsNegative,
+                                              int64_t            *pnExponent)
+{
+   QCBORItem Item;
+   size_t    uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
+                                             uTagRequirement,
+                                             CBOR_TAG_BIGFLOAT,
+                                             uOffset,
+                                            &Item,
+                                             BufferForMantissa,
+                                             pMantissa,
+                                             pbIsNegative,
+                                             pnExponent);
+}
+
+
+#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
+
+
+#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+/*
+ * Public function, see header qcbor/qcbor_spiffy_decode.h file
+ */
+void
+QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
+                                      QCBORItem          *pNumber)
+{
+   QCBORItem            Item;
+   struct IEEE754_ToInt ToInt;
+   double               dNum;
+   QCBORError           uError;
+
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   // TODO:VGetNext?
+   uError = QCBORDecode_GetNext(pMe, &Item);
+   if(uError != QCBOR_SUCCESS) {
+      *pNumber = Item;
+      pMe->uLastError = (uint8_t)uError;
+      return;
+   }
+
+   switch(Item.uDataType) {
+      case QCBOR_TYPE_INT64:
+      case QCBOR_TYPE_UINT64:
+         *pNumber = Item;
+         break;
+
+      case QCBOR_TYPE_DOUBLE:
+         ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
+         if(ToInt.type == IEEE754_ToInt_IS_INT) {
+            pNumber->uDataType = QCBOR_TYPE_INT64;
+            pNumber->val.int64 = ToInt.integer.is_signed;
+         } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
+            if(ToInt.integer.un_signed <= INT64_MAX) {
+               /* Do the same as base QCBOR integer decoding */
+               pNumber->uDataType = QCBOR_TYPE_INT64;
+               pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
+            } else {
+               pNumber->uDataType = QCBOR_TYPE_UINT64;
+               pNumber->val.uint64 = ToInt.integer.un_signed;
+            }
+         } else {
+            *pNumber = Item;
+         }
+         break;
+
+      case QCBOR_TYPE_FLOAT:
+         ToInt = IEEE754_SingleToInt(Item.val.fnum);
+         if(ToInt.type == IEEE754_ToInt_IS_INT) {
+            pNumber->uDataType = QCBOR_TYPE_INT64;
+            pNumber->val.int64 = ToInt.integer.is_signed;
+         } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
+            if(ToInt.integer.un_signed <= INT64_MAX) {
+               /* Do the same as base QCBOR integer decoding */
+               pNumber->uDataType = QCBOR_TYPE_INT64;
+               pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
+            } else {
+               pNumber->uDataType = QCBOR_TYPE_UINT64;
+               pNumber->val.uint64 = ToInt.integer.un_signed;
+            }
+         } else {
+            *pNumber = Item;
+         }
+         break;
+
+      case QCBOR_TYPE_65BIT_NEG_INT:
+         if(Item.val.uint64 == UINT64_MAX) {
+            /* The value -18446744073709551616 is encoded as an
+             * unsigned 18446744073709551615. It's a whole number that
+             * needs to be returned as a double. It can't be handled
+             * by IEEE754_UintToDouble because 18446744073709551616
+             * doesn't fit into a uint64_t. You can't get it by adding
+             * 1 to 18446744073709551615.
+             */
+            pNumber->val.dfnum = -18446744073709551616.0;
+            pNumber->uDataType = QCBOR_TYPE_DOUBLE;
+         } else {
+            dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
+            if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
+               *pNumber = Item;
+            } else {
+               pNumber->val.dfnum = dNum;
+               pNumber->uDataType = QCBOR_TYPE_DOUBLE;
+            }
+         }
+         break;
+
+      default:
+         pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+         pNumber->uDataType = QCBOR_TYPE_NONE;
+         break;
+   }
+}
+
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+
+
+
+static UsefulBufC
+QCBORDecode_IntToBigNumber(uint64_t         uNum,
+                           const UsefulBuf  BigNumberBuf)
+{
+   UsefulOutBuf OB;
+
+   /* With a UsefulOutBuf, there's no pointer math here. */
+   UsefulOutBuf_Init(&OB, BigNumberBuf);
+
+   /* Must copy one byte even if zero.  The loop, mask and shift
+    * algorithm provides endian conversion.
+    */
+   do {
+      UsefulOutBuf_InsertByte(&OB, uNum & 0xff, 0);
+      uNum >>= 8;
+   } while(uNum);
+
+   return UsefulOutBuf_OutUBuf(&OB);
+}
+
+
+/* Add one to the big number and put the result in a new UsefulBufC
+ * from storage in UsefulBuf.
+ *
+ * Leading zeros must be removed before calling this.
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+static UsefulBufC
+QCBORDecode_BigNumberCopyPlusOne(UsefulBufC BigNumber,
+                                 UsefulBuf  BigNumberBuf)
+{
+   uint8_t        uCarry;
+   uint8_t        uSourceValue;
+   const uint8_t *pSource;
+   uint8_t       *pDest;
+   ptrdiff_t      uDestBytesLeft;
+
+   /* Start adding at the LSB */
+   pSource = &((const uint8_t *)BigNumber.ptr)[BigNumber.len-1];
+   pDest   = &((uint8_t *)BigNumberBuf.ptr)[BigNumberBuf.len-1];
+
+   uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
+   *pDest = *pSource + 1;
+   while(1) {
+      /* Wrap around from 0xff to 0 is a defined operation for
+       * unsigned addition in C.*/
+      if(*pDest != 0) {
+         /*  The add operation didn't wrap so no more carry. This
+          * funciton only adds one, so when there is no more carry,
+          * carrying is over to the end.
+          */
+         uCarry = 0;
+      }
+
+      uDestBytesLeft = pDest - (uint8_t *)BigNumberBuf.ptr;
+      if(pSource <= (const uint8_t *)BigNumber.ptr && uCarry == 0) {
+         break; /* Successful exit */
+      }
+      if(pSource > (const uint8_t *)BigNumber.ptr) {
+         uSourceValue = *--pSource;
+      } else {
+         /* All source bytes processed, but not the last carry */
+         uSourceValue = 0;
+      }
+
+      pDest--;
+      if(uDestBytesLeft < 0) {
+         return NULLUsefulBufC; /* Not enough space in destination buffer */
+      }
+
+      *pDest = uSourceValue + uCarry;
+   }
+
+   return (UsefulBufC){pDest, BigNumberBuf.len - (size_t)uDestBytesLeft};
+}
+
+
+/* This returns 1 when uNum is 0 */
+static size_t
+QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
+{
+   size_t uCount = 0;
+   do {
+      uCount++;
+      uNum >>= 8;
+   } while(uNum);
+
+   return uCount;
+}
+
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+QCBORError
+QCBORDecode_ProcessBigNumberNoPreferred(const QCBORItem Item,
+                                        const UsefulBuf BigNumberBuf,
+                                        UsefulBufC     *pBigNumber,
+                                        bool           *pbIsNegative)
+{
+   size_t      uLen;
+   UsefulBufC  BigNumber;
+   int         uType;
+
+   uType = Item.uDataType;
+   if(uType == QCBOR_TYPE_BYTE_STRING) {
+      uType = *pbIsNegative ? QCBOR_TYPE_NEGBIGNUM : QCBOR_TYPE_POSBIGNUM;
+   }
+
+   static const uint8_t Zero[] = {0x00};
+   BigNumber = UsefulBuf_SkipLeading(Item.val.bigNum, 0);
+   if(BigNumber.len == 0) {
+      BigNumber = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
+   }
+
+   /* Compute required length so it can be returned if buffer is too small */
+   switch(uType) {
+
+      case QCBOR_TYPE_POSBIGNUM:
+         uLen = BigNumber.len;
+         break;
+
+      case QCBOR_TYPE_NEGBIGNUM:
+         uLen = BigNumber.len;
+         if(UsefulBuf_IsValue(UsefulBuf_SkipLeading(BigNumber, 0), 0xff) == SIZE_MAX) {
+            uLen++;
+         }
+         break;
+
+      default:
+         return QCBOR_ERR_UNEXPECTED_TYPE;
+   }
+
+   *pBigNumber = (UsefulBufC){NULL, uLen};
+
+   if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
+      return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
+      /* Buffer is too short or type is wrong */
+   }
+
+
+   if(uType == QCBOR_TYPE_POSBIGNUM) {
+      *pBigNumber = UsefulBuf_Copy(BigNumberBuf, BigNumber);
+      *pbIsNegative = false;
+   } else if(uType == QCBOR_TYPE_NEGBIGNUM) {
+      /* The messy one. Take the stuff in the buffer and copy it to
+       * the new buffer, adding one to it. This might be one byte
+       * bigger than the original because of the carry from adding
+       * one.*/
+      *pbIsNegative = true;
+      *pBigNumber = QCBORDecode_BigNumberCopyPlusOne(BigNumber, BigNumberBuf);
+   }
+
+   return QCBOR_SUCCESS;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+QCBORError
+QCBORDecode_ProcessBigNumber(const QCBORItem Item,
+                             UsefulBuf       BigNumberBuf,
+                             UsefulBufC     *pBigNumber,
+                             bool           *pbIsNegative)
+{
+   QCBORError  uResult;
+   size_t      uLen;
+   int         uType;
+
+   uType = Item.uDataType;
+
+   switch(uType) {
+      case QCBOR_TYPE_POSBIGNUM:
+      case QCBOR_TYPE_NEGBIGNUM:
+      case QCBOR_TYPE_BYTE_STRING:
+         return QCBORDecode_ProcessBigNumberNoPreferred(Item, BigNumberBuf, pBigNumber, pbIsNegative);
+         break;
+
+      case QCBOR_TYPE_INT64:
+         uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)ABSOLUTE_VALUE(Item.val.int64));
+         break;
+
+      case QCBOR_TYPE_UINT64:
+         uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
+         break;
+
+      case QCBOR_TYPE_65BIT_NEG_INT:
+         uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
+         break;
+
+      default:
+         return QCBOR_ERR_UNEXPECTED_TYPE;
+   }
+
+
+   *pBigNumber = (UsefulBufC){NULL, uLen};
+
+   if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
+      return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
+      /* Buffer is too short or type is wrong */
+   }
+
+   uResult = QCBOR_SUCCESS;
+
+   if(uType == QCBOR_TYPE_UINT64) {
+      *pBigNumber = QCBORDecode_IntToBigNumber(Item.val.uint64, BigNumberBuf);
+      *pbIsNegative = false;
+   } else if(uType == QCBOR_TYPE_INT64) {
+      /* Offset of 1 for negative numbers already performed */
+      *pbIsNegative = Item.val.int64 < 0;
+      *pBigNumber = QCBORDecode_IntToBigNumber((uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64), BigNumberBuf);
+   } else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
+      /* Offset of 1 for negative numbers NOT already performed */
+      *pbIsNegative = true;
+      if(Item.val.uint64 == UINT64_MAX) {
+         /* The one value that can't be done with a computation
+          * because it would overflow a uint64_t */
+         static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+         *pBigNumber = UsefulBuf_Copy(BigNumberBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
+      } else {
+         // TODO: why + 1; test it; document it
+         *pBigNumber = QCBORDecode_IntToBigNumber(Item.val.uint64 + 1, BigNumberBuf);
+      }
+   }
+
+   return uResult;
+}
+
+
+static const uint64_t QCBORDecode_Private_BigNumberTagNumbers[] = {
+   CBOR_TAG_POS_BIGNUM,
+   CBOR_TAG_NEG_BIGNUM,
+   CBOR_TAG_INVALID64};
+
+static const uint8_t QCBORDecode_Private_BigNumberTypes[] = {
+   QCBOR_TYPE_INT64,
+   QCBOR_TYPE_UINT64,
+   QCBOR_TYPE_65BIT_NEG_INT,
+   QCBOR_TYPE_POSBIGNUM,
+   QCBOR_TYPE_NEGBIGNUM,
+   QCBOR_TYPE_NONE};
+
+#define QCBORDecode_Private_BigNumberTypesNoPreferred &QCBORDecode_Private_BigNumberTypes[3]
+
+
+static void
+QCBORDecode_Private_BigNumberNoPreferredMain(QCBORDecodeContext *pMe,
+                                             const uint8_t       uTagRequirement,
+                                             QCBORItem          *pItem,
+                                             const size_t        uOffset,
+                                             UsefulBuf           BigNumberBuf,
+                                             UsefulBufC         *pBigNumber,
+                                             bool               *pbIsNegative)
+{
+   QCBORDecode_Private_ProcessTagItemMulti(pMe,
+                                           pItem,
+                                           uTagRequirement,
+                                           QCBORDecode_Private_BigNumberTypesNoPreferred,
+                                           QCBORDecode_Private_BigNumberTagNumbers,
+                                           QCBORDecode_StringsTagCB,
+                                           uOffset);
+   if(pMe->uLastError) {
+      return;
+   }
+
+   pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumberNoPreferred(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
+}
+
+
+static void
+QCBORDecode_Private_BigNumberMain(QCBORDecodeContext *pMe,
                                   const uint8_t       uTagRequirement,
-                                  const UsefulBuf     BufferForMantissa,
-                                  UsefulBufC         *pMantissa,
-                                  bool               *pbIsNegative,
-                                  int64_t            *pnExponent)
+                                  QCBORItem          *pItem,
+                                  const size_t        uOffset,
+                                  UsefulBuf           BigNumberBuf,
+                                  UsefulBufC         *pBigNumber,
+                                  bool               *pbIsNegative)
 {
-   QCBORItem Item;
-   QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+   QCBORDecode_Private_ProcessTagItemMulti(pMe,
+                                           pItem,
+                                           uTagRequirement,
+                                           QCBORDecode_Private_BigNumberTypes,
+                                           QCBORDecode_Private_BigNumberTagNumbers,
+                                           QCBORDecode_StringsTagCB,
+                                           uOffset);
+   if(pMe->uLastError) {
+      return;
+   }
 
-   const QCBOR_Private_TagSpec TagSpec =
-   {
-      uTagRequirement,
-      {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
-         QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
-      {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
-   };
-
-   QCBORDecode_Private_ProcessExpMantissaBig(pMe,
-                                             TagSpec,
-                                            &Item,
-                                             BufferForMantissa,
-                                             pMantissa,
-                                             pbIsNegative,
-                                             pnExponent);
+   pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumber(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
 }
 
-#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+void
+QCBORDecode_GetTBigNumber(QCBORDecodeContext *pMe,
+                          const uint8_t       uTagRequirement,
+                          UsefulBuf           BigNumberBuf,
+                          UsefulBufC         *pBigNumber,
+                          bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
+}
+
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+void
+QCBORDecode_GetTBigNumberInMapN(QCBORDecodeContext *pMe,
+                                const int64_t       nLabel,
+                                const uint8_t       uTagRequirement,
+                                UsefulBuf           BigNumberBuf,
+                                UsefulBufC         *pBigNumber,
+                                bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberMain(pMe,
+                                     uTagRequirement,
+                                    &Item,
+                                     uOffset,
+                                     BigNumberBuf,
+                                     pBigNumber,
+                                     pbIsNegative);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+void
+QCBORDecode_GetTBigNumberInMapSZ(QCBORDecodeContext *pMe,
+                                 const char         *szLabel,
+                                 const uint8_t       uTagRequirement,
+                                 UsefulBuf           BigNumberBuf,
+                                 UsefulBufC         *pBigNumber,
+                                 bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberMain(pMe,
+                                     uTagRequirement,
+                                    &Item,
+                                     uOffset,
+                                     BigNumberBuf,
+                                     pBigNumber,
+                                     pbIsNegative);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+void
+QCBORDecode_GetTBigNumberNoPreferred(QCBORDecodeContext *pMe,
+                                     const uint8_t       uTagRequirement,
+                                     UsefulBuf           BigNumberBuf,
+                                     UsefulBufC         *pBigNumber,
+                                     bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+void
+QCBORDecode_GetTBigNumberNoPreferredInMapN(QCBORDecodeContext *pMe,
+                                           const int64_t       nLabel,
+                                           const uint8_t       uTagRequirement,
+                                           UsefulBuf           BigNumberBuf,
+                                           UsefulBufC         *pBigNumber,
+                                           bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
+
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h
+ */
+void
+QCBORDecode_GetTBigNumberNoPreferredInMapSZ(QCBORDecodeContext *pMe,
+                                            const char         *szLabel,
+                                            const uint8_t       uTagRequirement,
+                                            UsefulBuf           BigNumberBuf,
+                                            UsefulBufC         *pBigNumber,
+                                            bool               *pbIsNegative)
+{
+   QCBORItem  Item;
+   size_t     uOffset;
+
+   QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+   QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
+}
+
+// TODO: re order above functions in tag number order
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index c30cbce..47208a8 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -35,6 +35,10 @@
 #include "qcbor/qcbor_encode.h"
 #include "ieee754.h"
 
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+#include <math.h> /* Only for NAN definition */
+#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
 
 /**
  * @file qcbor_encode.c
@@ -183,7 +187,7 @@
  * 4, 5             QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
  *                  QCBOREncode_OpenMapOrArrayIndefiniteLength(),
  *                  QCBOREncode_CloseMapOrArrayIndefiniteLength()
- * 6                QCBOREncode_AddTag()
+ * 6                QCBOREncode_AddTagNumber()
  * 7                QCBOREncode_AddDouble(), QCBOREncode_AddFloat(),
  *                  QCBOREncode_AddDoubleNoPreferred(),
  *                  QCBOREncode_AddFloatNoPreferred(), QCBOREncode_AddType7()
@@ -248,6 +252,11 @@
  */
 
 
+/* Forward declaration for reference in QCBOREncode_Init() */
+static void
+QCBOREncode_Private_CloseMapUnsorted(QCBOREncodeContext *pMe);
+
+
 /*
  * Public function for initialization. See qcbor/qcbor_encode.h
  */
@@ -257,6 +266,7 @@
    memset(pMe, 0, sizeof(QCBOREncodeContext));
    UsefulOutBuf_Init(&(pMe->OutBuf), Storage);
    Nesting_Init(&(pMe->nesting));
+   pMe->pfnCloseMap = QCBOREncode_Private_CloseMapUnsorted;
 }
 
 
@@ -529,7 +539,7 @@
  * @param pMe         Encoder context.
  * @param uMajorType  Major type to insert.
  * @param uArgument   The argument (an integer value or a length).
- * @param uMinLen     The minimum number of bytes for encoding the CBOR argument.
+ * @param uMinLen     Minimum number of bytes for encoding the CBOR argument.
  *
  * This formats the CBOR "head" and appends it to the output.
  *
@@ -581,9 +591,9 @@
    if(nNum < 0) {
       /* In CBOR -1 encodes as 0x00 with major type negative int.
        * First add one as a signed integer because that will not
-       * overflow. Then change the sign as needed for encoding.  (The
+       * overflow. Then change the sign as needed for encoding (the
        * opposite order, changing the sign and subtracting, can cause
-       * an overflow when encoding INT64_MIN. */
+       * an overflow when encoding INT64_MIN). */
       int64_t nTmp = nNum + 1;
       uValue = (uint64_t)-nTmp;
       uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
@@ -641,10 +651,53 @@
  * without a loss of precision. See QCBOREncode_AddDouble().
  */
 void
-QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum)
+QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, double dNum)
 {
-   const IEEE754_union uNum = IEEE754_DoubleToSmaller(dNum, true);
-   QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue);
+   IEEE754_union        FloatResult;
+   bool                 bNoNaNPayload;
+   struct IEEE754_ToInt IntResult;
+   uint64_t             uNegValue;
+
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   if(IEEE754_DoubleHasNaNPayload(dNum) && !(pMe->uAllow & QCBOR_ENCODE_ALLOW_NAN_PAYLOAD)) {
+      pMe->uError = QCBOR_ERR_NOT_ALLOWED;
+      return;
+   }
+#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+   if(pMe->uMode == QCBOR_ENCODE_MODE_DCBOR) {
+      IntResult = IEEE754_DoubleToInt(dNum);
+      switch(IntResult.type) {
+         case IEEE754_ToInt_IS_INT:
+            QCBOREncode_AddInt64(pMe, IntResult.integer.is_signed);
+            return;
+         case IEEE754_ToInt_IS_UINT:
+            QCBOREncode_AddUInt64(pMe, IntResult.integer.un_signed);
+            return;
+         case IEEE754_ToInt_IS_65BIT_NEG:
+            {
+               if(IntResult.integer.un_signed == 0) {
+                  uNegValue = UINT64_MAX;
+               } else {
+                  uNegValue = IntResult.integer.un_signed-1;
+               }
+               QCBOREncode_AddNegativeUInt64(pMe, uNegValue);
+            }
+            return;
+         case IEEE754_ToInt_NaN:
+            dNum = NAN;
+            bNoNaNPayload = true;
+            break;
+         case IEEE754_ToInt_NO_CONVERSION:
+            bNoNaNPayload = true;
+      }
+   } else  {
+      bNoNaNPayload = false;
+   }
+
+   FloatResult = IEEE754_DoubleToSmaller(dNum, true, bNoNaNPayload);
+
+   QCBOREncode_Private_AddType7(pMe, (uint8_t)FloatResult.uSize, FloatResult.uValue);
 }
 
 
@@ -658,24 +711,310 @@
  * without a loss of precision. See QCBOREncode_AddFloat().
  */
 void
-QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum)
+QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, float fNum)
 {
-   const IEEE754_union uNum = IEEE754_SingleToHalf(fNum);
-   QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue);
+   IEEE754_union        FloatResult;
+   bool                 bNoNaNPayload;
+   struct IEEE754_ToInt IntResult;
+   uint64_t             uNegValue;
+
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   if(IEEE754_SingleHasNaNPayload(fNum) && !(pMe->uAllow & QCBOR_ENCODE_ALLOW_NAN_PAYLOAD)) {
+      pMe->uError = QCBOR_ERR_NOT_ALLOWED;
+      return;
+   }
+#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+   if(pMe->uMode == QCBOR_ENCODE_MODE_DCBOR) {
+      IntResult = IEEE754_SingleToInt(fNum);
+      switch(IntResult.type) {
+         case IEEE754_ToInt_IS_INT:
+            QCBOREncode_AddInt64(pMe, IntResult.integer.is_signed);
+            return;
+         case IEEE754_ToInt_IS_UINT:
+            QCBOREncode_AddUInt64(pMe, IntResult.integer.un_signed);
+            return;
+         case IEEE754_ToInt_IS_65BIT_NEG:
+            {
+               if(IntResult.integer.un_signed == 0) {
+                  uNegValue = UINT64_MAX;
+               } else {
+                  uNegValue = IntResult.integer.un_signed-1;
+               }
+               QCBOREncode_AddNegativeUInt64(pMe, uNegValue);
+            }
+            return;
+         case IEEE754_ToInt_NaN:
+            fNum = NAN;
+            bNoNaNPayload = true;
+            break;
+         case IEEE754_ToInt_NO_CONVERSION:
+            bNoNaNPayload = true;
+      }
+   } else  {
+      bNoNaNPayload = false;
+   }
+
+   FloatResult = IEEE754_SingleToHalf(fNum, bNoNaNPayload);
+
+   QCBOREncode_Private_AddType7(pMe, (uint8_t)FloatResult.uSize, FloatResult.uValue);
 }
 #endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
 
 
+
+
+/**
+ * @brief Convert a big number to unsigned integer.
+ *
+ * @param[in]  BigNumber  Big number to convert.
+ *
+ * @return Converted unsigned.
+ *
+ * The big number must be less than 8 bytes long.
+ **/
+static uint64_t
+QCBOREncode_Private_BigNumberToUInt(const UsefulBufC BigNumber)
+{
+   uint64_t uInt;
+   size_t   uIndex;
+
+   uInt = 0;
+   for(uIndex = 0; uIndex < BigNumber.len; uIndex++) {
+      uInt = (uInt << 8) + UsefulBufC_NTH_BYTE(BigNumber, uIndex);
+   }
+
+   return uInt;
+}
+
+
+/**
+ * @brief Is there a carry when you subtract 1 from the BigNumber.
+ *
+ * @param[in]  BigNumber  Big number to check for carry.
+ *
+ * @return If there is a carry, \c true.
+ *
+ * If this returns @c true, then @c BigNumber - 1 is
+ * one byte shorter than @c BigNumber.
+ **/
+static bool
+QCBOREncode_Private_BigNumberCarry(const UsefulBufC BigNumber)
+{
+   bool       bCarry;
+   UsefulBufC SubBigNum;
+
+   // Improvement: rework without recursion?
+
+   if(BigNumber.len == 0) {
+      return true; /* Subtracting one from zero-length string gives a carry */
+   } else {
+      SubBigNum = UsefulBuf_Tail(BigNumber, 1);
+      bCarry = QCBOREncode_Private_BigNumberCarry(SubBigNum);
+      if(UsefulBufC_NTH_BYTE(BigNumber, 0) == 0x00 && bCarry) {
+         /* Subtracting one from 0 gives a carry */
+         return true;
+      } else {
+         return false;
+      }
+   }
+}
+
+
+/*
+ * @brief Output negative bignum bytes with subtraction of 1.
+ *
+ * @param[in] pMe              The decode context.
+ * @param[in] uTagRequirement  Either @ref QCBOR_ENCODE_AS_TAG or
+ *                             @ref QCBOR_ENCODE_AS_BORROWED.
+ * @param[in] BigNumber        The negative big number.
+ */
+static void
+QCBOREncode_Private_AddTNegativeBigNumber(QCBOREncodeContext *pMe,
+                                          const uint8_t       uTagRequirement,
+                                          const UsefulBufC    BigNumber)
+{
+   size_t     uLen;
+   bool       bCarry;
+   bool       bCopiedSomething;
+   uint8_t    uByte;
+   UsefulBufC SubString;
+   UsefulBufC NextSubString;
+
+   QCBOREncode_Private_BigNumberTag(pMe, uTagRequirement, true);
+
+   /* This works on any length without the need of an additional buffer */
+
+   /* This subtracts one, possibly making the string shorter by one
+    * 0x01 -> 0x00
+    * 0x01 0x00 -> 0xff
+    * 0x00 0x01 0x00 -> 0x00 0xff
+    * 0x02 0x00 -> 0x01 0xff
+    * 0xff -> 0xfe
+    * 0xff 0x00 -> 0xfe 0xff
+    * 0x01 0x00 0x00 -> 0xff 0xff
+    *
+    * This outputs the big number a byte at a time to be able to operate on
+    * a big number of any length without memory allocation.
+    */
+
+   /* Compute the length up front because it goes in the encoded head */
+   bCarry = QCBOREncode_Private_BigNumberCarry(UsefulBuf_Tail(BigNumber, 1));
+   uLen = BigNumber.len;
+   if(bCarry && BigNumber.len > 1 && UsefulBufC_NTH_BYTE(BigNumber, 0) >= 1) {
+      uLen--;
+   }
+   QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uLen, 0);
+
+   SubString = BigNumber;
+   bCopiedSomething = false;
+   while(SubString.len) {
+      uByte = UsefulBufC_NTH_BYTE(SubString, 0);
+      NextSubString = UsefulBuf_Tail(SubString, 1);
+      bCarry = QCBOREncode_Private_BigNumberCarry(NextSubString);
+      if(bCarry) {
+         uByte--;
+      }
+      /* This avoids all but the last leading zero. See
+       * QCBOREncode_Private_SkipLeadingZeros() */
+      if(bCopiedSomething || NextSubString.len == 0 || uByte != 0) {
+         UsefulOutBuf_AppendByte(&(pMe->OutBuf), uByte);
+         bCopiedSomething = true;
+      }
+      SubString = NextSubString;
+   }
+}
+
+
+/**
+ * @brief Convert a negative big number to unsigned int if possible.
+ *
+ * @param[in] BigNumber  The negative big number.
+ * @param[out] puInt     The converted negative big number.
+ *
+ * @return If conversion was possible, returns @c true.
+ *
+ * The parameters here are unsigned integers, but they always
+ * represent negative numbers.
+ *
+ * Conversion is possible if the big number is greater than -(2^64).
+ * Conversion include offset of 1 for encoding CBOR negative numbers.
+ */
+static bool
+QCBOREncode_Private_NegativeBigNumberToUInt(const UsefulBufC BigNumber, uint64_t *puInt)
+{
+   bool bIs2exp64;
+
+   static const uint8_t twoExp64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+   bIs2exp64 = ! UsefulBuf_Compare(BigNumber, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(twoExp64));
+
+   if(BigNumber.len > 8 && !bIs2exp64) {
+      return false;
+   }
+
+   /* Must convert to CBOR type 1, a negative integer */
+   if(bIs2exp64) {
+      /* 2^64 is a 9 byte big number. Since negative numbers are offset
+       * by one in CBOR, it can be encoded as a type 1 negative. The
+       * conversion below won't work because the uInt will overflow
+       * before the subtraction of 1.
+       */
+      *puInt = UINT64_MAX;
+   } else {
+      *puInt = QCBOREncode_Private_BigNumberToUInt(BigNumber);
+      (*puInt)--; /* CBOR's negative offset of 1 */
+   }
+   return true;
+}
+
+
+/**
+ * @brief Remove leading zeros.
+ *
+ * @param[in] BigNumber  The negative big number.
+ *
+ * @return Big number with no leading zeros.
+ *
+ * If the big number is all zeros, this returns a big number
+ * that is one zero rather than the empty string.
+ *
+ * 3.4.3 does not explicitly decoders MUST handle the empty string,
+ * but does say decoders MUST handle leading zeros. So Postel's Law
+ * is applied here and 0 is not encoded as an empty string.
+ */
+static UsefulBufC
+QCBOREncode_Private_SkipLeadingZeros(const UsefulBufC BigNumber)
+{
+   UsefulBufC NLZ;
+   NLZ = UsefulBuf_SkipLeading(BigNumber, 0x00);
+
+   /* An all-zero string reduces to one 0, not an empty string. */
+   if(NLZ.len == 0 && BigNumber.len > 0 && UsefulBufC_NTH_BYTE(BigNumber, 0) == 0x00) {
+      NLZ.len++;
+   }
+
+   return NLZ;
+}
+
+
+/*
+ * Public functions for adding a big number. See qcbor/qcbor_encode.h
+ */
+void
+QCBOREncode_AddTBigNumber(QCBOREncodeContext *pMe,
+                          const uint8_t       uTagRequirement,
+                          const bool          bNegative,
+                          const UsefulBufC    BigNumber)
+{
+   uint64_t uInt;
+
+   const UsefulBufC BigNumberNLZ = QCBOREncode_Private_SkipLeadingZeros(BigNumber);
+
+   /* Preferred serialization requires reduction to type 0 and 1 integers */
+   if(bNegative) {
+      if(QCBOREncode_Private_NegativeBigNumberToUInt(BigNumberNLZ, &uInt)) {
+         /* Might be a 65-bit negative; use special add method for such */
+         QCBOREncode_AddNegativeUInt64(pMe, uInt);
+      } else {
+         QCBOREncode_Private_AddTNegativeBigNumber(pMe, uTagRequirement, BigNumberNLZ);
+      }
+
+   } else {
+      if(BigNumberNLZ.len <= sizeof(uint64_t)) {
+         QCBOREncode_AddUInt64(pMe, QCBOREncode_Private_BigNumberToUInt(BigNumberNLZ));
+      } else {
+         QCBOREncode_AddTBigNumberRaw(pMe, bNegative, uTagRequirement, BigNumberNLZ);
+      }
+   }
+}
+
+
+/*
+ * Public functions for adding a big number. See qcbor/qcbor_encode.h
+ */
+void
+QCBOREncode_AddTBigNumberNoPreferred(QCBOREncodeContext *pMe,
+                                     const uint8_t       uTagRequirement,
+                                     const bool          bNegative,
+                                     const UsefulBufC    BigNumber)
+{
+   const UsefulBufC BigNumberNLZ = QCBOREncode_Private_SkipLeadingZeros(BigNumber);
+
+   if(bNegative) {
+      QCBOREncode_Private_AddTNegativeBigNumber(pMe, uTagRequirement, BigNumberNLZ);
+   } else {
+      QCBOREncode_AddTBigNumberRaw(pMe, false, uTagRequirement, BigNumberNLZ);
+   }
+}
+
+
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
 /**
  * @brief  Semi-private method to add bigfloats and decimal fractions.
  *
  * @param[in] pMe               The encoding context to add the value to.
- * @param[in] uTag               The type 6 tag indicating what this is to be.
- * @param[in] BigNumMantissa     Is @ref NULLUsefulBufC if mantissa is an
- *                               @c int64_t or the actual big number mantissa
- *                               if not.
- * @param[in] bBigNumIsNegative  This is @c true if the big number is negative.
+ * @param[in] uTagNumber               The type 6 tag indicating what this is to be.
  * @param[in] nMantissa          The @c int64_t mantissa if it is not a big number.
  * @param[in] nExponent          The exponent.
  *
@@ -698,12 +1037,11 @@
  * is called instead of this.
  */
 void
-QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe,
-                                   const uint64_t      uTag,
-                                   const UsefulBufC    BigNumMantissa,
-                                   const bool          bBigNumIsNegative,
-                                   const int64_t       nMantissa,
-                                   const int64_t       nExponent)
+QCBOREncode_Private_AddTExpIntMantissa(QCBOREncodeContext *pMe,
+                                       const int           uTagRequirement,
+                                       const uint64_t      uTagNumber,
+                                       const int64_t       nExponent,
+                                       const int64_t       nMantissa)
 {
    /* This is for encoding either a big float or a decimal fraction,
     * both of which are an array of two items, an exponent and a
@@ -711,22 +1049,72 @@
     * is base-2 for big floats and base-10 for decimal fractions, but
     * that has no effect on the code here.
     */
-   if(uTag != CBOR_TAG_INVALID64) {
-      QCBOREncode_AddTag(pMe, uTag);
+   /* Separate from QCBOREncode_Private_AddTExpBigMantissa() because
+    * linking QCBOREncode_AddTBigNumber() adds a lot because it
+    * does preferred serialization of big numbers and the offset of 1
+    * for CBOR negative numbers.
+    */
+   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+      QCBOREncode_AddTagNumber(pMe, uTagNumber);
    }
    QCBOREncode_OpenArray(pMe);
    QCBOREncode_AddInt64(pMe, nExponent);
-   if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
-      if(bBigNumIsNegative) {
-         QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa);
-      } else {
-         QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa);
-      }
-   } else {
-      QCBOREncode_AddInt64(pMe, nMantissa);
-   }
+   QCBOREncode_AddInt64(pMe, nMantissa);
    QCBOREncode_CloseArray(pMe);
 }
+
+void
+QCBOREncode_Private_AddTExpBigMantissa(QCBOREncodeContext *pMe,
+                                       const int           uTagRequirement,
+                                       const uint64_t      uTagNumber,
+                                       const int64_t       nExponent,
+                                       const UsefulBufC    BigNumMantissa,
+                                       const bool          bBigNumIsNegative)
+{
+   /* This is for encoding either a big float or a decimal fraction,
+    * both of which are an array of two items, an exponent and a
+    * mantissa.  The difference between the two is that the exponent
+    * is base-2 for big floats and base-10 for decimal fractions, but
+    * that has no effect on the code here.
+    */
+   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+      QCBOREncode_AddTag(pMe, uTagNumber);
+   }
+   QCBOREncode_OpenArray(pMe);
+   QCBOREncode_AddInt64(pMe, nExponent);
+   QCBOREncode_AddTBigNumber(pMe, QCBOR_ENCODE_AS_TAG, bBigNumIsNegative, BigNumMantissa);
+   QCBOREncode_CloseArray(pMe);
+}
+
+
+void
+QCBOREncode_Private_AddTExpBigMantissaRaw(QCBOREncodeContext *pMe,
+                                          const int           uTagRequirement,
+                                          const uint64_t      uTagNumber,
+                                          const int64_t       nExponent,
+                                          const UsefulBufC    BigNumMantissa,
+                                          const bool          bBigNumIsNegative)
+{
+   /* This is for encoding either a big float or a decimal fraction,
+    * both of which are an array of two items, an exponent and a
+    * mantissa.  The difference between the two is that the exponent
+    * is base-2 for big floats and base-10 for decimal fractions, but
+    * that has no effect on the code here.
+    */
+   /* Separate from QCBOREncode_Private_AddTExpBigMantissa() because
+    * linking QCBOREncode_AddTBigNumber() adds a lot because it
+    * does preferred serialization of big numbers and the offset of 1
+    * for CBOR negative numbers.
+    */
+   if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+      QCBOREncode_AddTag(pMe, uTagNumber);
+   }
+   QCBOREncode_OpenArray(pMe);
+   QCBOREncode_AddInt64(pMe, nExponent);
+   QCBOREncode_AddTBigNumberRaw(pMe, QCBOR_ENCODE_AS_TAG, bBigNumIsNegative, BigNumMantissa);
+   QCBOREncode_CloseArray(pMe);
+}
+
 #endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
 
 
@@ -788,6 +1176,12 @@
 QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
                                                    const uint8_t       uMajorType)
 {
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
+      pMe->uError = QCBOR_ERR_NOT_PREFERRED;
+      return;
+   }
+#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
    /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */
    QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0);
 
@@ -895,12 +1289,10 @@
 
 
 /**
- * @brief Semi-private method to close a map, array or bstr wrapped CBOR
+ * @brief Semi-private method to close a map, array or bstr wrapped CBOR.
  *
  * @param[in] pMe           The context to add to.
  * @param[in] uMajorType     The major CBOR type to close.
- *
- * Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
  */
 void
 QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
@@ -910,6 +1302,341 @@
 }
 
 
+/**
+ * @brief Private method to close a map without sorting.
+ *
+ * @param[in] pMe     The encode context with map to close.
+ *
+ * See QCBOREncode_SerializationCDE() implemention for explantion for why
+ * this exists in this form.
+ */
+static void
+QCBOREncode_Private_CloseMapUnsorted(QCBOREncodeContext *pMe)
+{
+   QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP);
+}
+
+
+/**
+ * @brief Decode a CBOR item head.
+ *
+ * @param[in]   pUInBuf           UsefulInputBuf to read from.
+ * @param[out]  pnMajorType       Major type of decoded head.
+ * @param[out]  puArgument        Argument of decoded head.
+ * @param[out]  pnAdditionalInfo  Additional info from decoded head.
+ *
+ * @return SUCCESS if a head was decoded
+ *         HIT_END if there were not enough bytes to decode a head
+ *         UNSUPPORTED if the decoded item is not one that is supported
+ *
+ * This is copied from qcbor_decode.c rather than referenced.  This
+ * makes the core decoder 60 bytes smaller because it gets inlined.
+ * It would not get inlined if it was referenced. It is important to
+ * make the core decoder as small as possible. The copy here does make
+ * map sorting 200 bytes bigger, but map sorting is rarely used in
+ * environments that need small object code. It would also make
+ * qcbor_encode.c depend on qcbor_decode.c
+ *
+ * This is also super stable and tested. It implements the very
+ * well-defined part of CBOR that will never change.  So this won't
+ * change.
+ */
+static QCBORError
+QCBOREncodePriv_DecodeHead(UsefulInputBuf *pUInBuf,
+                           int            *pnMajorType,
+                           uint64_t       *puArgument,
+                           int            *pnAdditionalInfo)
+{
+   QCBORError uReturn;
+
+   /* Get the initial byte that every CBOR data item has and break it
+    * down. */
+   const int nInitialByte    = (int)UsefulInputBuf_GetByte(pUInBuf);
+   const int nTmpMajorType   = nInitialByte >> 5;
+   const int nAdditionalInfo = nInitialByte & 0x1f;
+
+   /* Where the argument accumulates */
+   uint64_t uArgument;
+
+   if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= 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[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
+         /* This shift and add gives the endian conversion. */
+         uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
+      }
+   } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
+      /* The reserved and thus-far unused additional info values */
+      uReturn = QCBOR_ERR_UNSUPPORTED;
+      goto Done;
+   } else {
+      /* Less than 24, additional info is argument or 31, an
+       * indefinite-length.  No more bytes to get.
+       */
+      uArgument = (uint64_t)nAdditionalInfo;
+   }
+
+   if(UsefulInputBuf_GetError(pUInBuf)) {
+      uReturn = QCBOR_ERR_HIT_END;
+      goto Done;
+   }
+
+   /* All successful if arrived here. */
+   uReturn           = QCBOR_SUCCESS;
+   *pnMajorType      = nTmpMajorType;
+   *puArgument       = uArgument;
+   *pnAdditionalInfo = nAdditionalInfo;
+
+Done:
+   return uReturn;
+}
+
+
+/**
+ * @brief Consume the next item from a UsefulInputBuf.
+ *
+ * @param[in] pInBuf  UsefulInputBuf from which to consume item.
+ *
+ * Recursive, but stack usage is light and encoding depth limit
+ */
+static QCBORError
+QCBOR_Private_ConsumeNext(UsefulInputBuf *pInBuf)
+{
+   int      nMajor;
+   uint64_t uArgument;
+   int      nAdditional;
+   uint16_t uItemCount;
+   uint16_t uMul;
+   uint16_t i;
+   QCBORError uCBORError;
+
+   uCBORError = QCBOREncodePriv_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
+   if(uCBORError != QCBOR_SUCCESS) {
+      return uCBORError;
+   }
+
+   uMul = 1;
+
+   switch(nMajor) {
+      case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
+      case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
+         break;
+
+      case CBOR_MAJOR_TYPE_SIMPLE:
+         return uArgument == CBOR_SIMPLE_BREAK ? 1 : 0;
+         break;
+
+      case CBOR_MAJOR_TYPE_BYTE_STRING:
+      case CBOR_MAJOR_TYPE_TEXT_STRING:
+         if(nAdditional == LEN_IS_INDEFINITE) {
+            /* Segments of indefinite length */
+            while(QCBOR_Private_ConsumeNext(pInBuf) == 0);
+         }
+         (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
+         break;
+
+      case CBOR_MAJOR_TYPE_TAG:
+         QCBOR_Private_ConsumeNext(pInBuf);
+         break;
+
+      case CBOR_MAJOR_TYPE_MAP:
+         uMul = 2;
+         /* Fallthrough */
+      case CBOR_MAJOR_TYPE_ARRAY:
+         uItemCount = (uint16_t)uArgument * uMul;
+         if(nAdditional == LEN_IS_INDEFINITE) {
+            uItemCount = UINT16_MAX;
+         }
+         for(i = uItemCount; i > 0; i--) {
+            if(QCBOR_Private_ConsumeNext(pInBuf)) {
+               /* End of indefinite length */
+               break;
+            }
+         }
+         break;
+   }
+
+   return QCBOR_SUCCESS;
+}
+
+
+/**
+ * @brief  Decoded next item to get its lengths.
+ *
+ * Decode the next item in map no matter what type it is. It works
+ * recursively when an item is a map or array It returns offset just
+ * past the item decoded or zero there are no more items in the output
+ * buffer.
+ *
+ * This doesn't distinguish between end of the input and an error
+ * because it is used to decode stuff we encoded into a buffer, not
+ * stuff that came in from outside. We still want a check for safety
+ * in case of bugs here, but it is OK to report end of input on error.
+ */
+struct ItemLens {
+   uint32_t  uLabelLen;
+   uint32_t  uItemLen;
+};
+
+static struct ItemLens
+QCBOREncode_Private_DecodeNextInMap(QCBOREncodeContext *pMe, uint32_t uStart)
+{
+   UsefulInputBuf  InBuf;
+   UsefulBufC      EncodedMapBytes;
+   QCBORError      uCBORError;
+   struct ItemLens Result;
+
+   Result.uLabelLen = 0;
+   Result.uItemLen  = 0;
+
+   EncodedMapBytes = UsefulOutBuf_OutUBufOffset(&(pMe->OutBuf), uStart);
+   if(UsefulBuf_IsNULLC(EncodedMapBytes)) {
+      return Result;
+   }
+
+   UsefulInputBuf_Init(&InBuf, EncodedMapBytes);
+
+   /* This is always used on maps, so consume two, the label and the value */
+   uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
+   if(uCBORError) {
+      return Result;
+   }
+
+   /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
+   Result.uLabelLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
+
+   uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
+   if(uCBORError) {
+      Result.uLabelLen = 0;
+      return Result;
+   }
+
+   Result.uItemLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
+
+   /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
+   return Result;
+}
+
+
+/**
+ * @brief Sort items lexographically by encoded labels.
+ *
+ * @param[in] pMe     Encoding context.
+ * @param[in] uStart  Offset in outbuf of first item for sorting.
+ *
+ * This reaches into the UsefulOutBuf in the encoding context and
+ * sorts encoded CBOR items. The byte offset start of the items is at
+ * @c uStart and it goes to the end of valid bytes in the
+ * UsefulOutBuf.
+ */
+static void
+QCBOREncode_Private_SortMap(QCBOREncodeContext *pMe, uint32_t uStart)
+{
+   bool            bSwapped;
+   int             nComparison;
+   uint32_t        uStart1;
+   uint32_t        uStart2;
+   struct ItemLens Lens1;
+   struct ItemLens Lens2;
+
+
+   if(pMe->uError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   /* Bubble sort because the sizes of all the items are not the
+    * same. It works with adjacent pairs so the swap is not too
+    * difficult even though sizes are different.
+    *
+    * While bubble sort is n-squared, it seems OK here because n will
+    * usually be small and the comparison and swap functions aren't
+    * too CPU intensive.
+    *
+    * Another approach would be to have an array of offsets to the
+    * items. However this requires memory allocation and the swap
+    * operation for quick sort or such is complicated because the item
+    * sizes are not the same and overlap may occur in the bytes being
+    * swapped.
+    */
+   do { /* Loop until nothing was swapped */
+      Lens1 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart);
+      if(Lens1.uLabelLen == 0) {
+         /* It's an empty map. Nothing to do. */
+         break;
+      }
+      uStart1 = uStart;
+      uStart2 = uStart1 + Lens1.uItemLen;
+      bSwapped = false;
+
+      while(1) {
+         Lens2 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart2);
+         if(Lens2.uLabelLen == 0) {
+            break;
+         }
+
+         nComparison = UsefulOutBuf_Compare(&(pMe->OutBuf),
+                                            uStart1, Lens1.uLabelLen,
+                                            uStart2, Lens2.uLabelLen);
+         if(nComparison < 0) {
+            UsefulOutBuf_Swap(&(pMe->OutBuf), uStart1, uStart2, uStart2 + Lens2.uItemLen);
+            uStart1 = uStart1 + Lens2.uItemLen; /* item 2 now in position of item 1 */
+            /* Lens1 is still valid as Lens1 for the next loop */
+            bSwapped = true;
+         } else if(nComparison > 0) {
+            uStart1 = uStart2;
+            Lens1   = Lens2;
+         } else /* nComparison == 0 */ {
+            pMe->uError = QCBOR_ERR_DUPLICATE_LABEL;
+            return;
+         }
+         uStart2 = uStart2 + Lens2.uItemLen;
+      }
+   } while(bSwapped);
+}
+
+
+/*
+ * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
+ */
+void
+QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pMe)
+{
+   uint32_t uStart;
+
+   /* The Header for the map we are about to sort hasn't been
+    * inserted yet, so uStart is the position of the first item
+    * and the end out the UsefulOutBuf data is the end of the
+    * items we are about to sort.
+    */
+   uStart = Nesting_GetStartPos(&(pMe->nesting));
+   QCBOREncode_Private_SortMap(pMe, uStart);
+
+   QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
+}
+
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+/*
+ * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
+ */
+void
+QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pMe)
+{
+   uint32_t uStart;
+
+   uStart = Nesting_GetStartPos(&(pMe->nesting));
+   QCBOREncode_Private_SortMap(pMe, uStart);
+
+   QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+
 /*
  * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h
  */
diff --git a/src/qcbor_tag_decode.c b/src/qcbor_tag_decode.c
new file mode 100644
index 0000000..36e8dae
--- /dev/null
+++ b/src/qcbor_tag_decode.c
@@ -0,0 +1,424 @@
+/* ==========================================================================
+ * qcbor_tag_decode.c -- Tag content decoders
+ *
+ * Copyright (c) 2024, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ *
+ * Created on 9/5/24
+ * ========================================================================== */
+
+#include "qcbor/qcbor_tag_decode.h"
+
+#include <math.h> /* For isnan() */
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_DateEpochTagCB(QCBORDecodeContext *pDecodeCtx,
+                           void               *pTagDecodersContext,
+                           uint64_t            uTagNumber,
+                           QCBORItem          *pDecodedItem)
+{
+   (void)pDecodeCtx;
+   (void)pTagDecodersContext;
+   (void)uTagNumber;
+
+   QCBORError uReturn = QCBOR_SUCCESS;
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+   pDecodedItem->val.epochDate.fSecondsFraction = 0;
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
+
+   switch (pDecodedItem->uDataType) {
+
+      case QCBOR_TYPE_INT64:
+         pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
+         break;
+
+      case QCBOR_TYPE_UINT64:
+         /* This only happens for CBOR type 0 > INT64_MAX so it is
+          * always an overflow.
+          */
+         uReturn = QCBOR_ERR_DATE_OVERFLOW;
+         goto Done;
+         break;
+
+      case QCBOR_TYPE_DOUBLE:
+      case QCBOR_TYPE_FLOAT:
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+      {
+         /* Convert working value to double if input was a float */
+         const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
+                   pDecodedItem->val.dfnum :
+                   (double)pDecodedItem->val.fnum;
+
+         /* The conversion from float to integer requires overflow
+          * detection since floats can be much larger than integers.
+          * This implementation errors out on these large float values
+          * since they are beyond the age of the earth.
+          *
+          * These constants for the overflow check are computed by the
+          * compiler. They are not computed at run time.
+          *
+          * The factor of 0x7ff is added/subtracted to avoid a
+          * rounding error in the wrong direction when the compiler
+          * computes these constants. There is rounding because a
+          * 64-bit integer has 63 bits of precision where a double
+          * only has 53 bits. Without the 0x7ff factor, the compiler
+          * may round up and produce a double for the bounds check
+          * that is larger than can be stored in a 64-bit integer. The
+          * amount of 0x7ff is picked because it has 11 bits set.
+          *
+          * Without the 0x7ff there is a ~30 minute range of time
+          * values 10 billion years in the past and in the future
+          * where this code could go wrong. Some compilers
+          * generate a warning or error without the 0x7ff. */
+         const double dDateMax = (double)(INT64_MAX - 0x7ff);
+         const double dDateMin = (double)(INT64_MIN + 0x7ff);
+
+         if(isnan(d) || d > dDateMax || d < dDateMin) {
+            uReturn = QCBOR_ERR_DATE_OVERFLOW;
+            goto Done;
+         }
+
+         /* The actual conversion */
+         pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
+         pDecodedItem->val.epochDate.fSecondsFraction =
+                           d - (double)pDecodedItem->val.epochDate.nSeconds;
+      }
+#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
+
+         uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
+         goto Done;
+
+#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
+         break;
+
+      default:
+         /* It's the arrays and maps that are unrecoverable because
+          * they are not consumed here. Since this is just an error
+          * condition, no extra code is added here to make the error
+          * recoverable for non-arrays and maps like strings. */
+         uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
+         goto Done;
+   }
+
+   pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
+
+Done:
+   return uReturn;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_DaysEpochTagCB(QCBORDecodeContext *pDecodeCtx,
+                           void               *pTagDecodersContext,
+                           uint64_t            uTagNumber,
+                           QCBORItem          *pDecodedItem)
+{
+   (void)pDecodeCtx;
+   (void)pTagDecodersContext;
+   (void)uTagNumber;
+
+   QCBORError uReturn;
+
+   switch (pDecodedItem->uDataType) {
+
+      case QCBOR_TYPE_INT64:
+         pDecodedItem->val.epochDays = pDecodedItem->val.int64;
+         pDecodedItem->uDataType     = QCBOR_TYPE_DAYS_EPOCH;
+         uReturn                     = QCBOR_SUCCESS;
+         break;
+
+      case QCBOR_TYPE_UINT64:
+         /* This only happens for CBOR type 0 > INT64_MAX so it is
+          * always an overflow. */
+         pDecodedItem->uDataType = QCBOR_TYPE_NONE;
+         uReturn                 = QCBOR_ERR_DATE_OVERFLOW;
+         break;
+
+      default:
+         /* It's the arrays and maps that are unrecoverable because
+          * they are not consumed here. Since this is just an error
+          * condition, no extra code is added here to make the error
+          * recoverable for non-arrays and maps like strings. */
+         pDecodedItem->uDataType = QCBOR_TYPE_NONE;
+         uReturn                 = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
+         break;
+   }
+
+   return uReturn;
+}
+
+
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
+
+/**
+ * @brief Figures out QCBOR data type for exponent and mantissa tags.
+ *
+ * @param[in] uTagToProcess  Either @ref CBOR_TAG_DECIMAL_FRACTION or
+ *                           @ref CBOR_TAG_BIG_FLOAT.
+ * @param[in] pDecodedItem   Item being decoded.
+ *
+ * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION and @ref QCBOR_TYPE_BIGFLOAT
+ *
+ * Does mapping between a CBOR tag number and a QCBOR type with a
+ * little logic and arithmetic.
+ */
+static uint8_t
+QCBOR_Private_ExpMantissaDataType(const uint64_t   uTagToProcess,
+                                  const QCBORItem *pDecodedItem)
+{
+   uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
+                                       QCBOR_TYPE_DECIMAL_FRACTION :
+                                       QCBOR_TYPE_BIGFLOAT;
+
+   switch(pDecodedItem->uDataType) {
+      case QCBOR_TYPE_INT64:
+         return uBase;
+
+      case QCBOR_TYPE_UINT64:
+         return uBase + (QCBOR_TYPE_DECIMAL_FRACTION_POS_U64 - QCBOR_TYPE_DECIMAL_FRACTION); // TODO: test this
+
+      case QCBOR_TYPE_65BIT_NEG_INT:
+         return uBase + (QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64 - QCBOR_TYPE_DECIMAL_FRACTION);
+
+      default:
+         return (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
+   }
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_ExpMantissaTagCB(QCBORDecodeContext *pDecodeCtx,
+                             void               *pTagDecodersContext,
+                             uint64_t            uTagNumber,
+                             QCBORItem          *pDecodedItem)
+{
+   (void)pTagDecodersContext;
+
+   QCBORError uReturn;
+   QCBORItem  ExponentItem;
+   QCBORItem  MantissaItem;
+
+   /* --- Make sure it is an array; track nesting level of members --- */
+   if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
+      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+      goto Done;
+   }
+
+   /* A check for pDecodedItem->val.uCount == 2 would work for
+    * definite-length arrays, but not for indefinite. Instead remember
+    * the nesting level the two integers must be at, which is one
+    * deeper than that of the array. */
+   const uint8_t uNestLevel = pDecodedItem->uNestingLevel + 1;
+
+   /* --- Get the exponent --- */
+   uReturn = QCBORDecode_GetNext(pDecodeCtx, &ExponentItem);
+   if(uReturn != QCBOR_SUCCESS) {
+      goto Done;
+   }
+   if(ExponentItem.uNestingLevel != uNestLevel) {
+      /* Array is empty or a map/array encountered when expecting an int */
+      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+      goto Done;
+   }
+   if(ExponentItem.uDataType == QCBOR_TYPE_INT64) {
+     /* Data arriving as an unsigned int < INT64_MAX has been
+      * converted to QCBOR_TYPE_INT64 and thus handled here. This is
+      * also means that the only data arriving here of type
+      * QCBOR_TYPE_UINT64 data will be too large for this to handle
+      * and thus an error that will get handled in the next else.*/
+     pDecodedItem->val.expAndMantissa.nExponent = ExponentItem.val.int64;
+   } else {
+      /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
+      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+      goto Done;
+   }
+
+   /* --- Get the mantissa --- */
+   uReturn = QCBORDecode_GetNext(pDecodeCtx, &MantissaItem);
+   if(uReturn != QCBOR_SUCCESS) {
+      goto Done;
+   }
+   if(MantissaItem.uNestingLevel != uNestLevel) {
+      /* Mantissa missing or map/array encountered when expecting number */
+      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+      goto Done;
+   }
+   /* Stuff the mantissa data type into the item to send it up to the
+    * the next level. */
+   if(MantissaItem.uDataType == QCBOR_TYPE_INT64) {
+      /* Data arriving as an unsigned int < INT64_MAX has been
+       * converted to QCBOR_TYPE_INT64 and thus handled here. This is
+       * also means that the only data arriving here of type
+       * QCBOR_TYPE_UINT64 data will be too large for this to handle
+       * and thus an error that will get handled in an else below. */
+      pDecodedItem->val.expAndMantissa.Mantissa.nInt = MantissaItem.val.int64;
+#ifndef QCBOR_DISABLE_TAGS
+      /* With tags fully disabled a big number mantissa will error out
+       * in the call to QCBORDecode_GetNextWithTags() because it has
+       * a tag number. */
+   }  else if(MantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
+              MantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
+      /* Got a good big num mantissa */
+      pDecodedItem->val.expAndMantissa.Mantissa.bigNum = MantissaItem.val.bigNum;
+#endif /* QCBOR_DISABLE_TAGS */
+   } else if(MantissaItem.uDataType == QCBOR_TYPE_UINT64) {
+      pDecodedItem->val.expAndMantissa.Mantissa.uInt = MantissaItem.val.uint64;
+   } else if(MantissaItem.uDataType == QCBOR_TYPE_65BIT_NEG_INT) {
+      pDecodedItem->val.expAndMantissa.Mantissa.uInt = MantissaItem.val.uint64;
+   } else {
+      /* Wrong type of mantissa */
+      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+      goto Done;
+   }
+
+   /* --- Check that array only has the two numbers --- */
+   if(MantissaItem.uNextNestLevel == uNestLevel) {
+      /* Extra items in the decimal fraction / big float */
+      /* Improvement: this should probably be an unrecoverable error. */
+      uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+      goto Done;
+   }
+
+   pDecodedItem->uNextNestLevel = MantissaItem.uNextNestLevel;
+   pDecodedItem->uDataType      = QCBOR_Private_ExpMantissaDataType(uTagNumber, &MantissaItem);
+
+Done:
+  return uReturn;
+}
+#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_MIMETagCB(QCBORDecodeContext *pDecodeCtx,
+                      void               *pTagDecodersContext,
+                      uint64_t            uTagNumber,
+                      QCBORItem          *pDecodedItem)
+{
+   (void)pDecodeCtx;
+   (void)pTagDecodersContext;
+   (void)uTagNumber;
+
+   if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
+      pDecodedItem->uDataType = QCBOR_TYPE_MIME;
+   } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
+      pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
+   } else {
+      /* It's the arrays and maps that are unrecoverable because
+       * they are not consumed here. Since this is just an error
+       * condition, no extra code is added here to make the error
+       * recoverable for non-arrays and maps like strings. */
+      return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
+   }
+
+   return QCBOR_SUCCESS;
+}
+
+
+/* Table of CBOR tags whose content is either a text string or a byte
+ * string. The table maps the CBOR tag to the QCBOR type. The high-bit
+ * of uQCBORtype indicates the content should be a byte string rather
+ * than a text string. */
+struct StringTagMapEntry {
+   uint16_t uTagNumber;
+   uint8_t  uQCBORtype;
+};
+
+#define IS_BYTE_STRING_BIT 0x80
+#define QCBOR_TYPE_MASK   ~IS_BYTE_STRING_BIT
+
+static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
+   {CBOR_TAG_DATE_STRING,   QCBOR_TYPE_DATE_STRING},
+   {CBOR_TAG_DAYS_STRING,   QCBOR_TYPE_DAYS_STRING},
+   {CBOR_TAG_POS_BIGNUM,    QCBOR_TYPE_POSBIGNUM    | IS_BYTE_STRING_BIT},
+   {CBOR_TAG_NEG_BIGNUM,    QCBOR_TYPE_NEGBIGNUM    | IS_BYTE_STRING_BIT},
+   {CBOR_TAG_CBOR,          QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
+   {CBOR_TAG_URI,           QCBOR_TYPE_URI},
+   {CBOR_TAG_B64URL,        QCBOR_TYPE_BASE64URL},
+   {CBOR_TAG_B64,           QCBOR_TYPE_BASE64},
+   {CBOR_TAG_REGEX,         QCBOR_TYPE_REGEX},
+   {CBOR_TAG_BIN_UUID,      QCBOR_TYPE_UUID                  | IS_BYTE_STRING_BIT},
+   {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT}, // TODO: does this belong here?
+   {CBOR_TAG_INVALID16,     QCBOR_TYPE_NONE}
+};
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_StringsTagCB(QCBORDecodeContext *pDecodeCtx,
+                         void               *pTagDecodersContext,
+                         uint64_t            uTagNumber,
+                         QCBORItem          *pDecodedItem)
+{
+   (void)pDecodeCtx;
+   (void)pTagDecodersContext;
+
+   int uIndex;
+   for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
+      if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTagNumber) {
+         break;
+      }
+   }
+
+   const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
+   if(uQCBORType == QCBOR_TYPE_NONE) {
+      /* repurpose this error to mean not handled here */
+      return QCBOR_ERR_UNSUPPORTED;
+   }
+
+   uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
+   if(uQCBORType & IS_BYTE_STRING_BIT) {
+      uExpectedType = QCBOR_TYPE_BYTE_STRING;
+   }
+
+   if(pDecodedItem->uDataType != uExpectedType) {
+      /* It's the arrays and maps that are unrecoverable because
+       * they are not consumed here. Since this is just an error
+       * condition, no extra code is added here to make the error
+       * recoverable for non-arrays and maps like strings. */
+      return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
+   }
+
+   pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
+   return QCBOR_SUCCESS;
+}
+
+
+
+
+#ifndef QCBOR_DISABLE_TAGS
+
+/* Public data structure; see qcbor_tag_decode.h */
+const struct QCBORTagDecoderEntry QCBORDecode_TagDecoderTablev1[] = {
+   {CBOR_TAG_DATE_STRING,      QCBORDecode_StringsTagCB},
+   {CBOR_TAG_DATE_EPOCH,       QCBORDecode_DateEpochTagCB},
+   {CBOR_TAG_DAYS_STRING,      QCBORDecode_StringsTagCB},
+   {CBOR_TAG_POS_BIGNUM,       QCBORDecode_StringsTagCB},
+   {CBOR_TAG_NEG_BIGNUM,       QCBORDecode_StringsTagCB},
+   {CBOR_TAG_CBOR,             QCBORDecode_StringsTagCB},
+   {CBOR_TAG_URI,              QCBORDecode_StringsTagCB},
+   {CBOR_TAG_B64URL,           QCBORDecode_StringsTagCB},
+   {CBOR_TAG_B64,              QCBORDecode_StringsTagCB},
+   {CBOR_TAG_REGEX,            QCBORDecode_StringsTagCB},
+   {CBOR_TAG_BIN_UUID,         QCBORDecode_StringsTagCB},
+   {CBOR_TAG_CBOR_SEQUENCE,    QCBORDecode_StringsTagCB}, // TODO: does this belong here?
+   {CBOR_TAG_MIME,             QCBORDecode_MIMETagCB},
+   {CBOR_TAG_BINARY_MIME,      QCBORDecode_MIMETagCB},
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
+
+   {CBOR_TAG_BIGFLOAT,         QCBORDecode_ExpMantissaTagCB},
+   {CBOR_TAG_DECIMAL_FRACTION, QCBORDecode_ExpMantissaTagCB},
+#endif
+   {CBOR_TAG_DAYS_EPOCH,       QCBORDecode_DaysEpochTagCB},
+   {CBOR_TAG_INVALID64,        NULL},
+};
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
diff --git a/tag-examples.c b/tag-examples.c
new file mode 100644
index 0000000..99c6fd9
--- /dev/null
+++ b/tag-examples.c
@@ -0,0 +1,209 @@
+/* ==========================================================================
+ * tag-examples.c -- Tag decoding examples
+ *
+ * Copyright (c) 2024, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ *
+ * Created on 10/7/24
+ * ========================================================================== */
+
+
+#include "tag-examples.h"
+#include "qcbor/qcbor_tag_decode.h"
+#include <stdio.h>
+
+// The CBOR to decode
+static const uint8_t spAddrs[] = {
+    0xD8, 0x34, 0x44, 0xC0, 0x00, 0x02, 0x01
+
+};
+
+#define CBOR_TAG_IPV4 52
+#define CBOR_TAG_IPV6 54
+
+
+
+#ifndef QCBOR_DISABLE_TAGS
+
+
+#define USER_TYPE_IPV4_ADDR 130
+#define USER_TYPE_IPV6_ADDR 131
+
+static QCBORError
+IPAddrDecodeCallBack(QCBORDecodeContext *pDecodeCtx,
+                     void               *pTagDecodersContext,
+                     uint64_t            uTagNumber,
+                     QCBORItem          *pDecodedItem)
+{
+    (void)pTagDecodersContext;
+    (void)pDecodeCtx;
+
+    if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return QCBOR_ERR_UNEXPECTED_TYPE;
+    }
+
+    switch(uTagNumber) {
+        case CBOR_TAG_IPV4:
+            if(pDecodedItem->val.string.len != 4) {
+                return QCBOR_ERR_BAD_TAG_CONTENT;
+            }
+            pDecodedItem->uDataType = USER_TYPE_IPV4_ADDR;
+            break;
+
+        case CBOR_TAG_IPV6:
+            if(pDecodedItem->val.string.len != 6) {
+                return QCBOR_ERR_BAD_TAG_CONTENT;
+            }
+            pDecodedItem->uDataType = USER_TYPE_IPV6_ADDR;
+            break;
+
+        default:
+            return QCBOR_ERR_UNEXPECTED_TAG_NUMBER;
+    }
+
+    return QCBOR_SUCCESS;
+}
+
+const struct QCBORTagDecoderEntry Example_TagDecoderTable[] = {
+    {CBOR_TAG_IPV4, IPAddrDecodeCallBack},
+    {CBOR_TAG_IPV6, IPAddrDecodeCallBack},
+    {CBOR_TAG_INVALID64, NULL}
+};
+
+
+
+
+void 
+Example_DecodeIPAddrWithCallBack(void)
+{
+    QCBORDecodeContext DCtx;
+    QCBORItem          Item;
+
+    QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spAddrs), 0);
+    QCBORDecode_InstallTagDecoders(&DCtx, Example_TagDecoderTable, NULL);
+    QCBORDecode_VGetNext(&DCtx, &Item);
+    QCBORDecode_Finish(&DCtx);
+
+    if(QCBORDecode_GetError(&DCtx)) {
+        printf("Fail\n");
+    } else {
+        printf("%d\n", Item.uDataType);
+    }
+}
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+
+/* If bMustBeTag is true, the input to decode must start with
+ * a tag number indicating an IP address. The type of IP address
+ * is returned in puIPVersion.
+ *
+ * if bMustBeTag is false, the input must not have a tag
+ * number. It is just the tag content that is defined for
+ * for IP Addresses. puIPVersion because an input parameter
+ * and indicates the type of IP address.
+ */
+void
+GetIPAddr(QCBORDecodeContext *pDecodeCtx,
+          bool                bMustBeTag,
+          uint8_t            *puIPVersion,
+          UsefulBufC         *pAddr)
+{
+    QCBORItem  Item;
+    size_t     nExpectedLen;
+    QCBORError uErr;
+
+#ifndef QCBOR_DISABLE_TAGS
+    if(bMustBeTag) {
+        uint64_t   uTagNumber;
+
+        QCBORDecode_GetNextTagNumber(pDecodeCtx, &uTagNumber);
+        switch(uTagNumber) {
+            case CBOR_TAG_IPV4:
+                *puIPVersion = 4;
+                break;
+
+            case CBOR_TAG_IPV6:
+                *puIPVersion = 6;
+                break;
+
+            case CBOR_TAG_INVALID64:
+                if(bMustBeTag) {
+                    uErr = QCBOR_ERR_BAD_TAG_CONTENT;
+                }
+
+            default:
+                uErr = QCBOR_ERR_UNEXPECTED_TYPE;
+                goto Done;
+        }
+    }
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+    if(*puIPVersion == 4) {
+        nExpectedLen = 4;
+    } else if(*puIPVersion == 6) {
+        nExpectedLen = 16;
+    } else  {
+        uErr = 150; // TODO:
+        goto Done;
+    }
+
+    QCBORDecode_VGetNext(pDecodeCtx, &Item);
+    if(QCBORDecode_GetError(pDecodeCtx)) {
+        return;
+    }
+
+    if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        uErr = QCBOR_ERR_BAD_TAG_CONTENT;
+        goto Done;
+    }
+
+    if(Item.val.string.len != nExpectedLen) {
+        uErr = QCBOR_ERR_BAD_TAG_CONTENT;
+        goto Done;
+    }
+
+    uErr = QCBOR_SUCCESS;
+    *pAddr = Item.val.string;
+
+Done:
+    QCBORDecode_SetError(pDecodeCtx, uErr);
+}
+
+
+void 
+Example_DecodeIPAddrWithGet(void)
+{
+    QCBORDecodeContext DCtx;
+    uint8_t            uType;
+    UsefulBufC         Addr;
+
+    QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spAddrs), 0);
+    GetIPAddr(&DCtx, true, &uType, &Addr);
+    QCBORDecode_Finish(&DCtx);
+
+    if(QCBORDecode_GetError(&DCtx)) {
+        printf("Fail\n");
+    } else {
+        printf("%d\n", uType);
+    }
+}
+
+
+
+
+int32_t
+RunTagExamples(void)
+{
+#ifndef QCBOR_DISABLE_TAGS
+    Example_DecodeIPAddrWithCallBack();
+#endif /* ! QCBOR_DISABLE_TAGS */
+    Example_DecodeIPAddrWithGet();
+
+    return 0;
+}
diff --git a/tag-examples.h b/tag-examples.h
new file mode 100644
index 0000000..2ba302b
--- /dev/null
+++ b/tag-examples.h
@@ -0,0 +1,19 @@
+/* ==========================================================================
+ * tag-examples.h -- Tag decoding examples
+ *
+ * Copyright (c) 2024, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ *
+ * Created on 10/7/24
+ * ========================================================================== */
+#ifndef tag_examples_h
+#define tag_examples_h
+
+#include <stdint.h>
+
+int32_t RunTagExamples(void);
+
+#endif /* tag_examples_h */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ab53f70..7f5f82e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,5 +1,6 @@
 #-------------------------------------------------------------------------------
 # Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+# Copyright (c) 2024, Laurence Lundblade. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -55,6 +56,7 @@
         PRIVATE
             ../cmd_line_main.c
             ../example.c
+            ../tag-examples.c
             ../ub-example.c
     )
 
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index 83e9a68..ae3862c 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -704,6 +704,31 @@
       return "Failed to find 4";
    }
 
+   UsefulBufC Substring;
+   Substring = UsefulBuf_SkipLeading(UsefulBuf_FromSZ("xxyyzz"), 'x');
+   if(UsefulBuf_Compare(Substring, UsefulBuf_FromSZ("yyzz"))) {
+      return "SkipLeading didn't skip";
+   }
+
+   Substring = UsefulBuf_SkipLeading(UsefulBuf_FromSZ("xxyyzz"), 'y');
+   if(UsefulBuf_Compare(Substring, UsefulBuf_FromSZ("xxyyzz"))) {
+      return "SkipLeading skipped";
+   }
+
+   Substring = UsefulBuf_SkipLeading(UsefulBuf_FromSZ("qqq"), 'q');
+   if(UsefulBuf_Compare(Substring, UsefulBuf_FromSZ(""))) {
+      return "SkipLeading didn't return empty";
+   }
+
+   Substring = UsefulBuf_SkipLeading(UsefulBuf_FromSZ("x"), 'x');
+   if(UsefulBuf_Compare(Substring, UsefulBuf_FromSZ(""))) {
+      return "SkipLeading didn't return empty";
+   }
+
+   Substring = UsefulBuf_SkipLeading(UsefulBuf_FromSZ("xxxxxxxxxxxx"), 'x');
+   if(UsefulBuf_Compare(Substring, UsefulBuf_FromSZ(""))) {
+      return "SkipLeading didn't return empty";
+   }
 
    const uint8_t pB[] = {0x01, 0x02, 0x03};
    UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
@@ -935,6 +960,31 @@
       return "UIB SetBufferLength failed";
    }
 
+   UsefulBufC CompCheck = UsefulBuf_FROM_SZ_LITERAL("abcd");
+   UsefulInputBuf_Init(&UIB, CompCheck);
+
+   if(UsefulInputBuf_Compare(&UIB, 0, 2, 2, 2) >= 0) {
+      return "UB 1 compared greater than UB2";
+   }
+   if(UsefulInputBuf_Compare(&UIB, 0, 2, 0, 2) != 0) {
+      return "UB1 and UB2 didn't compare equally";
+   }
+   if(UsefulInputBuf_Compare(&UIB, 2, 2, 0, 2) <= 0) {
+      return "UB2 compared less than UB1";
+   }
+   if(UsefulInputBuf_Compare(&UIB, 4, 1, 2, 2) <= 0) {
+      return "Off-the-end UB1 compared as less than UB2";
+   }
+   if(UsefulInputBuf_Compare(&UIB, 0, 5, 2, 2) <= 0) {
+      return "Off-the-end UB1 compared as less than UB2 (second)";
+   }
+   if(UsefulInputBuf_Compare(&UIB, 0, 2, 5, 1) >= 0) {
+      return "Off-the-end UB2 compared as less than UB2";
+   }
+   if(UsefulInputBuf_Compare(&UIB, 0, 2, 2, 3) >= 0) {
+      return "Off-the-end UB2 compared as less than UB2 (second)";
+   }
+
    return NULL;
 }
 
@@ -1036,3 +1086,205 @@
 
    return NULL;
 }
+
+
+const char * UOBExtraTests(void)
+{
+   #define COMPARE_TEST_SIZE 10
+   UsefulOutBuf_MakeOnStack( UOB, COMPARE_TEST_SIZE);
+   int                       nCompare;
+   UsefulBufC                Out;
+
+   /* Test UsefulOutBuf_Compare() */
+   UsefulOutBuf_AppendString(&UOB, "abcabdefab");
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 8, 2);
+   if(nCompare != 0) {
+      return "ab should compare equal";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 3, 3);
+   if(nCompare != 'd' - 'c') {
+      return "abc should not equal abd";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 3, 2, 8, 2);
+   if(nCompare != 0) {
+       return "ab should compare equal";
+    }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 2, 4, 5, 4);
+   if(nCompare != 'd' - 'c') {
+      return "ca should not equal de";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 5, 1, 2, 1);
+   if(nCompare != 'c' - 'd') {
+      return "de should not equal ca";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 7, 2, 8, 2);
+   if(nCompare !=  'a' - 'f') {
+      return "fa should not equal ab";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 10, 0, 10);
+   if(nCompare != 0) {
+      return "comparison to self failed";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 9, 1, 9, 1);
+   if(nCompare != 0) {
+      return "b should compare equal to b";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 10, 1, 10, 1);
+   if(nCompare != 0) {
+      return "Comparison off the end is equal";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 1, 100, 1);
+   if(nCompare != 0) {
+      return "Comparison off the end is equal";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 100, 1, 0, 1);
+   if(nCompare != 0) {
+      return "Comparison off the end is equal";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 3, 2);
+   if(nCompare > 0) {
+      return "Comparison of unequal lengths incorrect";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 8, 2, 0, 3);
+   if(nCompare < 0) {
+      return "Comparison of unequal lengths incorrect 2";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 2, 3);
+   if(nCompare != 'c' - 'a') {
+      return "Inequal lengths, but inequal strings";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 1, 3, 4, 2);
+   if(nCompare != 'd' - 'c') {
+      return "Inequal lengths, but inequal strings";
+   }
+
+   /* Test UsefulOutBuf_Swap() */
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 4, 8);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("efghabcd"))) {
+      return "swap fail 1";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 1, 2);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bacdefgh"))) {
+      return "swap fail 2";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 1, 8);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bcdefgha"))) {
+      return "swap fail 3";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 3, 4);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("dabcefgh"))) {
+      return "swap fail 4";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 9, 10, 11);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+      return "swap fail 5";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 4, 11);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+      return "swap fail 6";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 9, 0, 0);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+      return "swap fail 7";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 0, 0);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+      return "swap fail 8";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 8, 4, 0);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+      return "swap fail 9";
+   }
+
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+   UsefulOutBuf_Swap(&UOB, 0, 8, 4);
+   Out = UsefulOutBuf_OutUBuf(&UOB);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+      return "swap fail 10";
+   }
+
+
+   /* Test for UsefulOutBuf_GetOutput() */
+   UsefulOutBuf_Reset(&UOB);
+   UsefulOutBuf_AppendString(&UOB, "abc");
+   UsefulOutBuf_AppendString(&UOB, "xyz");
+
+   Out = UsefulOutBuf_OutUBufOffset(&UOB, 0);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcxyz"))) {
+      return "GetOutput fail 1";
+   }
+
+   Out = UsefulOutBuf_OutUBufOffset(&UOB, 5);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("z"))) {
+      return "GetOutput fail 2";
+   }
+
+   Out = UsefulOutBuf_OutUBufOffset(&UOB, 1);
+   if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bcxyz"))) {
+      return "GetOutput fail 3";
+   }
+
+   Out = UsefulOutBuf_OutUBufOffset(&UOB, 6);
+   if(!UsefulBuf_IsNULLC(Out)) {
+      return "GetOutput fail 4";
+   }
+
+   Out = UsefulOutBuf_OutUBufOffset(&UOB, 7);
+   if(!UsefulBuf_IsNULLC(Out)) {
+      return "GetOutput fail 5";
+   }
+
+   return NULL;
+}
diff --git a/test/UsefulBuf_Tests.h b/test/UsefulBuf_Tests.h
index 828f3f4..c0317e8 100644
--- a/test/UsefulBuf_Tests.h
+++ b/test/UsefulBuf_Tests.h
@@ -52,4 +52,6 @@
 
 const char * UBAdvanceTest(void);
 
+const char * UOBExtraTests(void);
+
 #endif
diff --git a/test/float_tests.c b/test/float_tests.c
index 6e00472..892942d 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -41,16 +41,16 @@
 #include "half_to_double_from_rfc7049.h"
 
 
-struct DoubleTestCase {
+struct FloatTestCase {
    double      dNumber;
-   double      fNumber;
+   float       fNumber;
    UsefulBufC  Preferred;
    UsefulBufC  NotPreferred;
    UsefulBufC  CDE;
    UsefulBufC  DCBOR;
 };
 
-/* Boundaries for all destination conversions to test at.
+/* Boundaries for destination conversions:
  *
  * smallest subnormal single  1.401298464324817e-45   2^^-149
  * largest subnormal single   1.1754942106924411e-38  2^^-126
@@ -62,29 +62,34 @@
  * smallest normal half      6.103515625E-5
  * largest half              65504.0
  *
- * Boundaries for origin conversions
+ * Boundaries for origin conversions:
  * smallest subnormal double 5.0e-324  2^^-1074
  * largest subnormal double
  * smallest normal double 2.2250738585072014e-308  2^^-1022
  * largest normal double 1.7976931348623157e308 2^^-1023
+ *
+ * Boundaries for double conversion to 64-bit integer:
+ * exponent 51, 52 significand bits set     4503599627370495
+ * exponent 52, 52 significand bits set     9007199254740991
+ * exponent 53, 52 bits set in significand  18014398509481982
  */
 
 /* Always four lines per test case so shell scripts can process into
- * other formats.  CDE and DCBOR standards are not complete yet,
- * encodings are a guess.  C string literals are used because they
+ * other formats. CDE and DCBOR standards are not complete yet,
+ * encodings are what is expected.  C string literals are used because they
  * are the shortest notation. They are used __with a length__ . Null
  * termination doesn't work because there are zero bytes.
  */
-static const struct DoubleTestCase DoubleTestCases[] =  {
+static const struct FloatTestCase FloatTestCases[] =  {
    /* Zero */
    {0.0,                                         0.0f,
     {"\xF9\x00\x00", 3},                         {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x00\x00", 3},                         {"\xF9\x00\x00", 3}},
+    {"\xF9\x00\x00", 3},                         {"\x00", 1}},
 
    /* Negative Zero */
    {-0.0,                                        -0.0f,
     {"\xF9\x80\x00", 3},                         {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x80\x00", 3},                         {"\xF9\x80\x00", 3}},
+    {"\xF9\x80\x00", 3},                         {"\x00", 1}},
 
    /* NaN */
    {NAN,                                         NAN,
@@ -104,12 +109,12 @@
    /* 1.0 */
    {1.0,                                         1.0f,
     {"\xF9\x3C\x00", 3},                         {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x3C\x00", 3},                         {"\xF9\x3C\x00", 3}},
+    {"\xF9\x3C\x00", 3},                         {"\x01", 1}},
 
-   /* -2.0 -- a negative number that is not zero */
+   /* -2.0 -- a negative */
    {-2.0,                                        -2.0f,
     {"\xF9\xC0\x00", 3},                         {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9},
-    {"\xF9\xC0\x00", 3},                         {"\xF9\x3C\x00", 3}},
+    {"\xF9\xC0\x00", 3},                         {"\x21", 1}},
 
    /* 1/3 */
    {0.333251953125,                              0.333251953125f,
@@ -129,45 +134,44 @@
    /* 6.097555160522461E-5 -- largest half-precision subnormal */
    {6.097555160522461E-5,                        0.0f,
     {"\xF9\x03\xFF", 3},                         {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x03\xFF", 3},                         {"\xF9\04\00", 3}},
-
-   /* 6.103515625E-5 -- smallest possible half-precision normal */
-   {6.103515625E-5,                              0.0f,
-    {"\xF9\04\00", 3},                           {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9},
-    {"\xF9\04\00", 3},                           {"\xF9\04\00", 3}},
-
-   /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */
-   {6.1035156250000014E-5,                       6.1035156250000014E-5f,
-    {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9},
-    {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}},
+    {"\xF9\x03\xFF", 3},                         {"\xF9\x03\xFF", 3}},
 
    /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */
    {6.1035156249999993E-5,  0.0f,
     {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
     {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
 
-   /* 65504.0 -- largest possible half-precision */
+   /* 6.103515625E-5 -- smallest half-precision normal */
+   {6.103515625E-5,                              0.0f,
+    {"\xF9\04\00", 3},                           {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9},
+    {"\xF9\04\00", 3},                           {"\xF9\04\00", 3}},
+
+   /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */
+   {6.1035156250000014E-5,                       0.0f,
+    {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9},
+    {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}},
+
+   /* 65504.0 -- largest half-precision */
    {65504.0,                                     0.0f,
     {"\xF9\x7B\xFF", 3},                         {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x7B\xFF", 3},                         {"\xF9\x7B\xFF", 3}},
+    {"\xF9\x7B\xFF", 3},                         {"\x19\xFF\xE0", 3}},
 
-   /* 65504.1 -- exponent too large and too much precision to convert */
+   /* 65504.1 -- exponent too large and too much precision to convert to half */
    {65504.1,                                     0.0f,
     {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9},
     {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}},
 
-    /* 65536.0 -- exponent too large but not too much precision for single */
+    /* 65536.0 -- exponent too large for half but not too much precision for single */
    {65536.0,                                     65536.0f,
     {"\xFA\x47\x80\x00\x00", 5},                 {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9},
-    {"\xFA\x47\x80\x00\x00", 5},                 {"\xFA\x47\x80\x00\x00", 5}},
+    {"\xFA\x47\x80\x00\x00", 5},                 {"\x1A\x00\x01\x00\x00", 5}},
 
    /* 1.401298464324817e-45 -- smallest single subnormal */
    {1.401298464324817e-45,                       1.40129846E-45f,
     {"\xFA\x00\x00\x00\x01", 5},                 {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9},
     {"\xFA\x00\x00\x00\x01", 5},                 {"\xFA\x00\x00\x00\x01", 5}},
 
-   /* 5.8774717541114375E-39 -- slightly smaller than the smallest
-    // single normal */
+   /* 5.8774717541114375E-39 -- slightly smaller than the smallest single normal */
    {5.8774717541114375E-39,                      5.87747175E-39f,
     {"\xFA\x00\x40\x00\x00", 5},                 {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9},
     {"\xFA\x00\x40\x00\x00", 5},                 {"\xFA\x00\x40\x00\x00", 5}},
@@ -192,20 +196,100 @@
     {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9},
     {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}},
 
+   /* 8388607 -- exponent 22 to test single exponent boundary */
+   {8388607,                                     8388607.0f,
+    {"\xFA\x4A\xFF\xFF\xFE", 5},                 {"\xFB\x41\x5F\xFF\xFF\xC0\x00\x00\x00", 9},
+    {"\xFA\x4A\xFF\xFF\xFE", 5},                 {"\x1A\x00\x7F\xFF\xFF", 5}},
+
+   /* 16777215 -- exponent 23 to test single exponent boundary */
+   {16777215,                                    16777215.0f,
+    {"\xFA\x4B\x7F\xFF\xFF", 5},                 {"\xFB\x41\x6F\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\x4B\x7F\xFF\xFF", 5},                 {"\x1A\x00\xFF\xFF\xFF", 5}},
+
    /* 16777216 -- converts to single without loss */
-   {16777216,                                    16777216,
+   {16777216,                                    16777216.0f,
     {"\xFA\x4B\x80\x00\x00", 5},                 {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9},
-    {"\xFA\x4B\x80\x00\x00", 5},                 {"\xFA\x4B\x80\x00\x00", 5}},
+    {"\xFA\x4B\x80\x00\x00", 5},                 {"\x1A\x01\x00\x00\x00", 5}},
 
-   /* 16777217 -- one more than above and fails conversion to single */
-   {16777217,                                    16777216,
+   /* 16777217 -- one more than above and fails conversion to single because of precision */
+   {16777217,                                    0.0f,
     {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9},
-    {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}},
+    {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\x1A\x01\x00\x00\x01", 5}},
+ 
+   /* 33554430 -- exponent 24 to test single exponent boundary */
+   {33554430,                                    33554430.0f,
+    {"\xFA\x4B\xFF\xFF\xFF", 5},                 {"\xFB\x41\x7F\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\x4B\xFF\xFF\xFF", 5},                 {"\x1A\x01\xFF\xFF\xFE",                 5}},
 
-   /* 3.4028234663852886E+38 -- largest possible single normal */
+   /* 4294967295 -- 2^^32 - 1 UINT32_MAX */
+   {4294967295,                                  0,
+    {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
+    {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x1A\xFF\xFF\xFF\xFF",                 5}},
+
+   /* 4294967296 -- 2^^32, UINT32_MAX + 1 */
+   {4294967296,                                  4294967296.0f,
+    {"\xFA\x4F\x80\x00\x00",                 5}, {"\xFB\x41\xF0\x00\x00\x00\x00\x00\x00", 9},
+    {"\xFA\x4F\x80\x00\x00",                 5}, {"\x1B\x00\x00\x00\x01\x00\x00\x00\x00", 9}},
+
+   /* 2251799813685248 -- exponent 51, 0 significand bits set, to test double exponent boundary */
+   {2251799813685248,                            2251799813685248.0f,
+    {"\xFA\x59\x00\x00\x00",                 5}, {"\xFB\x43\x20\x00\x00\x00\x00\x00\x00", 9},
+    {"\xFA\x59\x00\x00\x00",                 5}, {"\x1B\x00\x08\x00\x00\x00\x00\x00\x00", 9}},
+
+   /* 4503599627370495 -- exponent 51, 52 significand bits set to test double exponent boundary*/
+   {4503599627370495,                            0,
+    {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9},
+    {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\x1B\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
+
+   /* 9007199254740991 -- exponent 52, 52 significand bits set to test double exponent boundary */
+   {9007199254740991,                            0,
+    {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+    {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
+
+   /* 18014398509481982 -- exponent 53, 52 bits set in significand (double lacks precision to represent 18014398509481983) */
+   {18014398509481982,                           0,
+    {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+    {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFE", 9}},
+
+   /* 18014398509481984 -- next largest possible double above 18014398509481982  */
+   {18014398509481984,                           18014398509481984.0f,
+    {"\xFA\x5A\x80\x00\x00",                 5}, {"\xFB\x43\x50\x00\x00\x00\x00\x00\x00", 9},
+    {"\xFA\x5A\x80\x00\x00",                 5}, {"\x1B\x00\x40\x00\x00\x00\x00\x00\x00", 9}},
+   
+   /* 18446742974197924000.0.0 -- largest single that can convert to uint64 */
+   {18446742974197924000.0,                      18446742974197924000.0f,
+    {"\xFA\x5F\x7F\xFF\xFF",                 5}, {"\xFB\x43\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\x5F\x7F\xFF\xFF",                 5}, {"\x1B\xFF\xFF\xFF\x00\x00\x00\x00\x00", 9}},
+
+   /* 18446744073709550000.0 -- largest double that can convert to uint64, almost UINT64_MAX (18446744073709551615) */
+   {18446744073709550000.0,                      0,
+    {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+    {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00", 9}},
+
+   /* 18446744073709552000.0 -- just too large to convert to uint64, but converts to a single, just over UINT64_MAX  */
+   {18446744073709552000.0,                      18446744073709552000.0f,
+    {"\xFA\x5F\x80\x00\x00",                 5}, {"\xFB\x43\xF0\x00\x00\x00\x00\x00\x00", 9},
+    {"\xFA\x5F\x80\x00\x00",                 5}, {"\xFA\x5F\x80\x00\x00",                 5}},
+
+   /* -4294967295 -- negative UINT32_MAX */
+   {-4294967295.0,                               0,
+    {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
+    {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x3A\xFF\xFF\xFF\xFE", 5}},
+
+   /* -9223372036854774784.0 -- most negative double that converts to int64 */
+   {-9223372036854774784.0,                      0,
+    {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+    {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x3B\x7F\xFF\xFF\xFF\xFF\xFF\xFB\xFF", 9}},
+
+   /* -18446742974197923840.0 -- large negative that converts to float, but too large for int64 */
+   {-18446742974197923840.0,                     -18446742974197923840.0f,
+    {"\xFA\xDF\x7F\xFF\xFF",                 5}, {"\xFB\xC3\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\xDF\x7F\xFF\xFF",                 5}, {"\x3B\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF", 9}},
+
+   /* 3.4028234663852886E+38 -- largest possible single */
    {3.4028234663852886E+38,                      3.40282347E+38f,
-    {"\xFA\x7F\x7F\xFF\xFF", 5},                 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
-    {"\xFA\x7F\x7F\xFF\xFF", 5},                 {"\xFA\x7F\x7F\xFF\xFF", 5}},
+    {"\xFA\x7F\x7F\xFF\xFF",                 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\x7F\x7F\xFF\xFF",                 5}, {"\xFA\x7F\x7F\xFF\xFF",                 5}},
 
    /* 3.402823466385289E+38 -- slightly larger than largest possible single */
    {3.402823466385289E+38,                       0.0f,
@@ -242,9 +326,12 @@
 };
 
 
+/* Can't use types double and float here because there's no way in C to
+ * construct arbitrary payloads for those types.
+ */
 struct NaNTestCase {
-   uint64_t    uDouble;
-   uint32_t    uSingle;
+   uint64_t    uDouble; /* Converted to double in test */
+   uint32_t    uSingle; /* Converted to single in test */
    UsefulBufC  Preferred;
    UsefulBufC  NotPreferred;
    UsefulBufC  CDE;
@@ -292,14 +379,13 @@
    /* Payload with all bits set */
    {0x7fffffffffffffff,                          0x00000000,
     {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
+    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
 
    /* List terminator */
    {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
 };
 
 
-
 /* Public function. See float_tests.h
  *
  * This is the main test of floating-point encoding / decoding. It is
@@ -311,7 +397,7 @@
 FloatValuesTests(void)
 {
    unsigned int                 uTestIndex;
-   const struct DoubleTestCase *pTestCase;
+   const struct FloatTestCase  *pTestCase;
    const struct NaNTestCase    *pNaNTestCase;
    MakeUsefulBufOnStack(        TestOutBuffer, 20);
    UsefulBufC                   TestOutput;
@@ -325,12 +411,11 @@
 #endif
 
    /* Test a variety of doubles */
-   for(uTestIndex = 0; DoubleTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
-      pTestCase = &DoubleTestCases[uTestIndex];
+   for(uTestIndex = 0; FloatTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
+      pTestCase = &FloatTestCases[uTestIndex];
 
-     // if(pTestCase->dNumber == 1.1754943508222874E-38) {
-         if(uTestIndex == 19) {
-         uErr = 99; /* For setting break points for particular tests */
+      if(uTestIndex == 40) {
+         uDecoded = 1;
       }
 
       /* Number Encode of Preferred */
@@ -357,6 +442,47 @@
          return MakeTestResultCode(uTestIndex, 2, 200);
       }
 
+      /* Number Encode of CDE */
+      QCBOREncode_Init(&EnCtx, TestOutBuffer);
+      QCBOREncode_SerializationCDE(&EnCtx);
+      QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
+      uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+
+      if(uErr != QCBOR_SUCCESS) {
+         return MakeTestResultCode(uTestIndex, 20, uErr);;
+      }
+      if(UsefulBuf_Compare(TestOutput, pTestCase->CDE)) {
+         return MakeTestResultCode(uTestIndex, 21, 200);
+      }
+
+      /* Number Encode of dCBOR */
+      QCBOREncode_Init(&EnCtx, TestOutBuffer);
+      QCBOREncode_SerializationdCBOR(&EnCtx);
+      QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
+      uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+
+      if(uErr != QCBOR_SUCCESS) {
+         return MakeTestResultCode(uTestIndex, 22, uErr);;
+      }
+      if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
+         return MakeTestResultCode(uTestIndex, 23, 200);
+      }
+
+      if(pTestCase->fNumber != 0) {
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_SerializationdCBOR(&EnCtx);
+         QCBOREncode_AddFloat(&EnCtx, pTestCase->fNumber);
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex, 24, uErr);;
+         }
+         if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
+            return MakeTestResultCode(uTestIndex, 25, 200);
+         }
+      }
+
+
       /* Number Decode of Preferred */
       QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
       uErr = QCBORDecode_GetNext(&DCtx, &Item);
@@ -382,32 +508,32 @@
        * indicates single-precision in the encoded CBOR. */
       if(pTestCase->Preferred.len == 5) {
          if(Item.uDataType != QCBOR_TYPE_FLOAT) {
-            return MakeTestResultCode(uTestIndex, 4, 0);
+            return MakeTestResultCode(uTestIndex, 41, 0);
          }
          if(isnan(pTestCase->dNumber)) {
             if(!isnan(Item.val.fnum)) {
-               return MakeTestResultCode(uTestIndex, 5, 0);
+               return MakeTestResultCode(uTestIndex, 51, 0);
             }
          } else {
             if(Item.val.fnum != pTestCase->fNumber) {
-               return MakeTestResultCode(uTestIndex, 6, 0);
+               return MakeTestResultCode(uTestIndex, 61, 0);
             }
          }
       } else {
          if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
-            return MakeTestResultCode(uTestIndex, 4, 0);
+            return MakeTestResultCode(uTestIndex, 42, 0);
          }
          if(isnan(pTestCase->dNumber)) {
             if(!isnan(Item.val.dfnum)) {
-               return MakeTestResultCode(uTestIndex, 5, 0);
+               return MakeTestResultCode(uTestIndex, 52, 0);
             }
          } else {
             if(Item.val.dfnum != pTestCase->dNumber) {
-               return MakeTestResultCode(uTestIndex, 6, 0);
+               return MakeTestResultCode(uTestIndex, 62, 0);
             }
          }
       }
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
 
       /* Number Decode of Not Preferred */
       QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
@@ -441,6 +567,7 @@
 
       /* NaN Encode of Preferred */
       QCBOREncode_Init(&EnCtx, TestOutBuffer);
+      QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
       QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
       uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
       if(uErr != QCBOR_SUCCESS) {
@@ -489,6 +616,7 @@
 
       /* NaN Encode of Not Preferred */
       QCBOREncode_Init(&EnCtx, TestOutBuffer);
+      QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
       QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
       uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
       if(uErr != QCBOR_SUCCESS) {
@@ -498,8 +626,9 @@
          return MakeTestResultCode(uTestIndex+100, 11, 200);
       }
 
-      /* NaN Decode of Preferred */
+      /* NaN Decode of Not Preferred */
       QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
+      QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
       uErr = QCBORDecode_GetNext(&DCtx, &Item);
       if(uErr != QCBOR_SUCCESS) {
          return MakeTestResultCode(uTestIndex+100, 12, uErr);
@@ -535,6 +664,7 @@
 
       /* NaN Decode of Not Preferred */
       QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
+      QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
       uErr = QCBORDecode_GetNext(&DCtx, &Item);
       if(uErr != QCBOR_SUCCESS) {
          return MakeTestResultCode(uTestIndex+100, 13, uErr);
@@ -543,6 +673,21 @@
       if(uDecoded != pNaNTestCase->uDouble) {
          return MakeTestResultCode(uTestIndex+100, 13, 200);
       }
+
+
+      /* NaN Encode of DCBOR */
+      QCBOREncode_Init(&EnCtx, TestOutBuffer);
+      QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
+      QCBOREncode_SerializationdCBOR(&EnCtx);
+      QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
+      uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+      if(uErr != QCBOR_SUCCESS) {
+         return MakeTestResultCode(uTestIndex+100, 14, uErr);;
+      }
+      if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
+         return MakeTestResultCode(uTestIndex+100, 14, 200);
+      }
+
    }
 
    return 0;
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 910d43a..e4f0f9e 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -35,6 +35,7 @@
 #include "qcbor/qcbor_encode.h"
 #include "qcbor/qcbor_decode.h"
 #include "qcbor/qcbor_spiffy_decode.h"
+#include "qcbor/qcbor_tag_decode.h"
 #include <string.h>
 #include <math.h> // for fabs()
 #include "not_well_formed_cbor.h"
@@ -79,8 +80,11 @@
    return (int32_t)uCode;
 }
 
+
 /*
    [
+      -18446744073709551616,
+      -18446744073709551615,
       -9223372036854775808,
       -4294967297,
       -4294967296,
@@ -132,7 +136,9 @@
  */
 
 static const uint8_t spExpectedEncodedInts[] = {
-   0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
+   0x98, 0x31, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0x3b, 0xFf, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xfe, 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,
@@ -172,6 +178,18 @@
 
    if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
       return (int32_t)nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_65BIT_NEG_INT ||
+      Item.val.uint64 != 0xffffffffffffffff)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return (int32_t)nCBORError;
+   if(Item.uDataType != QCBOR_TYPE_65BIT_NEG_INT ||
+      Item.val.uint64 != 0xfffffffffffffffe)
+      return -1;
+
+   if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+      return (int32_t)nCBORError;
    if(Item.uDataType != QCBOR_TYPE_INT64 ||
       Item.val.int64 != -9223372036854775807LL - 1)
       return -1;
@@ -487,14 +505,6 @@
 }
 
 
-/* One less than the smallest negative integer allowed in C. Decoding
-   this should fail.
-   -9223372036854775809
- */
-static const uint8_t spTooSmallNegative[] = {
-   0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
 
 /*
    Tests the decoding of lots of different integers sizes
@@ -515,16 +525,6 @@
       return nReturn;
    }
 
-   // The one large negative integer that can be parsed
-   QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooSmallNegative),
-                    QCBOR_DECODE_MODE_NORMAL);
-
-   QCBORItem item;
-   if(QCBORDecode_GetNext(&DCtx, &item) != QCBOR_ERR_INT_OVERFLOW) {
-      nReturn = -4000;
-   }
-
    return(nReturn);
 }
 
@@ -1525,11 +1525,13 @@
    UsefulBufC         Encoded;
 
    /* Big decode of a map with a wide variety or labels */
+   // TODO: test  pPerverseLabels with v2 behavior
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pPerverseLabels),
                     QCBOR_DECODE_MODE_MAP_AS_ARRAY);
-      UsefulBuf_MAKE_STACK_UB(Pool, 100);
-      QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+   QCBORDecode_CompatibilityV1(&DCtx);
+   UsefulBuf_MAKE_STACK_UB(Pool, 100);
+   QCBORDecode_SetMemPool(&DCtx, Pool, 0);
 
    uErr = QCBORDecode_GetNext(&DCtx, &Item);
    if(uErr) {
@@ -1868,7 +1870,6 @@
    }
    if(Item.uLabelType != QCBOR_TYPE_NONE ||
       Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY ||
-      !QCBORDecode_IsTagged(&DCtx, &Item, 258) ||
       Item.val.uCount != UINT16_MAX) {
       return MakeTestResultCode(10, 65, 0);
    }
@@ -1908,7 +1909,6 @@
    }
    if(Item.uLabelType != QCBOR_TYPE_NONE ||
       Item.uDataType != QCBOR_TYPE_ARRAY ||
-      !QCBORDecode_IsTagged(&DCtx, &Item, 23) ||
       Item.val.uCount != 0) {
       return MakeTestResultCode(10, 73, 0);
    }
@@ -1928,7 +1928,8 @@
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pPerverseLabels),
                     QCBOR_DECODE_MODE_MAP_AS_ARRAY);
-      QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+   QCBORDecode_CompatibilityV1(&DCtx);
+   QCBORDecode_SetMemPool(&DCtx, Pool, 0);
 
    QCBORDecode_EnterArray(&DCtx, &Item);
    bool b;
@@ -2044,9 +2045,6 @@
    }
 
    QCBORDecode_EnterArray(&DCtx, &Item);
-   if(!QCBORDecode_IsTagged(&DCtx, &Item, 258)) {
-      return MakeTestResultCode(11, 17, 0);
-   }
    if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY) {
       return MakeTestResultCode(11, 18, 0);
    }
@@ -2062,9 +2060,6 @@
       return MakeTestResultCode(11, 21, 0);
    }
    QCBORDecode_EnterArray(&DCtx, &Item);
-   if(!QCBORDecode_IsTagged(&DCtx, &Item, 23)) {
-      return MakeTestResultCode(11, 22, 0);
-   }
    if(Item.uDataType != QCBOR_TYPE_ARRAY) {
       return MakeTestResultCode(11, 23, 0);
    }
@@ -2601,6 +2596,7 @@
       const struct DecodeFailTestInput *pF = &pFailInputs[nIndex];
 
       QCBORDecode_Init(&DCtx, pF->Input, pF->DecoderMode);
+      QCBORDecode_CompatibilityV1(&DCtx);
 
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
       /* Set up the decoding context including a memory pool so that
@@ -2614,7 +2610,11 @@
       }
 #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
 
-      if(nIndex == 4) {
+      if(nIndex == 0) {
+         uCBORError = 9; /* For setting break points */
+      }
+
+      if(strncmp("map with map label with non-preferred part", pF->szDescription, 25) == 0) {
          uCBORError = 9; /* For setting break points */
       }
 
@@ -2626,7 +2626,7 @@
          uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
       } while(uCBORError == QCBOR_SUCCESS);
 
-      /* Must get the expected error or the this test fails.
+      /* Must get the expected error or the test fails.
        * The data and label type must also be QCBOR_TYPE_NONE.
        */
       if(uCBORError != pF->nError ||
@@ -3430,6 +3430,8 @@
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput),
                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
 
    /* 1. The valid date string "1985-04-12" */
    if((uError = QCBORDecode_GetNext(&DCtx, &Item))) {
@@ -3475,11 +3477,11 @@
       return -7;
    }
    if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
-      Item.val.epochDate.nSeconds != 1400000001 ||
+      Item.val.epochDate.nSeconds != 1400000001
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-      Item.val.epochDate.fSecondsFraction != 0 ||
+      || Item.val.epochDate.fSecondsFraction != 0
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
-      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B64)) {
+      ) {
       return -8;
    }
 
@@ -3675,9 +3677,12 @@
                       nEpochDays2;
    UsefulBufC         StringDate1, StringDate2, StringDays2;
 
+   // TODO: test spSpiffyDateTestInput in v2 mode
    QCBORDecode_Init(&DC,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyDateTestInput),
                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DC);
+
 
    /* Items are in an array or map to test look up by label and other
     * that might not occur in isolated items. But it does make the
@@ -3774,7 +3779,7 @@
    int64_t            nEpochDate2,
                       nEpochDateFail,
                       nEpochDate1400000000, nEpochDays1;
-   UsefulBufC         StringDays1;
+   UsefulBufC         StringDays1, StringDate3;
    uint64_t           uTag1, uTag2;
 
    // Tagged date string
@@ -3876,7 +3881,8 @@
    }
 
    // Bad content for string date
-   QCBORDecode_GetDateString(&DC, QCBOR_TAG_REQUIREMENT_TAG, &StringDate1);
+   // TODO: should this set StringDate3 to NULL? variance between v1 and v2
+   QCBORDecode_GetDateString(&DC, QCBOR_TAG_REQUIREMENT_TAG, &StringDate3);
    uError = QCBORDecode_GetAndResetError(&DC);
    if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
       return 4;
@@ -3945,10 +3951,41 @@
       return 208;
    }
 
+
+   QCBORDecode_Init(&DC,
+                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyDateTestInput),
+                    QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_EnterArray(&DC, NULL);
+   QCBORDecode_EnterMap(&DC, NULL);
+   QCBORDecode_ExitMap(&DC);
+   QCBORDecode_EnterMap(&DC, NULL);
+
+   /*
+    Item with label 01. It has an extra tag number and the date tag number.
+    */
+   // QCBOR_TAG_REQUIREMENT_TAG
+   // QCBOR_TAG_REQUIREMENT_NOT_A_TAG
+   // QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG
+   // QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS
+   /*   0x01,
+    0xda, 0x03, 0x03, 0x03, 0x03, // An additional tag
+    0xc1, // tag for epoch date
+    0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
+   */
+#ifndef QCBOR_DISABLE_TAGS
+   QCBORDecode_GetNextTagNumberInMapN(&DC, 1, &uTag1);
+   QCBORDecode_GetEpochDateInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDate2);
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+
+
    return 0;
 }
 
 
+#ifndef QCBOR_DISABLE_TAGS
 // Input for one of the tagging tests
 static const uint8_t spTagInput[] = {
    0xd9, 0xd9, 0xf7, // CBOR magic number
@@ -4012,8 +4049,9 @@
  DB 9192939495969798 # tag(10489608748473423768)
    80                # array(0)
  */
-static const uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95,
-                                      0x96, 0x97, 0x98, 0x80};
+// TODO: get rid of this?
+//static const uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95,
+//                                      0x96, 0x97, 0x98, 0x80};
 
 /*
 DB 9192939495969798 # tag(10489608748473423768)
@@ -4022,8 +4060,10 @@
          C7         # tag(7)
             80      # array(0)
 */
-static const uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
-                                 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80};
+// TODO: get rid of this?
+
+//static const uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+//                                 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80};
 
 /*
    55799(55799(55799({
@@ -4101,7 +4141,7 @@
    0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string
 
    // This last case makes the array untraversable because it is
-   // an uncrecoverable error. Make sure it stays last and is the only
+   // an unrecoverable error. Make sure it stays last and is the only
    // instance so the other tests can work.
 };
 
@@ -4116,8 +4156,7 @@
 
 static int32_t CheckCSRMaps(QCBORDecodeContext *pDC);
 
-
-int32_t OptTagParseTest(void)
+int32_t TagNumberDecodeTest(void)
 {
    QCBORDecodeContext DCtx;
    QCBORItem          Item;
@@ -4127,8 +4166,9 @@
 
 
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
    /*
     This test matches the magic number tag and the fraction tag
@@ -4138,8 +4178,7 @@
    if(uError != QCBOR_SUCCESS) {
       return -2;
    }
-   if(Item.uDataType != QCBOR_TYPE_ARRAY ||
-      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) {
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
       return -3;
    }
 
@@ -4150,7 +4189,7 @@
 #ifdef QCBOR_DISABLE_EXP_AND_MANTISSA
    if(uError != QCBOR_SUCCESS ||
       Item.uDataType != QCBOR_TYPE_ARRAY ||
-      !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) ||
+ //     !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) || // TODO: worried this test is incorrect
       QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_DECIMAL_FRACTION ||
       QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 ||
       QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 ||
@@ -4234,68 +4273,140 @@
       return -10;
    }
 
-   // ----------------------------------
-   // This test sets up a caller-config list that includes the very large
-   // tage and then matches it. Caller-config lists are no longer
-   // used or needed. This tests backwards compatibility with them.
+   /* Testing with v2 */
    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);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput),
+                     QCBOR_DECODE_MODE_NORMAL);
 
-   if(QCBORDecode_GetNext(&DCtx, &Item)) {
+   /*
+    This test matches the magic number tag and the fraction tag
+    55799([...])
+    */
+   uint64_t uTagNumber;
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_SUCCESS) {
+      return -200;
+   }
+   if(uTagNumber != CBOR_TAG_CBOR_MAGIC) {
+      return -300;
+   }
+
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+   if(uError != QCBOR_SUCCESS) {
+      return -2;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 1) {
+      return -1003;
+   }
+   if(QCBORDecode_GetNthTagNumber(&DCtx, &Item, 0) != CBOR_TAG_CBOR_MAGIC) {
+      return -500;
+   }
+
+
+
+   /*
+    4([1,3])
+    */
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_SUCCESS) {
+      return -200;
+   }
+   if(uTagNumber != CBOR_TAG_DECIMAL_FRACTION) {
+      return -300;
+   }
+
+
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+   if(uError != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_DECIMAL_FRACTION ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 ||
+      Item.val.uCount != 2) {
+      return -4;
+   }
+   // consume the items in the array
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+
+
+   /*
+    More than 4 tags on an item 225(226(227(228(229([])))))
+    */
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_ERR_TOO_MANY_TAGS) {
+      return -2;
+   }
+
+
+   /* tag 10489608748473423768(
+             2442302356(
+                21590(
+                   240(
+                      []))))
+    */
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_SUCCESS ||  uTagNumber != 10489608748473423768ULL) {
+      return -6;
+   }
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_SUCCESS || uTagNumber != 2442302356ULL) {
+      return -6;
+   }
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_SUCCESS || uTagNumber != 21590ULL) {
+      return -6;
+   }
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_SUCCESS || uTagNumber != 240ULL) {
+      return -6;
+   }
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+   if(uError != QCBOR_SUCCESS) {
+      return -2;
+   }
+   if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 0) {
+      return -1003;
+   }
+
+   /* tag 21590(
+             10489608748473423768(
+                2442302357(
+                   21591(
+                       []))))
+    */
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+   if(uError != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_ARRAY ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 65534ULL ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 2442302357ULL ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 10489608748473423768ULL ||
+      QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 21590ULL) {
       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) {
+
+   /* Make sure to blow past the limit of tags that must be mapped.
+      works in conjuntion with entries above.
+    269488144(269488145(269488146(269488147([]))))
+    */
+   uError = QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uError != QCBOR_ERR_TOO_MANY_TAGS) {
       return -9;
    }
 
-   //------------------------
-   // Sets up a caller-configured list and look up something not in it
-   // Another backwards compatibility test.
-   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;
+   uError = QCBORDecode_GetNext(&DCtx, &Item);
+   if(uError == QCBOR_SUCCESS) {
+      return -10;
    }
+   /* 0-0-0-0-0-0-0--0-0--0*/
 
-   uint64_t puTags[4];
-   QCBORTagListOut Out = {0, 4, puTags};
-
-
-   // This tests retrievel of the full tag list
-   QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags),
-                    QCBOR_DECODE_MODE_NORMAL);
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -12;
-   }
-   if(puTags[0] != 0x9192939495969798 ||
-      puTags[1] != 0x88 ||
-      puTags[2] != 0x06 ||
-      puTags[3] != 0x07) {
-      return -13;
-   }
-
-   // ----------------------
-   // This tests 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;
-   }
 
 
 
@@ -4304,196 +4415,90 @@
    // It is a bit of a messy test and maybe could be improved, but
    // it is retained as a backwards compatibility check.
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    int n = CheckCSRMaps(&DCtx);
    if(n) {
       return n-2000;
    }
+   /* -9-9-9-9-9-9-9- */
 
-   Out = (QCBORTagListOut){0, 16, puTags};
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+                     QCBOR_DECODE_MODE_NORMAL);
 
-   /* With the spiffy decode revision, this tag list is not used.
-    It doesn't matter if a tag is in this list or not so some
-    tests that couldn't process a tag because it isn't in this list
-    now can process these unlisted tags. The tests have been
-    adjusted for this. */
-   const uint64_t puTagList[] = {773, 1, 90599561};
-   const QCBORTagListIn TagList = {3, puTagList};
-   QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList);
-
-
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -100;
+   QCBORDecode_VGetNextTagNumber(&DCtx, &uTagNumber);
+   QCBORDecode_VGetNextTagNumber(&DCtx, &uTagNumber);
+   QCBORDecode_VGetNextTagNumber(&DCtx, &uTagNumber);
+   if(uTagNumber != 55799) {
+      return 6000;
    }
-   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;
+   QCBORDecode_EnterMap(&DCtx, NULL);
+   uTagNumber = QCBORDecode_GetNthTagNumberOfLast(&DCtx, 0);
+   if(uTagNumber != 55799) {
+      return 6000;
    }
 
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -102;
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -22, &uTagNumber);
+   if(uTagNumber != 23) {
+      return 6000;
    }
-   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.val.uCount != 2 ||
-      puTags[0] != 5859837686836516696 ||
-      puTags[1] != 7 ||
-      Out.uNumUsed != 2) {
-      return -103;
+   QCBORDecode_GetItemInMapN(&DCtx, -22, QCBOR_TYPE_ANY, &Item);
+
+   uTagNumber = QCBORDecode_GetNthTagNumberOfLast(&DCtx, 0);
+   if(uTagNumber != 23) {
+      return 6000;
    }
 
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -104;
-   }
-   if(Item.uDataType != QCBOR_TYPE_MAP ||
-      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;
-   }
+   //---
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -23, &uTagNumber);
 
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -109;
+   QCBORDecode_EnterMapFromMapN(&DCtx, -23);
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNPROCESSED_TAG_NUMBER) {
+      return -99;
    }
-   if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
-      !QCBORDecode_IsTagged(&DCtx, &Item, 16) ||
-      Item.val.string.len != 9 ||
-      puTags[0] != 16 ||
-      puTags[3] != 7 ||
-      Out.uNumUsed != 4) {
-      return -110;
-   }
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -23, &uTagNumber);
 
-   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;
-   }
+   QCBORDecode_EnterMapFromMapN(&DCtx, -23);
 
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -111;
+   uTagNumber = QCBORDecode_GetNthTagNumberOfLast(&DCtx, 1);
+   if(uTagNumber != 7) {
+      return 6000;
    }
-   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;
-   }
+   UsefulBufC TX;
 
-   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;
-   }
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -20, &uTagNumber);
+   QCBORDecode_EnterMapFromMapN(&DCtx, -20);
 
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -115;
+   QCBORDecode_GetTextStringInMapN(&DCtx, -18, &TX);
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNPROCESSED_TAG_NUMBER) {
+      return -99;
    }
-   if(Item.uDataType != QCBOR_TYPE_MAP ||
-      !QCBORDecode_IsTagged(&DCtx, &Item, 9) ||
-      Item.val.uCount != 1 ||
-      puTags[0] != 9 ||
-      Out.uNumUsed != 1) {
-      return -116;
-   }
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -18, &uTagNumber);
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -18, &uTagNumber);
+   QCBORDecode_GetNextTagNumberInMapN(&DCtx, -18, &uTagNumber);
+   QCBORDecode_GetTextStringInMapN(&DCtx, -18, &TX);
 
-   if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
-      return -116;
-   }
-   if(Item.uDataType != QCBOR_TYPE_INT64 ||
-      Item.val.int64 != -7 ||
-      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 ||
-      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;
-   }
+   QCBORDecode_ExitMap(&DCtx);
 
-   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;
-   }
 
+   /* -9-9-9-9-9-9-9- */
+
+
+
+ 
    UsefulBufC DateString;
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
    QCBORDecode_EnterArray(&DCtx, NULL);
    // tagged date string
@@ -4505,7 +4510,7 @@
    }
    // untagged byte string
    QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString);
-   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
       return 101;
    }
    // tagged regex
@@ -4529,8 +4534,10 @@
 
 
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    QCBORDecode_EnterMap(&DCtx, NULL);
    if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 55799) {
       return 200;
@@ -4561,8 +4568,10 @@
 
 
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    QCBORDecode_EnterMap(&DCtx, NULL);
    QCBORDecode_EnterMapFromMapN(&DCtx, -23);
    if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) {
@@ -4577,8 +4586,10 @@
 
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
-                    QCBOR_DECODE_MODE_MAP_AS_ARRAY);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+                     QCBOR_DECODE_MODE_MAP_AS_ARRAY);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    QCBORDecode_EnterArray(&DCtx, NULL);
    if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 55799) {
       return 230;
@@ -4610,8 +4621,9 @@
 
 
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
    QCBORDecode_EnterArray(&DCtx, NULL);
    // tagged date string
@@ -4623,12 +4635,12 @@
    }
    // untagged byte string
    QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString);
-   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
       return 251;
    }
    // tagged regex
    QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString);
-   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
       return 252;
    }
    // tagged date string with a byte string
@@ -4643,8 +4655,9 @@
    }
 
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
    QCBORDecode_EnterArray(&DCtx, NULL);
    // tagged date string
@@ -4664,12 +4677,12 @@
    }
    // tagged regex
    QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString);
-   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
       return 303;
    }
    // tagged date string with a byte string
    QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString);
-   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) {
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_BAD_TAG_CONTENT) { // TODO: make sure this is the right error
       return 304;
    }
    // See comments above
@@ -4681,6 +4694,7 @@
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedString),
                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
    /* See that QCBORDecode_GetTextString() ignores tags */
    QCBORDecode_GetTextString(&DCtx, &UBC);
@@ -4691,7 +4705,7 @@
       return 401;
    }
 
-   uint64_t uTagNumber = QCBORDecode_GetNthTagOfLast(&DCtx, 0);
+   uTagNumber = QCBORDecode_GetNthTagOfLast(&DCtx, 0);
    if(uTagNumber != 240) {
       return 404;
    }
@@ -4700,6 +4714,7 @@
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedInt),
                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
    /* See that QCBORDecode_GetInt64() ignores tags */
    QCBORDecode_GetInt64(&DCtx, &nInt);
    if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) {
@@ -4716,6 +4731,7 @@
 
    return 0;
 }
+#endif /* ! QCBOR_DISABLE_TAGS */
 
 /*
  * These are showing the big numbers converted to integers.
@@ -4748,23 +4764,163 @@
        0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
+
+struct BignumDecodeTest {
+   const char *szDescription;
+   UsefulBufC  Encoded;
+   QCBORError  uErr;
+   UsefulBufC  ExpectedBigNum;
+   bool        bExpectedSign;
+};
+
 #ifndef QCBOR_DISABLE_TAGS
+static struct BignumDecodeTest BignumDecodeTests[] = {
+   {
+      "-18446744073709551617",
+      {"\xC3\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+      QCBOR_SUCCESS,
+      {"\x01\x00\x00\x00\x00\x00\x00\x00\x01", 9},
+      true
+   },
+   {
+      "-18446744073709551616 preferred",
+      {"\x3B\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+      QCBOR_SUCCESS,
+      {"\x01\x00\x00\x00\x00\x00\x00\x00\x00", 9},
+      true
+   },
+   {
+      "-18446744073709551616 as big num",
+      {"\xC3\x48\xff\xff\xff\xff\xff\xff\xff\xff", 10},
+      QCBOR_SUCCESS,
+      {"\x01\x00\x00\x00\x00\x00\x00\x00\x00", 9},
+      true
+   },
+   {
+      "-9223372036854775808  -(2^63)",
+      {"\x3B\x7f\xff\xff\xff\xff\xff\xff\xff", 9},
+      QCBOR_SUCCESS,
+      {"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
+      true
+   },
+   {
+      "Preferred -1",
+      {"\x20", 1},
+      QCBOR_SUCCESS,
+      {"\x01", 1},
+      true
+   },
+   {
+      "bignum -1",
+      {"\xc3\x42\x00\x00", 4},
+      QCBOR_SUCCESS,
+      {"\x01", 1},
+      true
+   },
+   {
+      "bignum -1 empty buffer",
+      {"\xc3\x40", 2},
+      QCBOR_SUCCESS,
+      {"\x01", 1},
+      true
+   },
+   {
+      "Preferred Zero",
+      {"\x00", 1},
+      QCBOR_SUCCESS,
+      {"\x00", 1},
+      false
+   },
+   {
+      "Bignum zero",
+      {"\xC2\x40", 2},
+      QCBOR_SUCCESS,
+      {"\x00", 1},
+      false
+   },
+   {
+      "Bignum zero with leading zeros",
+      {"\xC2\x43\x00\x00\x00", 5},
+      QCBOR_SUCCESS,
+      {"\x00", 1},
+      false
+   },
+   {
+      "Preferred one",
+      {"\x01", 1},
+      QCBOR_SUCCESS,
+      {"\x01", 1},
+      false
+   },
+   {
+      "Bignum one",
+      {"\xc2\x41\x01", 3},
+      QCBOR_SUCCESS,
+      {"\x01", 1},
+      false
+   },
+   {
+      "512 with leading zeros",
+      {"\x1A\x00\x00\x02\x00", 5},
+      QCBOR_SUCCESS,
+      {"\x02\x00", 2},
+      false
+   },
+   {
+      "512 with leading zeros again",
+      {"\xc2\x46\x00\x00\x00\x00\x02\x00", 8},
+      QCBOR_SUCCESS,
+      {"\x02\x00", 2},
+      false
+   },
+   {
+      "1297093868730187896 (a byte pattern with zeros and different digits",
+      {"\x1B\x12\x00\x34\x00\x56\x00\x00\x78", 9},
+      QCBOR_SUCCESS,
+      {"\x12\x00\x34\x00\x56\x00\x00\x78", 8},
+      false
+   },
+   {
+      "Preferred UINT64_MAX",
+      {"\x1B\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+      QCBOR_SUCCESS,
+      {"\xff\xff\xff\xff\xff\xff\xff\xff", 8},
+      false
+   },
+   {
+      "Bignum UINT64_MAX",
+      {"\xC2\x48\xff\xff\xff\xff\xff\xff\xff\xff", 10},
+      QCBOR_SUCCESS,
+      {"\xff\xff\xff\xff\xff\xff\xff\xff", 8},
+      false
+   },
+   {
+      "UINT64_MAX + 1",
+      {"\xC2\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+      QCBOR_SUCCESS,
+      {"\x01\x00\x00\x00\x00\x00\x00\x00\x00", 9},
+      false
+   }
+};
+
+
 /* The expected big num */
 static const uint8_t spBigNum[] = {
    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00};
-#endif /* QCBOR_DISABLE_TAGS */
+#endif /* ! QCBOR_DISABLE_TAGS */
 
 
-int32_t BignumParseTest(void)
+int32_t BignumDecodeTest(void)
 {
    QCBORDecodeContext DCtx;
    QCBORItem Item;
    QCBORError nCBORError;
 
    QCBORDecode_Init(&DCtx,
-                    UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput),
-                    QCBOR_DECODE_MODE_NORMAL);
+                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput),
+                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
 
    //
@@ -4832,10 +4988,75 @@
       UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
       return -14;
    }
-
-
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
 
+
+   unsigned                  uTestIndex;
+   unsigned                  uTestCount;
+   struct BignumDecodeTest  *pTest;
+   QCBORError                uErr;
+   UsefulBuf_MAKE_STACK_UB(  BignumBuf, 200);
+   UsefulBufC                ResultBigNum;
+   bool                      bIsNeg;
+
+   uTestCount = (int)C_ARRAY_COUNT(BignumDecodeTests, struct BignumDecodeTest);
+
+   for(uTestIndex = 0; uTestIndex < uTestCount; uTestIndex++) {
+      pTest = &BignumDecodeTests[uTestIndex];
+
+      if(uTestIndex == 9) {
+         bIsNeg = false; /* Line of code so a break point can be set. */
+      }
+
+      QCBORDecode_Init(&DCtx, pTest->Encoded, 0);
+      QCBORDecode_CompatibilityV1(&DCtx);
+
+      uErr = QCBORDecode_GetNext(&DCtx, &Item);
+      if(uErr != QCBOR_SUCCESS) {
+         return MakeTestResultCode(uTestIndex, 1, uErr);
+      }
+
+      uErr = QCBORDecode_ProcessBigNumber(Item, BignumBuf, &ResultBigNum, &bIsNeg);
+      if(uErr != pTest->uErr) {
+         return MakeTestResultCode(uTestIndex, 2, uErr);
+      }
+
+      if(uErr != QCBOR_SUCCESS) {
+         continue; /* This test passed */
+      }
+
+      if(UsefulBuf_Compare(ResultBigNum, pTest->ExpectedBigNum)) {
+         return MakeTestResultCode(uTestIndex, 3, 0);
+      }
+
+      if(bIsNeg != pTest->bExpectedSign) {
+         return MakeTestResultCode(uTestIndex, 4, 0);
+      }
+
+      uErr = QCBORDecode_ProcessBigNumber(Item, (UsefulBuf){NULL, 200}, &ResultBigNum, &bIsNeg);
+      if(ResultBigNum.len != pTest->ExpectedBigNum.len) {
+         return MakeTestResultCode(uTestIndex, 5, uErr);
+      }
+
+      QCBORDecode_Init(&DCtx, pTest->Encoded, 0);
+      QCBORDecode_CompatibilityV1(&DCtx);
+      QCBORDecode_GetTBigNumber(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, BignumBuf,  &ResultBigNum, &bIsNeg);
+      uErr = QCBORDecode_GetError(&DCtx);
+      if(uErr != QCBOR_SUCCESS) {
+         return MakeTestResultCode(uTestIndex, 6, uErr);
+      }
+
+      if(UsefulBuf_Compare(ResultBigNum, pTest->ExpectedBigNum)) {
+         return MakeTestResultCode(uTestIndex, 7, 0);
+      }
+
+      if(bIsNeg != pTest->bExpectedSign) {
+         return MakeTestResultCode(uTestIndex, 8, 0);
+      }
+
+   }
+
+
 #else
 
    if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_TAGS_DISABLED) {
@@ -5224,6 +5445,7 @@
    IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5);
 
    QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DC);
 
    nResult = QCBORDecode_GetNext(&DC, &Item);
 
@@ -5786,6 +6008,7 @@
    uint8_t     uQCBORTypeGN;
    int64_t     nExponentGN;
    int64_t     nMantissaGN;
+   uint64_t    uMantissaGU;
    UsefulBufC  MantissaGN;
 
    /* Expected values for GetDecimalFraction */
@@ -5809,6 +6032,8 @@
    int64_t     nExponentGBFB;
    UsefulBufC  MantissaGBFB;
    bool        IsNegativeGBFB;
+
+   // TODO: add tests for Raw
 };
 
 
@@ -5824,27 +6049,27 @@
       QCBOR_TYPE_ARRAY,
       0,
       0,
+      0UL,
       {(const uint8_t []){0x00}, 1},
 
       QCBOR_SUCCESS, /* GetDecimalFraction */
       -1,
       3,
 
-      QCBOR_SUCCESS, /* for GetDecimalFractionBig */
+      QCBOR_SUCCESS, /* for GetTDecimalFractionBigMantissa */
       -1,
-      {(const uint8_t []){0x02}, 1},
+      {(const uint8_t []){0x03}, 1},
       false,
 
       QCBOR_SUCCESS, /* for GetBigFloat */
       -1,
       3,
 
-      QCBOR_SUCCESS, /* for GetBigFloatBig */
+      QCBOR_SUCCESS, /* for GetTBigFloatBigMantissa */
       -1,
-      {(const uint8_t []){0x02}, 1},
+      {(const uint8_t []){0x03}, 1},
       false
    },
-
    {
       "2. Untagged pair (big float or decimal fraction), tag required",
       {(const uint8_t []){0x82, 0x20, 0x03}, 3},
@@ -5855,13 +6080,14 @@
       QCBOR_TYPE_ARRAY,
       0,
       0,
+      0UL,
       {(const uint8_t []){0x00}, 1},
 
       QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */
+      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetTDecimalFractionBigMantissa */
       0,
       {(const uint8_t []){0x00}, 1},
       false,
@@ -5870,13 +6096,11 @@
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */
+      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetTBigFloatBigMantissa */
       0,
       {(const uint8_t []){0x00}, 1},
       false
-
    },
-
    {
       "3. Tagged 1.5 decimal fraction, tag 4 optional",
       {(const uint8_t []){0xC4, 0x82, 0x20, 0x03}, 4},
@@ -5887,6 +6111,7 @@
       QCBOR_TYPE_DECIMAL_FRACTION,
       -1,
       3,
+      0UL,
       {(const uint8_t []){0x00}, 1},
 
 
@@ -5894,16 +6119,16 @@
       -1,
       3,
 
-      QCBOR_SUCCESS, /* for GetDecimalFractionBig */
+      QCBOR_SUCCESS, /* for GetTDecimalFractionBigMantissa */
       -1,
-      {(const uint8_t []){0x02}, 1},
+      {(const uint8_t []){0x03}, 1},
       false,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloat */ // TODO: think about error code here
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTBigFloatBigMantissa */
       0,
       {(const uint8_t []){0x00}, 1},
       false
@@ -5918,14 +6143,14 @@
       QCBOR_TYPE_BIGFLOAT,
       300,
       100,
+      0UL,
       {(const uint8_t []){0x00}, 1},
 
-
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFraction */ // TODO: think about error code
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTDecimalFractionBigMantissa */ // TODO: think about error code
       0,
       {(const uint8_t []){0x02}, 1},
       false,
@@ -5934,12 +6159,11 @@
       300,
       100,
 
-      QCBOR_SUCCESS, /* for GetBigFloatBig */
+      QCBOR_SUCCESS, /* for GetTBigFloatBigMantissa */
       300,
-      {(const uint8_t []){0x63}, 1},
+      {(const uint8_t []){0x64}, 1},
       false
    },
-
    {
       "5. Tagged 4([-20, 4759477275222530853136]) decimal fraction, tag 4 required",
       {(const uint8_t []){0xC4, 0x82, 0x33,
@@ -5951,9 +6175,10 @@
       QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
       -20,
       0,
+      0UL,
       {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10},
 
-      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetDecimalFraction */
+      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetTDecimalFractionBigMantissa */
       0,
       0,
 
@@ -5966,12 +6191,11 @@
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */
+      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetTBigFloatBigMantissa */
       0,
       {(const uint8_t []){0x00}, 0},
       false
    },
-
    {
       "6. Error: Mantissa and exponent inside a Mantissa and exponent",
       {(const uint8_t []){0xC4, 0x82, 0x33,
@@ -5983,13 +6207,14 @@
       QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
       0,
       0,
+      0UL,
       {(const uint8_t []){0x00}, 0},
 
       QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFraction */
       0,
       0,
 
-      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFractionBig */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTDecimalFractionBigMantissa */
       0,
       {(const uint8_t []){0x00}, 0},
       false,
@@ -5998,7 +6223,7 @@
       0,
       0,
 
-      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloatBig */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTBigFloatBigMantissa */
       0,
       {(const uint8_t []){0x00}, 0},
       false
@@ -6014,13 +6239,14 @@
       QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
       -20,
       0,
+      0UL,
       {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4},
 
       QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */
+      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetTDecimalFractionBigMantissa */
       -20,
       {(const uint8_t []){0x00}, 1},
       false,
@@ -6029,12 +6255,11 @@
       -20,
       4294967295,
 
-      QCBOR_SUCCESS, /* for GetBigFloatBig */
+      QCBOR_SUCCESS, /* for GetTBigFloatBigMantissa */
       -20,
       {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4},
       false
    },
-
    {
       /* Special case for test 8. Don't renumber it. */
       "8. Untagged pair with big num (big float or decimal fraction), tag optional",
@@ -6046,18 +6271,19 @@
       QCBOR_TYPE_ARRAY,
       0,
       0,
+      0UL,
       {(const uint8_t []){0x00}, 1},
 
       QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */
       0,
       0,
 
-      QCBOR_SUCCESS, /* for GetDecimalFractionBig */
+      QCBOR_SUCCESS, /* for GetTDecimalFractionBigMantissa */
       -20,
       {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10},
       false,
 
-      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */
+      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetTBigFloatBigMantissa */
       0,
       0,
 
@@ -6066,7 +6292,6 @@
       {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10},
       false
    },
-
    {
       "9. decimal fraction with large exponent and negative big num mantissa",
       {(const uint8_t []){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -6078,6 +6303,7 @@
       QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
       9223372036854775807,
       0,
+      0UL,
       {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10},
 
       QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */
@@ -6086,18 +6312,114 @@
 
       QCBOR_SUCCESS, /* for GetDecimalFractionBig */
       9223372036854775807,
-      {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10},
+      {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x11}, 10},
       true,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloat */
       0,
       0,
 
-      QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTBigFloatBigMantissa */
       0,
       {(const uint8_t []){0x00}, 1},
       false
    },
+   {
+      "10. big float with large exponent and negative big num mantissa",
+      {(const uint8_t []){0xC5, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                                0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 23},
+      QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG,
+      true,
+
+      QCBOR_SUCCESS, /* for GetNext */
+      QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM,
+      9223372036854775807,
+      0,
+      0UL,
+      {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10},
+
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* GetDecimalFraction */
+      0,
+      0,
+
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTDecimalFractionBigMantissa */
+      0,
+      {(const uint8_t []){0x00}, 1},
+      false,
+
+      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetTBigFloatBigMantissa */
+      0,
+      0,
+
+      QCBOR_SUCCESS, /* for GetBigFloatBig */
+      9223372036854775807,
+      {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x11}, 10},
+      true
+   },
+   {
+      "11. big float with large exponent and negative big num mantissa",
+      {(const uint8_t []){0xC5, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                          0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 20},
+      QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG,
+      true,
+
+      QCBOR_SUCCESS, /* for GetNext */
+      QCBOR_TYPE_BIGFLOAT_NEG_U64,
+      9223372036854775807,
+      0,
+      0xffffffffffffffff,
+      {(const uint8_t []){0x00}, 0},
+
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* GetDecimalFraction */
+      0,
+      0,
+
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTDecimalFractionBigMantissa */
+      0,
+      {(const uint8_t []){0x00}, 1},
+      false,
+
+      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */
+      0,
+      0,
+
+      QCBOR_SUCCESS, /* for GetTBigFloatBigMantissa */
+      9223372036854775807,
+      {(const uint8_t []){0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 9},
+      true
+   },
+   {
+      "12. big float with large exponent and positive unsigned mantissa",
+      {(const uint8_t []){0xC5, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                          0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 20},
+      QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG,
+      true,
+
+      QCBOR_SUCCESS, /* for GetNext */
+      QCBOR_TYPE_BIGFLOAT_POS_U64,
+      9223372036854775807,
+      0,
+      0xffffffffffffffff,
+      {(const uint8_t []){0x00}, 0},
+
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* GetDecimalFraction */
+      0,
+      0,
+
+      QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetTDecimalFractionBigMantissa */
+      0,
+      {(const uint8_t []){0x00}, 1},
+      false,
+
+      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */
+      0,
+      0,
+
+      QCBOR_SUCCESS, /* for GetTBigFloatBigMantissa */
+      9223372036854775807,
+      {(const uint8_t []){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8},
+      false
+   }
 };
 
 
@@ -6115,13 +6437,14 @@
 
    for(uIndex = 0; uIndex < C_ARRAY_COUNT(pEaMTests, struct EaMTest); uIndex++) {
       const struct EaMTest *pT = &pEaMTests[uIndex];
-      /* Decode with GetNext */
-      QCBORDecode_Init(&DCtx, pT->Input, 0);
 
-      if(uIndex + 1 == 9) {
+      if(uIndex + 1 == 4) {
          nExponent = 99; // just to set a break point
       }
 
+      /* --- Decode with GetNext --- */
+      QCBORDecode_Init(&DCtx, pT->Input, 0);
+      QCBORDecode_CompatibilityV1(&DCtx);
       uError = QCBORDecode_GetNext(&DCtx, &Item);
 #ifdef QCBOR_DISABLE_TAGS
       /* Test 8 is a special case when tags are disabled */
@@ -6146,6 +6469,11 @@
                if(pT->nMantissaGN != Item.val.expAndMantissa.Mantissa.nInt) {
                    return (int32_t)(1+uIndex) * 1000 + 4;
                 }
+            } else if(Item.uDataType == QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64 || Item.uDataType == QCBOR_TYPE_BIGFLOAT_NEG_U64 ||
+                      Item.uDataType == QCBOR_TYPE_DECIMAL_FRACTION_POS_U64 || Item.uDataType == QCBOR_TYPE_BIGFLOAT_POS_U64) {
+               if(pT->uMantissaGU != Item.val.expAndMantissa.Mantissa.uInt) {
+                   return (int32_t)(1+uIndex) * 1000 + 4;
+                }
             } else {
                if(UsefulBuf_Compare(Item.val.expAndMantissa.Mantissa.bigNum, pT->MantissaGN)) {
                    return (int32_t)(1+uIndex) * 1000 + 5;
@@ -6156,12 +6484,13 @@
       }
 #endif
 
-      /* Decode with GetDecimalFraction */
+      /* --- Decode with GetDecimalFraction --- */
       QCBORDecode_Init(&DCtx, pT->Input, 0);
-      QCBORDecode_GetDecimalFraction(&DCtx,
-                                      pT->uTagRequirement,
-                                     &nMantissa,
-                                     &nExponent);
+      QCBORDecode_CompatibilityV1(&DCtx);
+      QCBORDecode_GetTDecimalFraction(&DCtx,
+                                       pT->uTagRequirement,
+                                      &nMantissa,
+                                      &nExponent);
       uError = QCBORDecode_GetAndResetError(&DCtx);
 #ifdef QCBOR_DISABLE_TAGS
       if(pT->bHasTags) {
@@ -6186,14 +6515,17 @@
       }
 #endif
 
-      /* Decode with GetDecimalFractionBig */
+ 
+
+      /* --- Decode with GetDecimalFractionBig ---v*/
       QCBORDecode_Init(&DCtx, pT->Input, 0);
-      QCBORDecode_GetDecimalFractionBig(&DCtx,
-                                 pT->uTagRequirement,
-                                 MantissaBuf,
-                                 &Mantissa,
-                                 &bMantissaIsNegative,
-                                 &nExponent);
+      QCBORDecode_CompatibilityV1(&DCtx);
+      QCBORDecode_GetTDecimalFractionBigMantissa(&DCtx,
+                                         pT->uTagRequirement,
+                                         MantissaBuf,
+                                        &Mantissa,
+                                        &bMantissaIsNegative,
+                                        &nExponent);
       uError = QCBORDecode_GetAndResetError(&DCtx);
 #ifdef QCBOR_DISABLE_TAGS
       if(pT->bHasTags) {
@@ -6221,9 +6553,11 @@
       }
 #endif
 
-      /* Decode with GetBigFloat */
+
+      /* --- Decode with GetBigFloat --- */
       QCBORDecode_Init(&DCtx, pT->Input, 0);
-      QCBORDecode_GetBigFloat(&DCtx,
+      QCBORDecode_CompatibilityV1(&DCtx);
+      QCBORDecode_GetTBigFloat(&DCtx,
                               pT->uTagRequirement,
                               &nMantissa,
                               &nExponent);
@@ -6251,9 +6585,12 @@
       }
 #endif
 
-      /* Decode with GetBigFloatBig */
+
+
+      /* --- Decode with GetBigFloatBig --- */
       QCBORDecode_Init(&DCtx, pT->Input, 0);
-      QCBORDecode_GetBigFloatBig(&DCtx,
+      QCBORDecode_CompatibilityV1(&DCtx);
+      QCBORDecode_GetTBigFloatBigMantissa(&DCtx,
                                  pT->uTagRequirement,
                                  MantissaBuf,
                                  &Mantissa,
@@ -6285,6 +6622,7 @@
 #ifdef QCBOR_DISABLE_TAGS
       }
 #endif
+
    }
 
    return 0;
@@ -6319,6 +6657,8 @@
 
 
    QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DC);
+
    uErr = QCBORDecode_GetNext(&DC, &item);
    if(uErr != QCBOR_SUCCESS) {
       return 100;
@@ -6375,16 +6715,6 @@
 
 
 static const struct DecodeFailTestInput ExponentAndMantissaFailures[] = {
-   { "Exponent > INT64_MAX",
-      QCBOR_DECODE_MODE_NORMAL,
-      {"\xC4\x82\x1B\x7f\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1B\x80\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 20},
-      QCBOR_ERR_BAD_EXP_AND_MANTISSA
-   },
-   { "Mantissa > INT64_MAX",
-      QCBOR_DECODE_MODE_NORMAL,
-      {"\xC4\x82\x1B\x80\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC3\x4A\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10", 23},
-      QCBOR_ERR_BAD_EXP_AND_MANTISSA
-   },
    {
       "End of input",
       QCBOR_DECODE_MODE_NORMAL,
@@ -6923,6 +7253,19 @@
 };
 
 
+/*
+ {1: 1(1), 2: 1(2(2)), 3: 1(2(3(3)))}
+
+ */
+static const uint8_t spMapWithNestedTags[] = {
+   0xA3,
+      0x01, 0xc1, 0x01,
+      0x02, 0xc1, 0xc2, 0x02,
+      0x03, 0xc1, 0xc2, 0xc3, 0x03,
+};
+
+
+
 static int32_t EnterMapCursorTest(void)
 {
    QCBORDecodeContext DCtx;
@@ -7003,6 +7346,38 @@
       }
    }
 
+   QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapWithNestedTags), 0);
+   QCBORDecode_EnterMap(&DCtx, NULL);
+
+#ifndef QCBOR_DISABLE_TAGS
+   // TODO: map/array items counts and tag numbers
+   QCBORDecode_SeekToLabelN(&DCtx, 1);
+   uint64_t uTagNumber;
+   QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uTagNumber != 1) {
+      return 9001;
+   }
+   uErr = QCBORDecode_GetNext(&DCtx, &Item1); // int 1
+   if(uErr != QCBOR_SUCCESS || Item1.val.int64 != 1) {
+      return 9002;
+   }
+
+
+   QCBORDecode_SeekToLabelN(&DCtx, 2);
+   QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uTagNumber != 1) {
+      return 9001;
+   }
+   QCBORDecode_GetNextTagNumber(&DCtx, &uTagNumber);
+   if(uTagNumber != 2) {
+      return 9001;
+   }
+   uErr = QCBORDecode_GetNext(&DCtx, &Item1); // int 2
+   if(uErr != QCBOR_SUCCESS || Item1.val.int64 != 2) {
+      return 9002;
+   }
+
+#endif /* ! QCBOR_DISABLE_TAGS */
    return 0;
 }
 
@@ -7219,6 +7594,8 @@
 
    int64_t nInt;
    QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spRecoverableMapErrors), 0);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    QCBORDecode_EnterMap(&DCtx, NULL);
 #ifndef QCBOR_DISABLE_TAGS
    QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt);
@@ -7233,12 +7610,6 @@
 #endif
 
 
-   QCBORDecode_GetInt64InMapN(&DCtx, 0x03, &nInt);
-   uErr = QCBORDecode_GetAndResetError(&DCtx);
-   if(uErr != QCBOR_ERR_INT_OVERFLOW) {
-      return 2023;
-   }
-
 #ifndef QCBOR_DISABLE_TAGS
    QCBORDecode_GetEpochDateInMapN(&DCtx, 0x04, QCBOR_TAG_REQUIREMENT_TAG, &nInt);
    uErr = QCBORDecode_GetAndResetError(&DCtx);
@@ -7459,8 +7830,7 @@
    },
    {
       "Decimal Fraction with positive bignum 257 * 10e3",
-      {(uint8_t[]){0xC4, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-                               0xC2, 0x42, 0x01, 0x01}, 15},
+      {(uint8_t[]){0xC4, 0x82, 0x03, 0xC2, 0x42, 0x01, 0x01}, 8},
       257000,
       EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS),
       257000,
@@ -7470,8 +7840,7 @@
    },
    {
       "bigfloat with negative bignum -258 * 2e3",
-      {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-                               0xC3, 0x42, 0x01, 0x01}, 15},
+      {(uint8_t[]){0xC5, 0x82, 0x03, 0xC3, 0x42, 0x01, 0x01}, 8},
       -2064,
       EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS),
       0,
@@ -7481,8 +7850,7 @@
    },
    {
       "bigfloat with positive bignum 257 * 2e3",
-      {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-                               0xC2, 0x42, 0x01, 0x01}, 15},
+      {(uint8_t[]){0xC5, 0x82, 0x03, 0xC2, 0x42, 0x01, 0x01}, 8},
       2056,
       EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS),
       2056,
@@ -7760,8 +8128,8 @@
       FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
    },
    {
-      "Negative integer -18446744073709551616",
-      {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9},
+      "Negative integer -9223372036854775808",
+      {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9},
       -9223372036854775807-1, // INT64_MIN
       QCBOR_SUCCESS,
       0ULL,
@@ -7770,6 +8138,16 @@
       FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
    },
    {
+      "Negative integer -18446744073709551616",
+      {(uint8_t[]){0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9},
+      0ULL,
+      QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
+      0ULL,
+      QCBOR_ERR_NUMBER_SIGN_CONVERSION,
+      -18446744073709551616.0,
+      FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
+   },
+   {
       "Double Floating point value 100.3",
       {(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9},
       100L,
@@ -7815,11 +8193,13 @@
 
 
 
-static int32_t SetUpDecoder(QCBORDecodeContext *DCtx, UsefulBufC CBOR, UsefulBuf Pool)
+static int32_t SetUpDecoder(QCBORDecodeContext *pDCtx, UsefulBufC CBOR, UsefulBuf Pool)
 {
-   QCBORDecode_Init(DCtx, CBOR, QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_Init(pDCtx, CBOR, QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(pDCtx);
+
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
-   if(QCBORDecode_SetMemPool(DCtx, Pool, 0)) {
+   if(QCBORDecode_SetMemPool(pDCtx, Pool, 0)) {
       return 1;
    }
 #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
@@ -7831,6 +8211,9 @@
 
 int32_t IntegerConvertTest(void)
 {
+   uint64_t uInt;
+
+
    const int nNumTests = C_ARRAY_COUNT(NumberConversions,
                                        struct NumberConversion);
 
@@ -7847,6 +8230,10 @@
          return (int32_t)(3333+nIndex);
       }
 
+      if(nIndex == 21) {
+         uInt = 99; // For break point only
+      }
+
       int64_t nInt;
       QCBORDecode_GetInt64ConvertAll(&DCtx, 0xffff, &nInt);
       if(QCBORDecode_GetError(&DCtx) != pF->uErrorInt64) {
@@ -7861,7 +8248,6 @@
          return (int32_t)(3333+nIndex);
       }
 
-      uint64_t uInt;
       QCBORDecode_GetUInt64ConvertAll(&DCtx, 0xffff, &uInt);
       if(QCBORDecode_GetError(&DCtx) != pF->uErrorUint64) {
          return (int32_t)(4000+nIndex);
@@ -8531,6 +8917,7 @@
    QCBORError         uErr;
 
    QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedTypes), 0);
+   QCBORDecode_CompatibilityV1(&DC);
 
    UsefulBufC String;
    bool       bNeg;
@@ -8849,6 +9236,7 @@
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapWithIndefLenStrings),
                     QCBOR_DECODE_MODE_NORMAL);
+   QCBORDecode_CompatibilityV1(&DCtx);
 
    UsefulBuf_MAKE_STACK_UB(StringBuf, 200);
    QCBORDecode_SetMemPool(&DCtx, StringBuf, false);
@@ -9819,7 +10207,12 @@
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedSimples),
                     0);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    QCBORDecode_GetBool(&DCtx, &b);
+   if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) {
+      return 410;
+   }   
    if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 22) {
       return 401;
    }
@@ -9849,6 +10242,668 @@
 }
 
 
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+#define PREFERRED_ERR    QCBOR_ERR_PREFERRED_CONFORMANCE
+#define DCBOR_FLOAT_ERR  QCBOR_ERR_DCBOR_CONFORMANCE
+#define HALF_FLOAT_ERR   QCBOR_ERR_DCBOR_CONFORMANCE
+#else
+#define PREFERRED_ERR    QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE
+#define DCBOR_FLOAT_ERR  QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE
+#define HALF_FLOAT_ERR   QCBOR_ERR_HALF_PRECISION_DISABLED
+#endif
+#else
+#define PREFERRED_ERR    QCBOR_ERR_ALL_FLOAT_DISABLED
+#define DCBOR_FLOAT_ERR  QCBOR_ERR_ALL_FLOAT_DISABLED
+#define HALF_FLOAT_ERR   QCBOR_ERR_ALL_FLOAT_DISABLED
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
+
+
+/* These are all well-formed and valid CBOR, but fail
+ * conformance with preferred, CDE or dCBOR.
+ */
+static const struct DecodeFailTestInput DecodeConformanceFailures[] = {
+   /* --- Major type 0 and 1 not shortest-form --- */
+   { "zero encoded in 2 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x18\x00", 2},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "23 encoded in 2 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x18\x17", 2},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "255 encoded in 3 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x19\x00\xff", 3},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "65535 encoded in 5 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x1a\x00\x00\xff\xff", 5},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "4294967295 encoded in 9 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x1b\x00\x00\x00\x00\xff\xff\xff\xff", 9},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "-24 encoded in 2 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x38\x17", 2},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "-256 encoded in 3 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x39\x00\xff", 3},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "-65536 encoded in 5 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x3a\x00\x00\xff\xff", 5},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "-4294967296 encoded in 9 bytes",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\x3b\x00\x00\x00\x00\xff\xff\xff\xff", 9},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   /* TODO: what to do about this test?
+    { "65-bit negative not allowed in dCBOR",
+    QCBOR_DECODE_MODE_DCBOR,
+    {"\x3b\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+    QCBOR_ERR_DCBOR_CONFORMANCE
+    },*/
+
+   /* --- Simple values not allowed in dCBOR --- */
+   { "undefined not allowed in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xf7", 1},
+      QCBOR_ERR_DCBOR_CONFORMANCE
+   },
+   { "Simple value 0 not allowed in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xe0", 1},
+      QCBOR_ERR_DCBOR_CONFORMANCE
+   },
+   { "Simple value 19 not allowed in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xf3", 1},
+      QCBOR_ERR_DCBOR_CONFORMANCE
+   },
+   { "Simple value 32 not allowed in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xF8\x20", 2},
+      QCBOR_ERR_DCBOR_CONFORMANCE
+   },
+   { "Simple value 255 not allowed in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xF8\xff", 2},
+      QCBOR_ERR_DCBOR_CONFORMANCE
+   },
+
+   /* --- Floats not in shortest-form --- */
+   { "1.5 single should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfa\x3f\xc0\x00\x00", 5},
+      PREFERRED_ERR
+   },
+   { "1.5 double should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfb\x3f\xf8\x00\x00\x00\x00\x00\x00", 9},
+      PREFERRED_ERR
+   },
+   { "8388607.0 double should be single",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xFB\x41\x5F\xFF\xFF\xC0\x00\x00\x00", 9},
+      PREFERRED_ERR
+   },
+   { "3.0517578125E-5 double should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9},
+      PREFERRED_ERR
+   },
+   { "255.875 single should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfa\x43\x7f\xe0\x00", 5},
+      PREFERRED_ERR
+   },
+   { "INFINITY single should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfa\x7f\x80\x00\x00", 5},
+      PREFERRED_ERR
+   },
+   { "INFINITY double should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfb\x7f\xf0\x00\x00\x00\x00\x00\x00", 9},
+      PREFERRED_ERR
+   },
+   { "-INFINITY single should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfa\xff\x80\x00\x00", 5},
+      PREFERRED_ERR
+   },
+   { "-INFINITY double should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfb\xff\xf0\x00\x00\x00\x00\x00\x00", 9},
+      PREFERRED_ERR
+   },
+   { "NAN single should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfa\x7f\xc0\x00\x00", 5},
+      PREFERRED_ERR
+   },
+   { "NAN double should be half",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00", 9},
+      PREFERRED_ERR
+   },
+   { "NAN half with payload (signaling)",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xf9\x7e\x01", 3},
+      HALF_FLOAT_ERR
+   },
+   { "NAN single with payload (signaling)",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xfa\x7f\xc0\x00\x01", 5},
+      DCBOR_FLOAT_ERR
+   },
+   { "NAN double with payload (signaling)",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xfb\x7f\xf8\x00\x00\x00\x00\x00\x01", 9},
+      DCBOR_FLOAT_ERR
+   },
+   { "NAN half with some payload",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xf9\x7e\x80", 3},
+      HALF_FLOAT_ERR
+   },
+   { "NAN single with some payload",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xfa\x7f\xc4\x00\x00", 5},
+      DCBOR_FLOAT_ERR
+   },
+   { "NAN double with some payload",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xfb\x7f\xf8\x01\x01\x00\x00\x00\x00", 9},
+      DCBOR_FLOAT_ERR
+   },
+
+   /* --- Floats that should be integers --- */
+   { "0 half not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xf9\x00\x00", 3},
+      HALF_FLOAT_ERR
+   },
+   { "0 double not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xfb\x00\x00\x00\x00\x00\x00\x00\x00", 9},
+      DCBOR_FLOAT_ERR
+   },
+   { "-0 half not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xf9\x80\x00", 3},
+      HALF_FLOAT_ERR
+   },
+   { "18446744073709550000 double not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+      DCBOR_FLOAT_ERR
+   },
+   { "4294967295 double not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
+      DCBOR_FLOAT_ERR
+   },
+   { "65535 single not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xFA\x47\x7F\xFF\x00", 5},
+      DCBOR_FLOAT_ERR
+   },
+   { "255 half not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xF9\x5C\x00", 3},
+      HALF_FLOAT_ERR
+   },
+   { "-1 half not an integer in dCBOR",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xF9\xBC\x00", 3},
+      HALF_FLOAT_ERR
+   },
+
+   /* --- Various non-shortest-form CBOR arguments ---*/
+   { "byte string length not-shortest form",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\x59\x00\x01\x99", 4},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "array length not-shortest form",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\x9a\x00\x00\x00\x02\x05\x06", 7},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "tag number not shortest-form",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xd9\x00\xff\x00", 4},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+#if !defined(QCBOR_DISABLE_TAGS) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+   { "tag number on lable not shortest-form",
+      QCBOR_DECODE_MODE_PREFERRED,
+      {"\xA3\xC1\x00\x61\x61\xD8\x01\x00\x61\x62\xD9\x00\x01\x00\x61\x63", 16},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+#endif
+
+   /* --- Indefinite lengths --- */
+   { "indefinite-length byte string",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\x5f\x62\x68\x69\xff", 5},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "indefinite-length text string",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\x7f\x62\x68\x69\xff", 5},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "indefinite-length array",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\x9f\xff", 2},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+   { "indefinite-length map",
+      QCBOR_DECODE_MODE_DCBOR,
+      {"\xbf\xff", 2},
+      QCBOR_ERR_PREFERRED_CONFORMANCE
+   },
+
+   /* --- Unsorted maps --- */
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+   { "simple unsorted map with text labels",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xa2\x61\x62\x00\x61\x61\x01", 7},
+      QCBOR_ERR_UNSORTED
+   },
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+   { "reverse sorted map with integer labels",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xa5\x19\x03\xE8\xf6\x18\x64\xf6\x00\xf6\x29\xf6\x3A\x00\x01\x86\x9f\xf6", 18},
+      QCBOR_ERR_UNSORTED
+   },
+   {"map with out-of-order labels that are arrays",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xA3\x83\x00\x01\x02\x61\x63\x83\x00\x01\x00\x61\x61\x83\x00\x01\x01\x61\x62", 19},
+      QCBOR_ERR_MAP_LABEL_TYPE
+   },
+#if !defined(QCBOR_DISABLE_TAGS) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+   { "unsorted map with labels of all types including arrays and maps",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xA8\x80\x07\xC1\x18\x58\x02\x64\x74\x65\x78\x74\x03\x01\x01\xA0\x04"
+         "\x42\x78\x78\x05\xF5\x06\xFB\x40\x21\x8A\x3D\x70\xA3\xD7\x0A\x07", 33},
+      QCBOR_ERR_MAP_LABEL_TYPE
+   },
+   { "unsorted map with labels of all non-aggregate types",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xA6\xC1\x18\x58\x02\x64\x74\x65\x78\x74\x03\x01\x01"
+         "\x42\x78\x78\x05\xF5\x06\xFB\x40\x21\x8A\x3D\x70\xA3\xD7\x0A\x07", 29},
+      QCBOR_ERR_UNSORTED
+   },
+   {"map with out-of-order labels that have tags",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xA3\xC1\x18\x63\x61\x61\xD9\x07\xD0\x18\x63\x61\x63\xD8\x30\x18\x63\x61\x62", 19},
+      QCBOR_ERR_UNSORTED
+   },
+#endif
+
+   /* --- Maps with dup labels --- */
+   { "simple map with dup integer labels",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xa2\x00\x00\x00\x00", 5},
+      QCBOR_ERR_DUPLICATE_LABEL
+   },
+   {"map with dup map labels",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xA3\xA1\x03\x03\x61\x61\xA1\x02\x02\x61\x62\xA1\x03\x03\x61\x63", 16},
+      QCBOR_ERR_MAP_LABEL_TYPE
+   },
+
+   /* --- Maps with bad labels --- */
+   { "map with invalid label",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xa1\x1c\x01", 3},
+      QCBOR_ERR_UNSUPPORTED
+   },
+
+   { "map with array label with invalid parts",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xa1\x81\x1c\x01", 4},
+      QCBOR_ERR_MAP_LABEL_TYPE
+   },
+
+   { "map with map label with non-preferred part",
+      QCBOR_DECODE_MODE_CDE,
+      {"\xa1\xa1\x19\x00\x00\x01\x02", 7},
+      QCBOR_ERR_MAP_LABEL_TYPE
+   }};
+
+
+static UsefulBufC CorrectlySorted[] = {
+   /* This one is correctly sorted, but is not correct preferred serialization. QCBOR checks
+    * the sort order of the map without checking the preferred serialization of the
+    * map items, so this test passes. */
+   {"\xa4\x01\x61\x61\xf9\x3C\x00\x61\x62\xFA\x3F\x80\x00\x00\x61\x63\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00\x61\x64", 27},
+   {"\xa3\x00\x61\x61\x01\x61\x62\xa3\x0c\x61\x78\x0b\x61\x79\x0a\x61\x7a\x61\x63", 19},
+   {"\xA3\xE0\x61\x61\xF5\x61\x62\xFB\x3F\xF1\x99\x99\x99\x99\x99\x9A\x61\x63", 18},
+   {"\xa2\x00\x00\x01\x01", 5},
+   {"\xA0", 1},
+   NULLUsefulBufC
+};
+
+
+
+int32_t 
+DecodeConformanceTests(void)
+{
+   QCBORDecodeContext DCtx;
+   QCBORItem          Item;
+   QCBORError         uErr;
+   uint32_t           uTestIndex;
+
+   for(uTestIndex = 0; UsefulBuf_IsNULLC(CorrectlySorted[uTestIndex]); uTestIndex++) {
+      QCBORDecode_Init(&DCtx, CorrectlySorted[uTestIndex], QCBOR_DECODE_MODE_CDE);
+
+      uErr = QCBORDecode_GetNext(&DCtx, &Item);
+      if(uErr != QCBOR_SUCCESS) {
+         return MakeTestResultCode(1, uTestIndex, uErr);
+      }
+   }
+
+   /* Make sure EnterMap is handling errors */
+   QCBORDecode_Init(&DCtx,UsefulBuf_FROM_SZ_LITERAL("\xa2\x00\x00\x00\x00"), QCBOR_DECODE_MODE_CDE);
+   QCBORDecode_EnterMap(&DCtx, &Item);
+   if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_DUPLICATE_LABEL) {
+      return -5000;
+   }
+
+   return ProcessDecodeFailures(DecodeConformanceFailures,
+                                C_ARRAY_COUNT(DecodeConformanceFailures, struct DecodeFailTestInput));
+
+}
+
+
+
+
+
+#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+
+struct PreciseNumberConversion {
+   char       *szDescription;
+   UsefulBufC  CBOR;
+   QCBORError  uError;
+   uint8_t     qcborType;
+   struct {
+      int64_t  int64;
+      uint64_t uint64;
+      double   d;
+   } number;
+};
+
+
+static const struct PreciseNumberConversion PreciseNumberConversions[] = {
+   {
+      "-0.00",
+      {"\xf9\x80\x00", 3},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {0, 0, 0}
+   },
+   {
+      "NaN",
+      {"\xf9\x7e\x00", 3},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, NAN}
+   },
+   {
+      "NaN payload",
+      {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, NAN}
+   },
+   {
+      "65536.0 single",
+      {"\xFA\x47\x80\x00\x00", 5},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {65536, 0, 0}
+   },
+   {
+      "Infinity",
+      {"\xf9\x7c\x00", 3},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, INFINITY}
+   },
+   {
+      "1.0",
+      {"\xf9\x3c\x00", 3},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {1, 0, 0}
+   },
+   {
+      "UINT64_MAX",
+      {"\x1B\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_UINT64,
+      {0, UINT64_MAX, 0}
+   },
+   {
+      "Largest float that is also representable as int64_t",
+      {"\x3B\x7f\xff\xff\xff\xff\xff\xfb\xff", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {-9223372036854774784, 0, 0}
+   },
+   {
+      "-9223372036854775807",
+      {"\x3B\x7f\xff\xff\xff\xff\xff\xff\xfe", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {-9223372036854775807, 0, 0}
+   },
+   {
+      "Largest representable in int64_t (INT64_MIN)",
+      {"\x3B\x7f\xff\xff\xff\xff\xff\xff\xff", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {INT64_MIN, 0, 0}
+   },
+   {
+      "-9223372036854775809 First encoded as 65-bit neg",
+      {"\x3B\x80\x00\x00\x00\x00\x00\x00\x00", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_65BIT_NEG_INT,
+      {0, 0, 0}
+   },
+
+   {
+      "-9223372036854777856 First float not representable as int64_t",
+      {"\x3B\x80\x00\x00\x00\x00\x00\x07\xFF", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, -9223372036854777856.0}
+   },
+
+   {
+      "18446742974197923840",
+      {"\xFB\x43\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_UINT64,
+      {0, 18446742974197923840ULL, 0}
+   },
+
+   {
+      "-18446744073709547522 65-bit neg lots of precision",
+      {"\x3B\xff\xff\xff\xff\xff\xff\xef\xff", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, -18446744073709547522.0}
+   },
+
+   {
+      "-18446744073709549568 Next to largest float encodable as 65-bit neg",
+      {"\x3B\xff\xff\xff\xff\xff\xff\xf7\xff", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, -18446744073709549568.0}
+   },
+
+   {
+      "-18446744073709551616 Largest possible encoded 65-bit neg",
+      {"\x3B\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, -18446744073709551616.0}
+   },
+   {
+      "-18446744073709551617 First value representable only as a tag 3 big num",
+      {"\xC3\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+#ifndef QCBOR_DISABLE_TAGS
+      QCBOR_ERR_UNEXPECTED_TYPE,
+#else
+      QCBOR_ERR_TAGS_DISABLED,
+#endif /* ! QCBOR_DISABLE_TAGS */
+      QCBOR_TYPE_NONE,
+      {0, 0, -0}
+   },
+   {
+      "-18446744073709555712 First whole integer that must be encoded as float in DCBOR",
+      {"\xFB\xC3\xF0\x00\x00\x00\x00\x00\x01", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, -18446744073709555712.0}
+   },
+   
+   {
+      "65-bit neg very precise",
+      {"\x3B\xff\xff\xff\xff\xff\xff\xf8\x00", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_65BIT_NEG_INT,
+      {0, 18446744073709549568ULL, 0.0}
+   },
+   {
+      "65-bit neg too precise",
+      {"\x3B\xff\xff\xff\xff\xff\xff\xfc\x00", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_65BIT_NEG_INT,
+      {0, 18446744073709550592ULL, 0.0}
+   },
+   {
+      "65-bit neg, power of two",
+      {"\x3B\x80\x00\x00\x00\x00\x00\x00\x00", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_65BIT_NEG_INT,
+      {0, 9223372036854775808ULL, 0.0}
+   },
+   {
+      "Zero",
+      {"\x00", 1},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_INT64,
+      {0, 0, 0}
+   },
+   {
+      "Pi",
+      {"\xFB\x40\x09\x2A\xDB\x40\x2D\x16\xB9", 9},
+      QCBOR_SUCCESS,
+      QCBOR_TYPE_DOUBLE,
+      {0, 0, 3.145926}
+   },
+   {
+      "String",
+      {"\x60", 1},
+      QCBOR_ERR_UNEXPECTED_TYPE,
+      QCBOR_TYPE_NONE,
+      {0, 0, 0}
+   }
+};
+
+
+int32_t
+PreciseNumbersDecodeTest(void)
+{
+   unsigned           uTestIndex;
+   unsigned           uTestCount;
+   QCBORError         uErr;
+   QCBORItem          Item;
+   QCBORDecodeContext DCtx;
+   const struct PreciseNumberConversion *pTest;
+
+   uTestCount = C_ARRAY_COUNT(PreciseNumberConversions, struct PreciseNumberConversion);
+   for(uTestIndex = 0; uTestIndex < uTestCount; uTestIndex++) {
+      pTest = &PreciseNumberConversions[uTestIndex];
+
+      if(uTestIndex == 16) {
+         uErr = 99; // For break point only
+      }
+
+      QCBORDecode_Init(&DCtx, pTest->CBOR, 0);
+      QCBORDecode_CompatibilityV1(&DCtx);
+
+      QCBORDecode_GetNumberConvertPrecisely(&DCtx, &Item);
+
+      uErr = QCBORDecode_GetError(&DCtx);
+
+      if(uErr != pTest->uError) {
+         return MakeTestResultCode(uTestIndex, 1, uErr);
+      }
+
+      if(pTest->qcborType != Item.uDataType) {
+         return MakeTestResultCode(uTestIndex, 2, 0);
+      }
+
+      if(pTest->qcborType == QCBOR_TYPE_NONE) {
+         continue;
+      }
+
+      switch(pTest->qcborType) {
+         case QCBOR_TYPE_INT64:
+            if(Item.val.int64 != pTest->number.int64) {
+               return MakeTestResultCode(uTestIndex, 3, 0);
+            }
+            break;
+
+         case QCBOR_TYPE_UINT64:
+         case QCBOR_TYPE_NEGBIGNUM:
+            if(Item.val.uint64 != pTest->number.uint64) {
+               return MakeTestResultCode(uTestIndex, 4, 0);
+            }
+            break;
+
+         case QCBOR_TYPE_DOUBLE:
+            if(isnan(pTest->number.d)) {
+               if(!isnan(Item.val.dfnum)) {
+                  return MakeTestResultCode(uTestIndex, 5, 0);
+               }
+            } else {
+               if(Item.val.dfnum != pTest->number.d) {
+                  return MakeTestResultCode(uTestIndex, 6, 0);
+               }
+            }
+            break;
+      }
+   }
+   return 0;
+}
+
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+
+
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
 static const uint8_t spExpectedArray2s[] = {
    0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
@@ -10001,6 +11056,8 @@
 #ifndef QCBOR_DISABLE_TAGS
    UsefulBufC ExpMant = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpMant);
    QCBORDecode_Init(&DCtx, ExpMant, 0);
+   QCBORDecode_CompatibilityV1(&DCtx);
+
    QCBORDecode_EnterArray(&DCtx, NULL);
    QCBORDecode_EnterArray(&DCtx, NULL);
    QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR);
@@ -10010,9 +11067,6 @@
    if(Item.uDataType != QCBOR_TYPE_ARRAY) {
       return 201;
    }
-   if(!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION)) {
-      return 202;
-   }
    if(Item.val.uCount != 2) {
       return 201;
    }
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index a08a3af..37d061e 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -1,6 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2018-2024, Laurence Lundblade.
  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -179,13 +179,13 @@
 /*
   Test decode of CBOR tagging like the CBOR magic number and many others.
  */
-int32_t OptTagParseTest(void);
+int32_t TagNumberDecodeTest(void);
 
 
 /*
  Parse some big numbers, positive and negative
  */
-int32_t BignumParseTest(void);
+int32_t BignumDecodeTest(void);
 
 
 /*
@@ -319,6 +319,12 @@
 int32_t CBORTestIssue134(void);
 
 
+/*
+ * Test the decode checking features for dCBOR, CDE and preferred.
+ */
+int32_t DecodeConformanceTests(void);
+
+int32_t PreciseNumbersDecodeTest(void);
 
 int32_t ErrorHandlingTests(void);
 
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 14bcc63..67bf459 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -48,7 +48,7 @@
 
  */
 
-//#define PRINT_FUNCTIONS_FOR_DEBUGGING
+#define PRINT_FUNCTIONS_FOR_DEBUGGING
 
 #ifdef  PRINT_FUNCTIONS_FOR_DEBUGGING
 #include <stdio.h>
@@ -96,13 +96,9 @@
 #endif
 
 
-#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
 /*
  Returns 0 if UsefulBufs are equal
  Returns 1000000 + offeset if they are not equal.
-
-
-
 */
 struct UBCompareDiagnostic {
    uint8_t uActual;
@@ -130,7 +126,18 @@
    return 0;
 
 }
-#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
+
+
+static inline int32_t
+MakeTestResultCode(uint32_t   uTestCase,
+                   uint32_t   uTestNumber,
+                   QCBORError uErrorCode)
+{
+   uint32_t uCode = (uTestCase * 1000000) +
+                    (uTestNumber * 1000) +
+                    (uint32_t)uErrorCode;
+   return (int32_t)uCode;
+}
 
 
 // One big buffer that is used by all the tests to encode into
@@ -286,7 +293,8 @@
 }
 
 
-
+/* Don't change this, make a new test instead. Keep this
+ * as it was in v1 for full regression. */
 static const uint8_t spExpectedEncodedAll[] = {
  0x98, 0x23, 0x66, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x32, 0xd8,
  0x64, 0x1a, 0x05, 0x5d, 0x23, 0x15, 0x65, 0x49, 0x4e, 0x54,
@@ -498,7 +506,6 @@
  0x00, 0x00
 };
 
-
 static const char *szMIME = "\
 MIME-Version: 1.0\n\
 Content-Type: multipart/mixed;\n\
@@ -531,12 +538,12 @@
    /* Some ints that are tagged and have strings preceeding them
     * (not labels becase it is not a map) */
    QCBOREncode_AddSZString(pECtx, "UINT62");
-   QCBOREncode_AddTag(pECtx, 100);
+   QCBOREncode_AddTagNumber(pECtx, 100);
    QCBOREncode_AddUInt64(pECtx, 89989909);
    QCBOREncode_AddSZString(pECtx, "INT64");
-   QCBOREncode_AddTag(pECtx, 76);
+   QCBOREncode_AddTagNumber(pECtx, 76);
    QCBOREncode_AddInt64(pECtx, 77689989909);
-   QCBOREncode_AddUInt64(pECtx,0);
+   QCBOREncode_AddUInt64(pECtx, 0);
    QCBOREncode_AddInt64(pECtx, -44);
 
    /* ints that go in maps */
@@ -563,7 +570,7 @@
    /* binary blobs in maps */
    QCBOREncode_OpenMap(pECtx);
    QCBOREncode_AddSZString(pECtx, "binbin");
-   QCBOREncode_AddTag(pECtx, 100000);
+   QCBOREncode_AddTagNumber(pECtx, 100000);
    QCBOREncode_AddBytes(pECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1}));
    QCBOREncode_AddBytesToMap(pECtx, "empty", NULLUsefulBufC); // Empty string
    QCBOREncode_AddBytesToMapSZ(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3}));
@@ -615,7 +622,7 @@
    QCBOREncode_AddUndef(pECtx);
    QCBOREncode_OpenMap(pECtx);
    QCBOREncode_AddSZString(pECtx, "dare");
-   QCBOREncode_AddTag(pECtx, 66);
+   QCBOREncode_AddTagNumber(pECtx, 66);
    QCBOREncode_AddBool(pECtx, true);
    QCBOREncode_AddBoolToMap(pECtx, "uu", false);
    QCBOREncode_AddNULLToMapN(pECtx, 737634);
@@ -628,7 +635,7 @@
    /* opening arrays in a map */
    QCBOREncode_OpenMap(pECtx);
    QCBOREncode_AddSZString(pECtx, "label and tagged empty array");
-   QCBOREncode_AddTag(pECtx, 1093);
+   QCBOREncode_AddTagNumber(pECtx, 1093);
    QCBOREncode_OpenArray(pECtx);
    QCBOREncode_CloseArray(pECtx);
    QCBOREncode_OpenArrayInMap(pECtx, "alabl");
@@ -642,7 +649,7 @@
    QCBOREncode_OpenMapInMap(pECtx, "in a map");
    QCBOREncode_OpenMapInMapN(pECtx, 5556);
    QCBOREncode_AddSZString(pECtx, "in a in a in a");
-   QCBOREncode_AddTag(pECtx, 9087);
+   QCBOREncode_AddTagNumber(pECtx, 9087);
    QCBOREncode_OpenMap(pECtx);
    QCBOREncode_CloseMap(pECtx);
    QCBOREncode_CloseMap(pECtx);
@@ -685,6 +692,7 @@
    QCBOREncode_AddBoolToMapN(pECtx, 010101, true);
    QCBOREncode_CloseMap(pECtx);
 
+
    /* Big numbers */
    static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum);
@@ -706,13 +714,18 @@
    /* Improvement: 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;
+   UsefulBufC         Enc;
+   size_t             size;
+   int                nReturn;
+   QCBORError         uExpectedErr;
+
+   nReturn = 0;
 
    QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_Allow(&ECtx, QCBOR_ENCODE_ALLOW_ALL);
 
-   AddAll (&ECtx);
+   AddAll(&ECtx);
 
-   UsefulBufC Enc;
    if(QCBOREncode_Finish(&ECtx, &Enc)) {
       nReturn = -1;
       goto Done;
@@ -720,15 +733,16 @@
 
    if(CheckResults(Enc, spExpectedEncodedAll)) {
       nReturn = -2;
+      goto Done;
    }
 
 
    /* Also test size calculation */
    QCBOREncode_Init(&ECtx, SizeCalculateUsefulBuf);
+   QCBOREncode_Allow(&ECtx, QCBOR_ENCODE_ALLOW_ALL);
 
-   AddAll (&ECtx);
+   AddAll(&ECtx);
 
-   size_t size;
    if(QCBOREncode_FinishGetSize(&ECtx, &size)) {
       nReturn = -10;
       goto Done;
@@ -736,8 +750,54 @@
 
    if(size != sizeof(spExpectedEncodedAll)) {
       nReturn = -11;
+      goto Done;
    }
 
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   uExpectedErr = QCBOR_ERR_NOT_ALLOWED;
+#else
+   uExpectedErr = QCBOR_SUCCESS;
+#endif
+
+
+#if !defined(QCBOR_DISABLE_ENCODE_USAGE_GUARDS) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+   uExpectedErr = QCBOR_ERR_NOT_ALLOWED;
+#else
+   uExpectedErr = QCBOR_SUCCESS;
+#endif
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+   QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   /* 0x7ff8000000000001ULL is a NaN with a payload. */
+   QCBOREncode_AddDouble(&ECtx, UsefulBufUtil_CopyUint64ToDouble(0x7ff8000000000001ULL));
+   if(QCBOREncode_Finish(&ECtx, &Enc) != uExpectedErr) {
+      nReturn = -22;
+      goto Done;
+   }
+
+
+   /* 0x7ffc000000000000ULL is a NaN with a payload. */
+   QCBOREncode_AddDouble(&ECtx, UsefulBufUtil_CopyUint64ToDouble(0x7ff8000000000001ULL));
+   if(QCBOREncode_Finish(&ECtx, &Enc) != uExpectedErr) {
+      nReturn = -23;
+      goto Done;
+   }
+
+   /* 0x7ff80001UL is a NaN with a payload. */
+   QCBOREncode_AddFloat(&ECtx, UsefulBufUtil_CopyUint32ToFloat(0x7ff80001UL));
+   if(QCBOREncode_Finish(&ECtx, &Enc) != uExpectedErr) {
+      nReturn = -24;
+      goto Done;
+   }
+
+   /* 0x7ffc0000UL is a NaN with a payload. */
+   QCBOREncode_AddFloat(&ECtx, UsefulBufUtil_CopyUint32ToFloat(0x7ffc0000UL));
+   if(QCBOREncode_Finish(&ECtx, &Enc) != uExpectedErr) {
+      nReturn = -25;
+      goto Done;
+   }
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
+
 Done:
    return nReturn;
 }
@@ -899,6 +959,130 @@
    return(nReturn);
 }
 
+struct BigNumEncodeTest {
+   const char *szDescription;
+   UsefulBufC  BigNum;
+   /* Expect all to succeed; no special error codes needed */
+   UsefulBufC  PositiveNoPreferred;
+   UsefulBufC  PositivePreferred;
+   UsefulBufC  NegativeNoPreferred;
+   UsefulBufC  NegativePreferred;
+};
+
+struct BigNumEncodeTest BigNumEncodeTestCases[] = {
+   {
+      "2^96 -1 or 79228162514264337593543950335 pos and neg with leading zeros",
+      {"\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 15},
+      {"\xC2\x4C\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 14},
+      {"\xC2\x4C\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 14},
+      {"\xC3\x4C\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe", 14},
+      {"\xC3\x4C\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe", 14},
+   },
+
+   {
+      "2^64+1 or 18446744073709551617 pos and neg)",
+      {"\x01\x00\x00\x00\x00\x00\x00\x00\x01", 9},
+      {"\xC2\x49\x01\x00\x00\x00\x00\x00\x00\x00\x01", 11},
+      {"\xC2\x49\x01\x00\x00\x00\x00\x00\x00\x00\x01", 11},
+      {"\xC3\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+      {"\xC3\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+   },
+   {
+      "2^64 or 18446744073709551616 pos and neg)",
+      {"\x01\x00\x00\x00\x0000\x00\x00\x00", 9},
+      {"\xC2\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+      {"\xC2\x49\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+      {"\xC3\x48\xff\xff\xff\xff\xff\xff\xff\xff", 10},
+      {"\x3B\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+   },
+   {
+      "2^64 - 1 or 18446744073709551615 pos and neg",
+      {"\xff\xff\xff\xff\xff\xff\xff\xff", 8},
+      {"\xC2\x48\xff\xff\xff\xff\xff\xff\xff\xff", 10},
+      {"\x1B\xff\xff\xff\xff\xff\xff\xff\xff", 9},
+      {"\xC3\x48\xff\xff\xff\xff\xff\xff\xff\xfe", 10},
+      {"\x3B\xff\xff\xff\xff\xff\xff\xff\xfe", 9},
+   },
+   {
+      "1 and -1",
+      {"\x01", 1},
+      {"\xC2\x41\x01", 3},
+      {"\x01", 1},
+      {"\xC3\x41\x00", 3},
+      {"\x20", 1},
+   },
+   {
+      "0 and error for no negative 0",
+      {"\x00", 1},
+      {"\xC2\x41\x00", 3},
+      {"\x00", 1},
+      NULLUsefulBufC,
+      NULLUsefulBufC,
+   },
+   {
+      "leading zeros -- 0 and error for no negative 0",
+      {"\x00\x00\x00\x00", 4},
+      {"\xC2\x41\x00", 3},
+      {"\x00", 1},
+      NULLUsefulBufC,
+      NULLUsefulBufC,
+   }
+
+};
+
+
+int32_t BigNumEncodeTests(void)
+{
+   unsigned           uTestIndex;
+   unsigned           uTestCount;
+   QCBOREncodeContext Enc;
+   UsefulBufC         EncodedBigNumber;
+
+   uTestCount = (int)C_ARRAY_COUNT(BigNumEncodeTestCases, struct BigNumEncodeTest);
+
+   for(uTestIndex = 0; uTestIndex < uTestCount; uTestIndex++) {
+      const struct BigNumEncodeTest *pTest = &BigNumEncodeTestCases[uTestIndex];
+
+      if(uTestIndex == 6) {
+         EncodedBigNumber.len = 0; /* Line of code so a break point can be set. */
+      }
+
+      QCBOREncode_Init(&Enc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+      QCBOREncode_AddTBigNumberNoPreferred(&Enc, QCBOR_ENCODE_AS_TAG, false, pTest->BigNum);
+      QCBOREncode_Finish(&Enc, &EncodedBigNumber);
+      if(UsefulBuf_Compare(EncodedBigNumber, pTest->PositiveNoPreferred)) {
+         return MakeTestResultCode(uTestIndex, 1, QCBOR_SUCCESS);
+      }
+
+      QCBOREncode_Init(&Enc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+      QCBOREncode_AddTBigNumber(&Enc, QCBOR_ENCODE_AS_TAG, false, pTest->BigNum);
+      QCBOREncode_Finish(&Enc, &EncodedBigNumber);
+      if(UsefulBuf_Compare(EncodedBigNumber, pTest->PositivePreferred)) {
+         return MakeTestResultCode(uTestIndex, 2, QCBOR_SUCCESS);
+      }
+
+      if(!UsefulBuf_IsNULLC(pTest->NegativeNoPreferred)){
+         QCBOREncode_Init(&Enc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+         QCBOREncode_AddTBigNumberNoPreferred(&Enc, QCBOR_ENCODE_AS_TAG, true, pTest->BigNum);
+         QCBOREncode_Finish(&Enc, &EncodedBigNumber);
+         if(UsefulBuf_Compare(EncodedBigNumber, pTest->NegativeNoPreferred)) {
+            return MakeTestResultCode(uTestIndex, 3, QCBOR_SUCCESS);
+         }
+      }
+
+      if(!UsefulBuf_IsNULLC(pTest->NegativePreferred)){
+         QCBOREncode_Init(&Enc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+         QCBOREncode_AddTBigNumber(&Enc, QCBOR_ENCODE_AS_TAG, true, pTest->BigNum);
+         QCBOREncode_Finish(&Enc, &EncodedBigNumber);
+         if(UsefulBuf_Compare(EncodedBigNumber, pTest->NegativePreferred)) {
+            return MakeTestResultCode(uTestIndex, 4, QCBOR_SUCCESS);
+         }
+      }
+   }
+
+   return 0;
+}
+
 
 /*
  85                  # array(5)
@@ -1803,12 +1987,6 @@
 */
 static const uint8_t spExpectedBstrWrap[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2};
 
-/*
- 81   #array(1)
- 0x58  0x25  # string of length 37 (length of "This is longer than twenty four bytes")
- */
-static const uint8_t spExpectedTypeAndLen[] = {0x81, 0x58, 0x25};
-
 static const uint8_t spExpectedForBstrWrapCancel[] = {0x82, 0x19, 0x01, 0xC3, 0x18, 0x2A};
 
 /*
@@ -1858,19 +2036,6 @@
       return -5;
    }
 
-   // Third, test QCBOREncode_AddBytesLenOnly() here as it is part of the
-   // bstr wrapping use cases.
-   UsefulBuf_MAKE_STACK_UB(StuffBuf, 50);
-   QCBOREncode_Init(&EC, StuffBuf);
-   QCBOREncode_OpenArray(&EC);
-   QCBOREncode_AddBytesLenOnly(&EC, UsefulBuf_FROM_SZ_LITERAL("This is longer than twenty four bytes"));
-   QCBOREncode_CloseArray(&EC);
-   if(QCBOREncode_Finish(&EC, &Encoded)) {
-      return -6;
-   }
-   if(CheckResults(Encoded, spExpectedTypeAndLen)) {
-      return -7;
-   }
 
    // Fourth test, cancelling a byte string
    QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
@@ -2803,6 +2968,7 @@
 
 
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
+
 /*
    [
       4([-1, 3]),
@@ -2817,7 +2983,8 @@
       5([-9223372036854775808, -4759477275222530853137])]
    ]
  */
-static const uint8_t spExpectedExponentAndMantissaArray[] = {
+static const uint8_t spExpectedExponentAndMantissaArrayv1[] = {
+
    0x8A, 0xC4, 0x82, 0x20, 0x03, 0x82, 0x20, 0x04,
    0xC4, 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x82,
@@ -2826,6 +2993,7 @@
    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
    0x07, 0x08, 0x09, 0x10, 0xC5, 0x82, 0x19, 0x01,
+
    0x2C, 0x18, 0x64, 0x82, 0x19, 0x02, 0x58, 0x18,
    0xC8, 0xC5, 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02,
    0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
@@ -2851,7 +3019,7 @@
     800: 5([-9223372036854775808, -4759477275222530853137])
   }
  */
-static const uint8_t spExpectedExponentAndMantissaMap[] = {
+static const uint8_t spExpectedExponentAndMantissaMapv1[] = {
    0xAC, 0x70, 0x64, 0x65, 0x63, 0x69, 0x6D, 0x61,
    0x6C, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69,
    0x6F, 0x6E, 0xC4, 0x82, 0x20, 0x03, 0x19, 0x01,
@@ -2899,7 +3067,81 @@
 };
 
 
-int32_t ExponentAndMantissaEncodeTests(void)
+struct EAMEncodeTest {
+   const char *szDescription;
+   int64_t     nExponent;
+   UsefulBufC  BigNumMantissa;
+   int64_t     nMantissa;
+   bool        bSign;
+   bool        bv1Mode;
+   enum {EAM_Any, EAM_Pref, EAM_CDE} eSerialization;
+   // TODO: add tag requirement
+
+   /* Only testing successes (right?) */
+   UsefulBufC  BigFloat;
+   UsefulBufC  DecFrac;
+   UsefulBufC  BigFloatBig;
+   UsefulBufC  DecFracBig;
+};
+
+struct EAMEncodeTest EET[] = {
+   { "basic",
+      -1,
+      NULLUsefulBufC,
+      3,
+      false,
+      false,
+      EAM_Pref,
+
+      {"\xC5\x82\x20\x03", 4},
+      {"\xC4\x82\x20\x03", 4},
+      NULLUsefulBufC,
+      NULLUsefulBufC
+   },
+
+   { "bignum gets preferred",
+      -1,
+      {"\x00\x03",2},
+      0,
+      false,
+      false,
+      EAM_Pref,
+
+      NULLUsefulBufC,
+      NULLUsefulBufC,
+      {"\xC5\x82\x20\x03", 4},
+      {"\xC4\x82\x20\x03", 4},
+   }
+
+   // TODO: add more test cases, including converting some of the already-existing
+};
+
+
+
+static void
+EAMTestSetup(const struct EAMEncodeTest *pTest, QCBOREncodeContext *pEnc)
+{
+   QCBOREncode_Init(pEnc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   if(pTest->bv1Mode) {
+      QCBOREncode_Setv1Compatibility(pEnc);
+   }
+
+   switch(pTest->eSerialization) {
+      case EAM_Pref:
+         QCBOREncode_SerializationPreferred(pEnc);
+         break;
+      case EAM_CDE:
+         QCBOREncode_SerializationCDE(pEnc);
+         break;
+
+      default:
+         break;
+   }
+}
+
+
+/* Test QCBOR v1 compatible functions */
+int32_t ExponentAndMantissaEncodeTestsv1(void)
 {
    QCBOREncodeContext EC;
    UsefulBufC         EncodedExponentAndMantissa;
@@ -2927,9 +3169,11 @@
       return -2;
    }
 
+   struct UBCompareDiagnostic Foo;
+
    int nReturn = UsefulBuf_CompareWithDiagnostic(EncodedExponentAndMantissa,
-                                                 UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentAndMantissaArray),
-                                                 NULL);
+                                                 UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentAndMantissaArrayv1),
+                                                 &Foo);
    if(nReturn) {
       return nReturn;
    }
@@ -3007,7 +3251,7 @@
    struct UBCompareDiagnostic Diag;
 
    nReturn = UsefulBuf_CompareWithDiagnostic(EncodedExponentAndMantissa,
-                                             UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentAndMantissaMap),
+                                             UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentAndMantissaMapv1),
                                              &Diag);
    if(nReturn) {
       return nReturn + 1000000; // +1000000 to distinguish from first test above
@@ -3016,6 +3260,84 @@
    return 0;
 }
 
+
+
+int32_t
+ExponentAndMantissaEncodeTests(void)
+{
+   QCBOREncodeContext EC;
+   UsefulBufC         EncodedExponentAndMantissa;
+   int                nIndex;
+   QCBORError         uErr;
+
+   int32_t uReturn = ExponentAndMantissaEncodeTestsv1();
+   if(uReturn) {
+      return uReturn;
+   }
+
+   const int nNumberOfTests = C_ARRAY_COUNT(EET, struct EAMEncodeTest);
+
+   for(nIndex = 0; nIndex < nNumberOfTests; nIndex++) {
+      struct EAMEncodeTest *pTest = &EET[nIndex];
+
+
+      if(UsefulBuf_IsNULLC(pTest->BigNumMantissa)) {
+         EAMTestSetup(pTest, &EC);
+
+         QCBOREncode_AddDecimalFraction(&EC, pTest->nMantissa, pTest->nExponent);
+         uErr = QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa);
+         if(uErr) {
+            return MakeTestResultCode((uint32_t)nIndex, 1, uErr);
+         }
+
+         if(UsefulBuf_Compare(EncodedExponentAndMantissa, pTest->DecFrac)) {
+            return MakeTestResultCode((uint32_t)nIndex, 2, 0);
+         }
+
+         EAMTestSetup(pTest, &EC);
+         QCBOREncode_AddBigFloat(&EC, pTest->nMantissa, pTest->nExponent);
+         uErr = QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa);
+         if(uErr) {
+            return MakeTestResultCode((uint32_t)nIndex, 11, uErr);
+         }
+
+         if(UsefulBuf_Compare(EncodedExponentAndMantissa, pTest->BigFloat)) {
+            return MakeTestResultCode((uint32_t)nIndex, 12, 0);
+         }
+
+      } else {
+         EAMTestSetup(pTest, &EC);
+
+         //QCBOREncode_AddDecimalFractionBigNum(&EC, pTest->BigNumMantissa, pTest->bSign, pTest->nExponent);
+         QCBOREncode_AddTDecimalFractionBigMantissa(&EC, QCBOR_ENCODE_AS_TAG, pTest->BigNumMantissa, pTest->bSign, pTest->nExponent);
+         uErr = QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa);
+         if(uErr) {
+            return MakeTestResultCode((uint32_t)nIndex, 11, uErr);
+         }
+
+         if(UsefulBuf_Compare(EncodedExponentAndMantissa, pTest->DecFracBig)) {
+            return MakeTestResultCode((uint32_t)nIndex, 12, 0);
+         }
+
+         EAMTestSetup(pTest, &EC);
+
+         //QCBOREncode_AddBigFloatBigNum(&EC, pTest->BigNumMantissa, pTest->bSign, pTest->nExponent);
+         QCBOREncode_AddTBigFloatBigMantissa(&EC, QCBOR_ENCODE_AS_TAG, pTest->BigNumMantissa, pTest->bSign, pTest->nExponent);
+         uErr = QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa);
+         if(uErr) {
+            return MakeTestResultCode((uint32_t)nIndex, 11, uErr);
+         }
+
+         if(UsefulBuf_Compare(EncodedExponentAndMantissa, pTest->BigFloatBig)) {
+            return MakeTestResultCode((uint32_t)nIndex, 12, 0);
+         }
+      }
+   }
+
+   return 0;
+}
+
+
 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
 
 
@@ -3217,6 +3539,573 @@
 }
 
 
+
+int32_t
+SortMapTest(void)
+{
+   UsefulBuf_MAKE_STACK_UB(   TestBuf,  200);
+   QCBOREncodeContext         EC;
+   UsefulBufC                 EncodedAndSorted;
+   QCBORError                 uErr;
+   struct UBCompareDiagnostic CompareDiagnostics;
+
+
+   /* --- Basic sort test case --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMapN(&EC, 3, 3);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_AddInt64ToMapN(&EC, 4, 4);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 11;
+   }
+
+   static const uint8_t spBasic[] = {
+      0xA4, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04};
+
+   if(UsefulBuf_Compare(EncodedAndSorted, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBasic))) {
+      return 12;
+   }
+
+   /* --- Empty map sort test case --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 21;
+   }
+
+   static const uint8_t spEmpty[] = {0xA0};
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmpty),
+                                      &CompareDiagnostics)) {
+      return 22;
+   }
+
+   /* --- Several levels of nested sorted maps ---  */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+     QCBOREncode_AddInt64ToMap(&EC, "three", 3);
+     QCBOREncode_OpenMapInMapN(&EC, 428);
+       QCBOREncode_AddNULLToMap(&EC, "null");
+       QCBOREncode_OpenArrayInMap(&EC, "array");
+         QCBOREncode_AddSZString(&EC, "hi");
+         QCBOREncode_AddSZString(&EC, "there");
+         QCBOREncode_CloseArray(&EC);
+       QCBOREncode_OpenMapInMap(&EC, "empty2");
+         QCBOREncode_CloseAndSortMap(&EC);
+       QCBOREncode_OpenMapInMap(&EC, "empty1");
+         QCBOREncode_CloseAndSortMap(&EC);
+       QCBOREncode_CloseAndSortMap(&EC);
+     QCBOREncode_AddDateEpochToMapN(&EC, 88, 888888);
+     QCBOREncode_AddBoolToMap(&EC, "boo", true);
+     QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 31;
+   }
+
+   /* Correctly sorted.
+    * {
+    *   88: 1(888888),
+    *   428: {
+    *     "null": null,
+    *     "array": [
+    *       "hi",
+    *       "there"
+    *     ],
+    *     "empty1": {},
+    *     "empty2": {}
+    *   },
+    *   "boo": true,
+    *   "three": 3
+    *  }
+    */
+   static const uint8_t spSorted[] = {
+      0xA4, 0x18, 0x58, 0xC1, 0x1A, 0x00, 0x0D, 0x90,
+      0x38, 0x19, 0x01, 0xAC, 0xA4, 0x64, 0x6E, 0x75,
+      0x6C, 0x6C, 0xF6, 0x65, 0x61, 0x72, 0x72, 0x61,
+      0x79, 0x82, 0x62, 0x68, 0x69, 0x65, 0x74, 0x68,
+      0x65, 0x72, 0x65, 0x66, 0x65, 0x6D, 0x70, 0x74,
+      0x79, 0x31, 0xA0, 0x66, 0x65, 0x6D, 0x70, 0x74,
+      0x79, 0x32, 0xA0, 0x63, 0x62, 0x6F, 0x6F, 0xF5,
+      0x65, 0x74, 0x68, 0x72, 0x65, 0x65, 0x03};
+
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSorted),
+                                      &CompareDiagnostics)) {
+      return 32;
+   }
+
+
+   /* Same data items, but added in a different order */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+     QCBOREncode_AddInt64ToMap(&EC, "three", 3);
+     QCBOREncode_OpenMapInMapN(&EC, 428);
+       QCBOREncode_OpenMapInMap(&EC, "empty1");
+         QCBOREncode_CloseAndSortMap(&EC);
+       QCBOREncode_OpenArrayInMap(&EC, "array");
+         QCBOREncode_AddSZString(&EC, "hi");
+         QCBOREncode_AddSZString(&EC, "there");
+         QCBOREncode_CloseArray(&EC);
+       QCBOREncode_OpenMapInMap(&EC, "empty2");
+         QCBOREncode_CloseAndSortMap(&EC);
+       QCBOREncode_AddNULLToMap(&EC, "null");
+       QCBOREncode_CloseAndSortMap(&EC);
+     QCBOREncode_AddDateEpochToMapN(&EC, 88, 888888);
+     QCBOREncode_AddBoolToMap(&EC, "boo", true);
+     QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 31;
+   }
+
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSorted),
+                                      &CompareDiagnostics)) {
+      return 32;
+   }
+
+   /* Same data items, but added in a different order */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+     QCBOREncode_AddBoolToMap(&EC, "boo", true);
+     QCBOREncode_OpenMapInMapN(&EC, 428);
+       QCBOREncode_OpenMapInMap(&EC, "empty1");
+         QCBOREncode_CloseAndSortMap(&EC);
+       QCBOREncode_OpenArrayInMap(&EC, "array");
+         QCBOREncode_AddSZString(&EC, "hi");
+         QCBOREncode_AddSZString(&EC, "there");
+         QCBOREncode_CloseArray(&EC);
+       QCBOREncode_OpenMapInMap(&EC, "empty2");
+         QCBOREncode_CloseAndSortMap(&EC);
+       QCBOREncode_AddNULLToMap(&EC, "null");
+       QCBOREncode_CloseAndSortMap(&EC);
+     QCBOREncode_AddDateEpochToMapN(&EC, 88, 888888);
+     QCBOREncode_AddInt64ToMap(&EC, "three", 3);
+     QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 31;
+   }
+
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSorted),
+                                      &CompareDiagnostics)) {
+      return 32;
+   }
+
+
+
+   /* --- Degenerate case of everything in order --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_AddInt64ToMap(&EC, "a", 3);
+   QCBOREncode_AddInt64ToMap(&EC, "b", 4);
+   QCBOREncode_AddInt64ToMap(&EC, "aa", 5);
+   QCBOREncode_AddInt64ToMap(&EC, "aaa", 6);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 41;
+   }
+
+   static const uint8_t sp6Items[] = {
+      0xA7, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x61,
+      0x61, 0x03, 0x61, 0x62, 0x04, 0x62, 0x61, 0x61,
+      0x05, 0x63, 0x61, 0x61, 0x61, 0x06};
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sp6Items),
+                                      &CompareDiagnostics)) {
+      return 42;
+   }
+
+   /* --- Degenerate case -- reverse order --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMap(&EC, "aaa", 6);
+   QCBOREncode_AddInt64ToMap(&EC, "aa", 5);
+   QCBOREncode_AddInt64ToMap(&EC, "b", 4);
+   QCBOREncode_AddInt64ToMap(&EC, "a", 3);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 51;
+   }
+
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sp6Items),
+                                      &CompareDiagnostics)) {
+      return 52;
+   }
+
+   /* --- Same items, randomly out of order --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMap(&EC, "aa", 5);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+   QCBOREncode_AddInt64ToMap(&EC, "b", 4);
+   QCBOREncode_AddInt64ToMap(&EC, "aaa", 6);
+   QCBOREncode_AddInt64ToMap(&EC, "a", 3);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 61;
+   }
+
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sp6Items),
+                                      &CompareDiagnostics)) {
+      return 62;
+   }
+
+   /* --- Stuff in front of and after array to sort --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenArray(&EC);
+   QCBOREncode_AddInt64(&EC, 111);
+   QCBOREncode_AddInt64(&EC, 222);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_CloseAndSortMap(&EC);
+   QCBOREncode_AddInt64(&EC, 888);
+   QCBOREncode_AddInt64(&EC, 999);
+   QCBOREncode_CloseArray(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 71;
+   }
+
+   static const uint8_t spPreItems[] = {
+      0x85, 0x18, 0x6F, 0x18, 0xDE, 0xA3, 0x00, 0x00,
+      0x01, 0x01, 0x02, 0x02, 0x19, 0x03, 0x78, 0x19,
+      0x03, 0xE7};
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spPreItems),
+                                      &CompareDiagnostics)) {
+      return 72;
+   }
+
+   /* --- map with labels of all CBOR major types and in reverse order --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+
+   /* Adding labels directly rather than AddToMap functions */
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+   QCBOREncode_AddDouble(&EC, 8.77);
+   QCBOREncode_AddInt64(&EC, 7);
+#endif /* QCBOR_DISABLE_ALL_FLOAT */
+
+   QCBOREncode_AddBool(&EC, true);
+   QCBOREncode_AddInt64(&EC, 6);
+
+   QCBOREncode_AddDateEpoch(&EC, 88);
+   QCBOREncode_AddInt64(&EC, 5);
+
+   QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\xa0"));
+   QCBOREncode_AddInt64(&EC, 4);
+
+   QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\x80"));
+   QCBOREncode_AddInt64(&EC, 7);
+
+   QCBOREncode_AddInt64ToMap(&EC, "text", 3);
+
+   QCBOREncode_AddBytes(&EC, UsefulBuf_FromSZ("xx"));
+   QCBOREncode_AddInt64(&EC, 2);
+
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1); /* Integer */
+   QCBOREncode_CloseAndSortMap(&EC);
+
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 81;
+   }
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+   static const uint8_t spLabelTypes[] = {
+      0xA8, 0x01, 0x01, 0x42, 0x78, 0x78, 0x02, 0x64,
+      0x74, 0x65, 0x78, 0x74, 0x03, 0x80, 0x07, 0xA0,
+      0x04, 0xC1, 0x18, 0x58, 0x05, 0xF5, 0x06, 0xFB,
+      0x40, 0x21, 0x8A, 0x3D, 0x70, 0xA3, 0xD7, 0x0A,
+      0x07};
+#else
+   static const uint8_t spLabelTypes[] = {
+      0xA7, 0x01, 0x01, 0x42, 0x78, 0x78, 0x02, 0x64,
+      0x74, 0x65, 0x78, 0x74, 0x03, 0x80, 0x07, 0xA0,
+      0x04, 0xC1, 0x18, 0x58, 0x05, 0xF5, 0x06};
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
+
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLabelTypes),
+                                      &CompareDiagnostics)) {
+      return 82;
+   }
+
+   /* --- labels are indefinitely encoded ---  */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+
+   QCBOREncode_AddInt64ToMap(&EC, "aaaa", 1);
+
+   QCBOREncode_AddInt64ToMap(&EC, "bb", 2);
+
+   QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\x7f\x61" "a" "\x61" "a" "\xff"));
+   QCBOREncode_AddInt64(&EC, 3);
+
+   QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\x7f" "\x61" "c" "\xff"));
+   QCBOREncode_AddInt64(&EC, 4);
+
+   QCBOREncode_CloseAndSortMap(&EC);
+
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 91;
+   }
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   static const uint8_t spIndefItems[] = {
+      0xA4, 0x62, 0x62, 0x62, 0x02, 0x64, 0x61, 0x61,
+      0x61, 0x61, 0x01, 0x7F, 0x61, 0x61, 0x61, 0x61,
+      0xFF, 0x03, 0x7F, 0x61, 0x63, 0xFF, 0x04};
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                       UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefItems),
+                                       &CompareDiagnostics)) {
+       return 92;
+   }
+
+   /* --- Indefinitely encoded maps --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMapIndefiniteLength(&EC);
+
+   QCBOREncode_OpenMapIndefiniteLengthInMap(&EC, "aa");
+   QCBOREncode_CloseMapIndefiniteLength(&EC);
+
+   QCBOREncode_OpenArrayIndefiniteLengthInMap(&EC, "ff");
+   QCBOREncode_CloseArrayIndefiniteLength(&EC);
+
+   QCBOREncode_OpenMapIndefiniteLengthInMap(&EC, "zz");
+   QCBOREncode_CloseMapIndefiniteLength(&EC);
+
+   QCBOREncode_OpenMapIndefiniteLengthInMap(&EC, "bb");
+   QCBOREncode_CloseMapIndefiniteLength(&EC);
+
+   QCBOREncode_CloseAndSortMapIndef(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr) {
+      return 101;
+   }
+
+   static const uint8_t spIndeMaps[] = {
+      0xBF, 0x62, 0x61, 0x61, 0xBF, 0xFF, 0x62, 0x62,
+      0x62, 0xBF, 0xFF, 0x62, 0x66, 0x66, 0x9F, 0xFF,
+      0x62, 0x7A, 0x7A, 0xBF, 0xFF, 0xFF, 0x06, 0xFB};
+   if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+                                      UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndeMaps),
+                                      &CompareDiagnostics)) {
+      return 102;
+   }
+#endif
+
+   /* --- Duplicate label test  --- */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMapN(&EC, 3, 3);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr != QCBOR_ERR_DUPLICATE_LABEL) {
+      return 114;
+   }
+
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMapN(&EC, 3, 3);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+   QCBOREncode_AddInt64ToMapN(&EC, 1, 2);
+   QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr != QCBOR_ERR_DUPLICATE_LABEL) {
+      return 115;
+   }
+
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddInt64ToMap(&EC, "abc", 3);
+   QCBOREncode_AddInt64ToMap(&EC, "def", 1);
+   QCBOREncode_AddInt64ToMap(&EC, "def", 1);
+   QCBOREncode_AddInt64ToMap(&EC, "def", 2);
+   QCBOREncode_CloseAndSortMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+   if(uErr != QCBOR_ERR_DUPLICATE_LABEL) {
+      return 116;
+   }
+
+   return 0;
+}
+
+
+#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+
+#include <math.h> /* For INFINITY and NAN and isnan() */
+
+
+/* Public function. See qcbor_encode_tests.h */
+int32_t CDETest(void)
+{
+   QCBOREncodeContext EC;
+   UsefulBufC         Encoded;
+   QCBORError         uExpectedErr;
+
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_SerializationCDE(&EC);
+
+   /* Items added to test sorting and preferred encoding of numbers and floats */
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddFloatToMap(&EC, "k", 1.0f);
+   QCBOREncode_AddInt64ToMap(&EC, "a", 1);
+   QCBOREncode_AddDoubleToMap(&EC, "x", 2.0);
+   QCBOREncode_AddDoubleToMap(&EC, "r", 3.4028234663852886E+38);
+   QCBOREncode_AddDoubleToMap(&EC, "b", NAN);
+   QCBOREncode_AddUndefToMap(&EC, "t"); /* Test because dCBOR disallows */
+
+   QCBOREncode_CloseMap(&EC);
+
+   uExpectedErr = QCBOREncode_Finish(&EC, &Encoded);
+   if(uExpectedErr != QCBOR_SUCCESS) {
+      return 2;
+   }
+
+   static const uint8_t spExpectedCDE[] = {
+      0xA6, 0x61, 0x61, 0x01, 0x61, 0x62, 0xF9, 0x7E,
+      0x00, 0x61, 0x6B, 0xF9, 0x3C, 0x00, 0x61, 0x72,
+      0xFA, 0x7F, 0x7F, 0xFF, 0xFF, 0x61, 0x74, 0xF7,
+      0x61, 0x78, 0xF9, 0x40, 0x00};
+
+   if(UsefulBuf_Compare(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedCDE),
+                        Encoded)) {
+      return 1;
+   }
+
+
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   uExpectedErr = QCBOR_ERR_NOT_PREFERRED;
+#else
+   uExpectedErr = QCBOR_SUCCESS;
+#endif
+
+#ifndef  QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   /* Next, make sure methods that encode non-CDE error out */
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_SerializationCDE(&EC);
+   QCBOREncode_OpenMapIndefiniteLength(&EC);
+   QCBOREncode_CloseMap(&EC);
+   if(QCBOREncode_GetErrorState(&EC) != uExpectedErr) {
+      return 100;
+   }
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   return 0;
+}
+
+/* Public function. See qcbor_encode_tests.h */
+int32_t DCBORTest(void)
+{
+   QCBOREncodeContext EC;
+   UsefulBufC         Encoded;
+   QCBORError         uExpectedErr;
+
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+
+   QCBOREncode_SerializationdCBOR(&EC);
+
+   /* Items added to test sorting and preferred encoding of numbers and floats */
+   QCBOREncode_OpenMap(&EC);
+   QCBOREncode_AddFloatToMap(&EC, "k", 1.0f);
+   QCBOREncode_AddInt64ToMap(&EC, "a", 1);
+   QCBOREncode_AddDoubleToMap(&EC, "x", 2.0);
+   QCBOREncode_AddDoubleToMap(&EC, "r", 3.4028234663852886E+38);
+   QCBOREncode_AddDoubleToMap(&EC, "d1", -18446744073709549568.0);
+   QCBOREncode_AddDoubleToMap(&EC, "d2", -18446744073709551616.0);
+   QCBOREncode_AddDoubleToMap(&EC, "d3", -18446744073709555712.0);
+   QCBOREncode_AddDoubleToMap(&EC, "b", NAN);
+
+   QCBOREncode_CloseMap(&EC);
+
+   QCBOREncode_Finish(&EC, &Encoded);
+
+   static const uint8_t spExpecteddCBOR[] = {
+      0xA8, 0x61, 0x61, 0x01, 0x61, 0x62, 0xF9, 0x7E, 0x00, 0x61, 0x6B, 0x01, 0x61, 0x72, 0xFA, 0x7F, 0x7F, 0xFF, 0xFF, 0x61, 0x78, 0x02, 0x62, 0x64, 0x31, 0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x62, 0x64, 0x32, 0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x64, 0x33, 0xFB, 0xC3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+   if(UsefulBuf_Compare(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpecteddCBOR),
+                        Encoded)) {
+      return 1;
+   }
+
+
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   uExpectedErr = QCBOR_ERR_NOT_PREFERRED;
+#else
+   uExpectedErr = QCBOR_SUCCESS;
+#endif
+
+   /* Next, make sure methods that encode of non-CDE error out */
+
+#ifndef  QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+   /* Indefinite-length map */
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_SerializationdCBOR(&EC);
+   QCBOREncode_OpenMapIndefiniteLength(&EC);
+   QCBOREncode_CloseMap(&EC);
+   if(QCBOREncode_GetErrorState(&EC) != uExpectedErr) {
+      return 100;
+   }
+
+   /* Indefinite-length array */
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_SerializationdCBOR(&EC);
+   QCBOREncode_OpenArrayIndefiniteLength(&EC);
+   QCBOREncode_CloseMap(&EC);
+   if(QCBOREncode_GetErrorState(&EC) != uExpectedErr) {
+      return 101;
+   }
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   /* The "undef" special value */
+   QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_SerializationdCBOR(&EC);
+   QCBOREncode_AddUndef(&EC);
+   QCBOREncode_CloseMap(&EC);
+   if(QCBOREncode_GetErrorState(&EC) != uExpectedErr) {
+      return 102;
+   }
+
+
+   /* Improvement: when indefinite length string encoding is supported
+    * test it here too. */
+
+   return 0;
+
+}
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
 int32_t SubStringTest(void)
 {
    QCBOREncodeContext EC;
diff --git a/test/qcbor_encode_tests.h b/test/qcbor_encode_tests.h
index bc47c55..cb9f00f 100644
--- a/test/qcbor_encode_tests.h
+++ b/test/qcbor_encode_tests.h
@@ -1,6 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2022, Laurence Lundblade.
+ Copyright (c) 2018-2024, Laurence Lundblade.
  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -94,9 +94,9 @@
 
 
 /*
- Encodes a goodly number of floats and doubles and checks encoding is right
+ * Big number encoding tests.
  */
-int32_t FloatValuesTest1(void);
+int32_t BigNumEncodeTests(void);
 
 
 /*
@@ -191,6 +191,19 @@
 int32_t OpenCloseBytesTest(void);
 
 
+/* Test map sorting */
+int32_t SortMapTest(void);
+
+#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+
+/* Test CBOR Deterministic Encoding */
+int32_t CDETest(void);
+
+/* Test "dCBOR" mode */
+int32_t DCBORTest(void);
+
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
 int32_t SubStringTest(void);
 
 
diff --git a/test/run_tests.c b/test/run_tests.c
index cf806e9..578c34c 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -61,106 +61,124 @@
     TEST_ENTRY(UBMacroConversionsTest),
     TEST_ENTRY(UBUtilTests),
     TEST_ENTRY(UIBTest_IntegerFormat),
-    TEST_ENTRY(UBAdvanceTest)
+    TEST_ENTRY(UBAdvanceTest),
+    TEST_ENTRY(UOBExtraTests)
 };
 
 
 static test_entry s_tests[] = {
+   TEST_ENTRY(BigNumEncodeTests),
+#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
+   TEST_ENTRY(DecodeConformanceTests),
+#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
+   TEST_ENTRY(ErrorHandlingTests),
+   TEST_ENTRY(OpenCloseBytesTest),
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-    TEST_ENTRY(GetMapAndArrayTest),
-    TEST_ENTRY(TellTests),
-    TEST_ENTRY(ParseMapAsArrayTest),
+   TEST_ENTRY(GetMapAndArrayTest),
+   TEST_ENTRY(TellTests),
+   TEST_ENTRY(ParseMapAsArrayTest),
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   TEST_ENTRY(ArrayNestingTest3),
+#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
    TEST_ENTRY(SpiffyDateDecodeTest),
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-    TEST_ENTRY(ErrorHandlingTests),
-    TEST_ENTRY(OpenCloseBytesTest),
-    TEST_ENTRY(EnterBstrTest),
-    TEST_ENTRY(IntegerConvertTest),
-    TEST_ENTRY(EnterMapTest),
-    TEST_ENTRY(QCBORHeadTest),
-    TEST_ENTRY(EmptyMapsAndArraysTest),
-    TEST_ENTRY(NotWellFormedTests),
+   TEST_ENTRY(EnterBstrTest),
+   TEST_ENTRY(IntegerConvertTest),
+   TEST_ENTRY(EnterMapTest),
+   TEST_ENTRY(QCBORHeadTest),
+   TEST_ENTRY(EmptyMapsAndArraysTest),
+   TEST_ENTRY(NotWellFormedTests),
+
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
-    TEST_ENTRY(IndefiniteLengthNestTest),
-    TEST_ENTRY(IndefiniteLengthArrayMapTest),
-    TEST_ENTRY(NestedMapTestIndefLen),
-#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
-    TEST_ENTRY(SimpleValueDecodeTests),
-    TEST_ENTRY(DecodeFailureTests),
-    TEST_ENTRY(EncodeRawTest),
-    TEST_ENTRY(RTICResultsTest),
-    TEST_ENTRY(MapEncodeTest),
-    TEST_ENTRY(ArrayNestingTest1),
-    TEST_ENTRY(ArrayNestingTest2),
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
-    TEST_ENTRY(ArrayNestingTest3),
-#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
-    TEST_ENTRY(EncodeDateTest),
-    TEST_ENTRY(SimpleValuesTest1),
-    TEST_ENTRY(IntegerValuesTest1),
-    TEST_ENTRY(AllAddMethodsTest),
-    TEST_ENTRY(ParseTooDeepArrayTest),
-    TEST_ENTRY(ComprehensiveInputTest),
+   TEST_ENTRY(IndefiniteLengthNestTest),
+   TEST_ENTRY(IndefiniteLengthArrayMapTest),
+   TEST_ENTRY(NestedMapTestIndefLen),
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+   TEST_ENTRY(SimpleValueDecodeTests),
+   TEST_ENTRY(DecodeFailureTests),
+   TEST_ENTRY(EncodeRawTest),
+   TEST_ENTRY(RTICResultsTest),
+   TEST_ENTRY(MapEncodeTest),
+   TEST_ENTRY(ArrayNestingTest1),
+   TEST_ENTRY(ArrayNestingTest2),
+   TEST_ENTRY(EncodeDateTest),
+   TEST_ENTRY(SimpleValuesTest1),
+   TEST_ENTRY(IntegerValuesTest1),
+   TEST_ENTRY(AllAddMethodsTest),
+   TEST_ENTRY(ParseTooDeepArrayTest),
+   TEST_ENTRY(ComprehensiveInputTest),
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-    TEST_ENTRY(ParseMapTest),
+   TEST_ENTRY(ParseMapTest),
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-    TEST_ENTRY(BasicEncodeTest),
-    TEST_ENTRY(NestedMapTest),
-    TEST_ENTRY(BignumParseTest),
+   TEST_ENTRY(BasicEncodeTest),
+   TEST_ENTRY(NestedMapTest),
+   TEST_ENTRY(BignumDecodeTest),
+
 #ifndef QCBOR_DISABLE_TAGS
-    TEST_ENTRY(OptTagParseTest),
-    TEST_ENTRY(DateParseTest),
-    TEST_ENTRY(DecodeTaggedTypeTests),
+   TEST_ENTRY(TagNumberDecodeTest),
+   TEST_ENTRY(DateParseTest),
+   TEST_ENTRY(DecodeTaggedTypeTests),
 #endif /* QCBOR_DISABLE_TAGS */
-    TEST_ENTRY(ShortBufferParseTest2),
-    TEST_ENTRY(ShortBufferParseTest),
-    TEST_ENTRY(ParseDeepArrayTest),
-    TEST_ENTRY(SimpleArrayTest),
-    TEST_ENTRY(IntegerValuesParseTest),
+
+   TEST_ENTRY(ShortBufferParseTest2),
+   TEST_ENTRY(ShortBufferParseTest),
+   TEST_ENTRY(ParseDeepArrayTest),
+   TEST_ENTRY(SimpleArrayTest),
+   TEST_ENTRY(IntegerValuesParseTest),
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
-    TEST_ENTRY(AllocAllStringsTest),
-    TEST_ENTRY(MemPoolTest),
-    TEST_ENTRY(IndefiniteLengthStringTest),
+   TEST_ENTRY(AllocAllStringsTest),
+   TEST_ENTRY(MemPoolTest),
+   TEST_ENTRY(IndefiniteLengthStringTest),
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-    TEST_ENTRY(SpiffyIndefiniteLengthStringsTests),
+   TEST_ENTRY(SpiffyIndefiniteLengthStringsTests),
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-    TEST_ENTRY(SetUpAllocatorTest),
-    TEST_ENTRY(CBORTestIssue134),
+   TEST_ENTRY(SetUpAllocatorTest),
+   TEST_ENTRY(CBORTestIssue134),
+
 #endif /* #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
 #ifndef QCBOR_DISABLE_PREFERRED_FLOAT
    TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest),
    TEST_ENTRY(FloatValuesTests),
+   TEST_ENTRY(PreciseNumbersDecodeTest),
 #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
-    TEST_ENTRY(GeneralFloatEncodeTests),
-    TEST_ENTRY(GeneralFloatDecodeTests),
+   TEST_ENTRY(GeneralFloatEncodeTests),
+   TEST_ENTRY(GeneralFloatDecodeTests),
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
-    TEST_ENTRY(BstrWrapTest),
-    TEST_ENTRY(BstrWrapErrorTest),
-    TEST_ENTRY(BstrWrapNestTest),
-    TEST_ENTRY(CoseSign1TBSTest),
+
+   TEST_ENTRY(BstrWrapTest),
+   TEST_ENTRY(BstrWrapErrorTest),
+   TEST_ENTRY(BstrWrapNestTest),
+   TEST_ENTRY(CoseSign1TBSTest),
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-    TEST_ENTRY(StringDecoderModeFailTest),
+   TEST_ENTRY(StringDecoderModeFailTest),
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-    TEST_ENTRY_DISABLED(BigComprehensiveInputTest),
-    TEST_ENTRY_DISABLED(TooLargeInputTest),
-    TEST_ENTRY(EncodeErrorTests),
+   TEST_ENTRY_DISABLED(BigComprehensiveInputTest),
+   TEST_ENTRY_DISABLED(TooLargeInputTest),
+   TEST_ENTRY(EncodeErrorTests),
 #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
     TEST_ENTRY(IndefiniteLengthTest),
 #endif
-    TEST_ENTRY(EncodeLengthThirtyoneTest),
-    TEST_ENTRY(CBORSequenceDecodeTests),
-    TEST_ENTRY(IntToTests),
+   TEST_ENTRY(EncodeLengthThirtyoneTest),
+   TEST_ENTRY(CBORSequenceDecodeTests),
+   TEST_ENTRY(IntToTests),
 #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
-    TEST_ENTRY(PeekAndRewindTest),
+   TEST_ENTRY(PeekAndRewindTest),
 #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
 #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
-    TEST_ENTRY(ExponentAndMantissaDecodeTests),
+   TEST_ENTRY(ExponentAndMantissaDecodeTests),
 #ifndef QCBOR_DISABLE_TAGS
-    TEST_ENTRY(ExponentAndMantissaDecodeFailTests),
+   TEST_ENTRY(ExponentAndMantissaDecodeFailTests),
 #endif /* QCBOR_DISABLE_TAGS */
-    TEST_ENTRY(ExponentAndMantissaEncodeTests),
+   TEST_ENTRY(ExponentAndMantissaEncodeTests),
 #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
+   TEST_ENTRY(SortMapTest),
+#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
+   TEST_ENTRY(CDETest),
+   TEST_ENTRY(DCBORTest),
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
     TEST_ENTRY(ParseEmptyMapInMapTest),
     TEST_ENTRY(SubStringTest),
     TEST_ENTRY(BoolTest)
@@ -359,8 +377,5 @@
    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(QCBORTagListIn)",      (uint32_t)sizeof(QCBORTagListIn),     pfOutput, pOutCtx);
-   PrintSize("sizeof(QCBORTagListOut)",     (uint32_t)sizeof(QCBORTagListOut),    pfOutput, pOutCtx);
-   PrintSize("sizeof(TagSpecification)",    (uint32_t)sizeof(QCBOR_Private_TagSpec),pfOutput, pOutCtx);
    (*pfOutput)("", pOutCtx, 1);
 }