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** 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);
}