Revise tag handling; breaks compatibility with QCBOR v1
This is the big tag processing revision that breaks backwards compatibility.
QCBOREncode_AddTag()->QCBOREncode_AddTagNumber()
Pluggable tag content decoders are added.
QCBORDecode_GetTagNumber() added
QCBORDecode_NthTagNumber() added; it replaces QCBORDecode_GetNthTagNum()
New file qcbor_tag_decode for the tag content decoders
New tag decode example file
Incompatible changes
all tag content decoders are not loaded automatically
unprocessed tag numbers give an error
v1 compatibility mode available to restore compatibility
Add Seek to label in map QCBORDecode_SeekToLabelN, QCBORDecode_SeekToLabelSZ
Remove some deprecated tag functions from a very long time ago. They didn't work well and probably weren't used. QCBORDecode_SetCallerConfiguredTagList() QCBORDecode_GetNextWithTags(), QCBORDecode_IsTagged()
While all tests are passing, this is not providing adequate test coverage for the new functionality yet.
* Revise tag handling (check point, not tested)
* Reverse order of tag nums in QCBORItem to reduce code size
* Update tag decoding documentation
* Replaces IsTagged with MatchOneTagNumber; get rid of ancient tag list stuff
* fix & improve QCBOR_DISABLE_TAGS
* straggler from last commit
* remove qcbor2_encode.h
* Big check point
* Another checkpoint
* Update CMAKE files
* Add missing tag-example files
* Check point (getting close)
* Add tag examples
* Check point; tests passing, TagSpec removed
* Remove unused; test fan out might pass
* Rearrange v1 compat set up; other clean up
* fix test fan out, lots of nits
* Address a number of TODOs
---------
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e4aa83f..5003b91 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 34bdfc7..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 */; };
@@ -179,8 +186,12 @@
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 */
@@ -234,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 */,
@@ -275,6 +288,7 @@
children = (
E776E08C214AE07400E67947 /* qcbor_encode.c */,
E776E08E214AE07500E67947 /* qcbor_decode.c */,
+ E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */,
E776E08D214AE07500E67947 /* UsefulBuf.c */,
E73B57572161CA680080D658 /* ieee754.h */,
E73B57582161CA690080D658 /* ieee754.c */,
@@ -290,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 */,
@@ -471,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 */,
@@ -490,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 */,
@@ -509,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 */,
@@ -522,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 */,
@@ -548,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 */,
@@ -568,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/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/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/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 74e20ee..b74a97d 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -30,10 +30,10 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ========================================================================= */
-
#ifndef qcbor_common_h
#define qcbor_common_h
+//TODO: get rid of QCBOR_DISABLE_EXP_AND_MANTISSA and uncommon tags
#ifdef __cplusplus
extern "C" {
@@ -153,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
@@ -167,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()). */
@@ -232,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)
+
@@ -560,12 +563,19 @@
/* 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
* that they are not QCBOR_SUCCESS. See QCBORDecode_SetError(). */
QCBOR_ERR_FIRST_USER_DEFINED = 128,
- /** See \ref QCBOR_ERR_FIRST_USER_DEFINED */
+ /** See @ref QCBOR_ERR_FIRST_USER_DEFINED */
QCBOR_ERR_LAST_USER_DEFINED = 255
/* This is stored in uint8_t; never add values > 255 */
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 8b56b5d..e0781a9 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -219,11 +219,18 @@
/** This requires integer-float unification. It performs all the checks that
* QCBOR_DECODE_MODE_CDE does. */
- QCBOR_DECODE_MODE_DCBOR = 5
+ 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.
@@ -360,7 +367,6 @@
* 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
@@ -411,15 +417,20 @@
* @c val.epochDays */
#define QCBOR_TYPE_DAYS_EPOCH 78
-#define QCBOR_TYPE_TAG 254 /* Used internally; never returned */
-#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)
@@ -550,7 +561,10 @@
} Mantissa;
} expAndMantissa;
#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
- uint64_t uTagV; /* Used internally during decoding */
+ uint64_t uTagNumber;
+
+ /* For use by user-defined tag content handlers */
+ uint8_t userDefined[24];
} val;
@@ -569,26 +583,14 @@
#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;
@@ -710,6 +712,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
@@ -910,33 +913,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).
*
@@ -1150,32 +1127,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.
*
@@ -1184,7 +1232,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);
/**
@@ -1193,10 +1241,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(),
@@ -1204,12 +1252,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.
*
@@ -1401,7 +1451,7 @@
* @param[in] Item The number to process.
* @param[in] BigNumBuf The buffer to output to.
* @param[out] pBigNum The resulting big number.
- * @param[out] pIsNegative The sign of 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
@@ -1417,7 +1467,9 @@
* 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.
+ * \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
@@ -1456,7 +1508,7 @@
QCBORDecode_BignumPreferred(const QCBORItem Item,
UsefulBuf BigNumBuf,
UsefulBufC *pBigNum,
- bool *pIsNegative);
+ bool *pbIsNegative);
/**
@@ -1593,122 +1645,68 @@
* not recommended.
* ---- */
-
/**
- * 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 */
/* ------------------------------------------------------------------------
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 640f831..a770768 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.
@@ -954,7 +954,7 @@
/**
- * @brief Add an optional tag.
+ * @brief Add a tag number.
*
* @param[in] pCtx The encoding context to add the tag to.
* @param[in] uTag The tag to add
@@ -977,7 +977,7 @@
* tags.
*/
static void
-QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag);
+QCBOREncode_AddTagNumber(QCBOREncodeContext *pCtx, uint64_t uTag);
/**
@@ -1008,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().
*
@@ -2192,7 +2192,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
@@ -2768,6 +2768,13 @@
+/* DEPRECATED */
+
+/* Use QCBOREncode_AddTagNumber() instead */
+static void
+QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag);
+
+
/* =========================================================================
BEGINNING OF PRIVATE IMPLEMENTATION
========================================================================= */
@@ -3029,12 +3036,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
@@ -3160,7 +3174,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);
}
@@ -3217,7 +3231,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);
}
@@ -3294,7 +3308,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);
}
@@ -3821,7 +3835,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);
}
@@ -3876,7 +3890,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);
}
@@ -3931,7 +3945,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);
}
@@ -3989,7 +4003,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);
}
@@ -4044,7 +4058,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);
}
@@ -4098,7 +4112,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);
}
@@ -4152,7 +4166,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);
}
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index d7abe31..97f5088 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -353,6 +353,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
*
@@ -395,10 +400,19 @@
/* 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
*/
@@ -426,6 +440,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 855e840..8420f20 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
*
@@ -417,6 +418,17 @@
bool *pbIsNegative);
+/*
+ * Decode the next as a big number.
+ *
+ *
+ */
+void
+QCBORDecode_GetBigNumber(QCBORDecodeContext *pCtx,
+ const uint8_t uTagRequirement,
+ UsefulBuf BigNumberBuf,
+ UsefulBufC *pBigNumber,
+ bool *pbIsNegative);
/**
@@ -1083,6 +1095,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.
@@ -1152,6 +1182,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
@@ -1241,7 +1281,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.
@@ -1984,13 +2028,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,
@@ -1998,7 +2042,7 @@
bool *pbIsTag257);
-static void
+void
QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx,
const char *szLabel,
uint8_t uTagRequirement,
@@ -2222,56 +2266,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);
@@ -2393,7 +2425,7 @@
static inline void
QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
+ const int64_t nLabel,
QCBORItem *pItem,
UsefulBufC *pEncodedCBOR)
{
@@ -2440,7 +2472,7 @@
static inline void
QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
+ const int64_t nLabel,
QCBORItem *pItem,
UsefulBufC *pEncodedCBOR)
{
@@ -2617,63 +2649,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_NOT_A_TAG,
- {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_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_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_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
@@ -2681,33 +2715,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_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_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)
{
@@ -2769,14 +2804,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
@@ -2785,14 +2817,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
@@ -2801,14 +2831,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
@@ -2816,14 +2844,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
@@ -2832,30 +2857,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);
}
@@ -2865,14 +2888,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
@@ -2881,14 +2901,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
@@ -2897,14 +2915,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);
}
@@ -2913,14 +2929,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
@@ -2929,14 +2942,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
@@ -2945,13 +2956,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);
}
@@ -2960,14 +2970,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
@@ -2976,14 +2983,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
@@ -2992,14 +2997,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);
}
@@ -3008,108 +3011,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
@@ -3117,14 +3061,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
@@ -3133,14 +3074,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
@@ -3149,14 +3088,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_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID);
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_UUID,
+ CBOR_TAG_BIN_UUID,
+ pUUID);
}
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/qcbor_decode.c b/src/qcbor_decode.c
index 21845f4..5edd2d6 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;
-}
-
-
/*
@@ -1049,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.
@@ -1068,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,
@@ -1086,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;
@@ -1109,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;
}
@@ -1138,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 */
@@ -1164,7 +1169,7 @@
#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
static QCBORError
-QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode)
+QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode3Bit)
{
struct IEEE754_ToInt ToInt;
@@ -1178,7 +1183,7 @@
* The only thing allowed here is a double/half-precision that
* can't be converted to anything but a double.
*/
- if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
+ if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
ToInt = IEEE754_DoubleToInt(d);
if(ToInt.type != QCBOR_TYPE_DOUBLE) {
return QCBOR_ERR_DCBOR_CONFORMANCE;
@@ -1190,12 +1195,12 @@
static QCBORError
-QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode)
+QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode3Bit)
{
struct IEEE754_ToInt ToInt;
IEEE754_union ToSmaller;
- if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
+ 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) {
@@ -1209,7 +1214,7 @@
}
/* See if it could have been encoded shorter */
- if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
+ if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
ToSmaller = IEEE754_SingleToHalf(f, true);
if(ToSmaller.uSize != sizeof(float)) {
return QCBOR_ERR_PREFERRED_CONFORMANCE;
@@ -1221,12 +1226,12 @@
static QCBORError
-QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
+QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
{
struct IEEE754_ToInt ToInt;
IEEE754_union ToSmaller;
- if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
+ 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) {
@@ -1237,9 +1242,9 @@
return QCBOR_ERR_DCBOR_CONFORMANCE;
}
}
-
+
/* See if it could have been encoded shorter */
- if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
+ if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
if(ToSmaller.uSize != sizeof(double)) {
return QCBOR_ERR_PREFERRED_CONFORMANCE;
@@ -1251,10 +1256,10 @@
#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
static QCBORError
-QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode)
+QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode3Bit)
{
(void)f;
- if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
+ if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
} else {
return QCBOR_SUCCESS;
@@ -1262,10 +1267,10 @@
}
static QCBORError
-QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
+QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
{
(void)d;
- if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
+ if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
} else {
return QCBOR_SUCCESS;
@@ -1278,7 +1283,7 @@
* Decode a float
*/
static QCBORError
-QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode,
+QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode3Bit,
const int nAdditionalInfo,
const uint64_t uArgument,
QCBORItem *pDecodedItem)
@@ -1298,7 +1303,7 @@
pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
- uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode);
+ uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
if(uReturn != QCBOR_SUCCESS) {
break;
}
@@ -1316,7 +1321,7 @@
* 32 bits. It was widened to 64 bits to be passed in here.
*/
single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
- uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode);
+ uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode3Bit);
if(uReturn != QCBOR_SUCCESS) {
break;
}
@@ -1344,7 +1349,7 @@
pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
- uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode);
+ uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
if(uReturn != QCBOR_SUCCESS) {
break;
}
@@ -1402,7 +1407,7 @@
* type in input.
*/
static QCBORError
-QCBOR_Private_DecodeType7(const uint8_t uDecodeMode,
+QCBOR_Private_DecodeType7(const uint8_t uDecodeMode3Bit,
const int nAdditionalInfo,
const uint64_t uArgument,
QCBORItem *pDecodedItem)
@@ -1425,7 +1430,7 @@
case SINGLE_PREC_FLOAT: /* 26 */
case DOUBLE_PREC_FLOAT: /* 27 */
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
- uReturn = QCBOR_Private_DecodeFloat(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
+ uReturn = QCBOR_Private_DecodeFloat(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
#else
uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
@@ -1437,7 +1442,7 @@
case CBOR_SIMPLEV_UNDEF: /* 23 */
case CBOR_SIMPLE_BREAK: /* 31 */
#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
- if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
+ if(uDecodeMode3Bit >= QCBOR_ENCODE_MODE_DCBOR &&
nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
goto Done;
@@ -1457,7 +1462,7 @@
default: /* 0-19 */
#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
- if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
+ if(uDecodeMode3Bit >= QCBOR_ENCODE_MODE_DCBOR &&
(uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
goto Done;
@@ -1518,6 +1523,7 @@
int nMajorType = 0;
uint64_t uArgument = 0;
int nAdditionalInfo = 0;
+ uint8_t uDecodeMode3Bit = pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK;
memset(pDecodedItem, 0, sizeof(QCBORItem));
@@ -1527,7 +1533,7 @@
uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
// TODO: make this prettier; will optimizer take out stuff without ifdef?
- pMe->uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED,
+ uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED,
#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
&nMajorType,
&uArgument,
@@ -1554,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(pMe->uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
+ return QCBOR_Private_DecodeType7(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
break;
default:
@@ -1742,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.
*
@@ -1760,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;
@@ -1779,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;
@@ -1816,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 */
/**
@@ -1857,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 */
}
@@ -1987,7 +2015,7 @@
/* 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));
@@ -2000,7 +2028,8 @@
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 */
+ /* The recoverable error for the value overrides the recoverable
+ * error for the label, if there was an error for the label */
uErr = uErr2;
}
@@ -2009,10 +2038,10 @@
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;
@@ -2352,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).
*
@@ -2834,88 +2391,54 @@
*
* 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, NULL);
- 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.
- */
- const uint16_t uTagToProcess = pDecodedItem->uTags[0];
+ /* Loop over tag numbers in reverse, those closest to content first */
+ for(nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >= 0; nTagIndex--) {
- if(uTagToProcess == CBOR_TAG_INVALID16) {
- /* Hit the end of the tag list. A successful exit. */
- break;
-
- } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
- uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
-
- } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
- uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
-
-#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);
-
-#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 */
-
- } 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;
- break;
- }
+ if(pDecodedItem->auTagNumbers[nTagIndex] == CBOR_TAG_INVALID16) {
+ continue; /* Empty slot, skip to next */
}
- if(uReturn != QCBOR_SUCCESS) {
- /* Error exit from the loop */
- break;
+ /* 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 */
}
- /* A tag was successfully processed, shift it out of the list of
- * tags returned. This is the loop increment.
- */
- QCBOR_Private_ShiftTags(pDecodedItem);
+ /* 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;
}
-#endif /* QCBOR_DISABLE_TAGS */
Done:
- return uReturn;
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+ return uErr;
}
@@ -2975,8 +2498,8 @@
}
+#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.
@@ -3134,6 +2657,44 @@
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;
+}
/*
@@ -3143,17 +2704,11 @@
QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
{
QCBORError uErr;
+ size_t uOffset;
+
+ uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
-#ifndef QCBOR_DISABLE_CONFORMANCE
- if(uErr == QCBOR_SUCCESS && pMe->uDecodeMode >= 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 */
- if(uErr != QCBOR_SUCCESS) {
- pDecodedItem->uDataType = QCBOR_TYPE_NONE;
- pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
- }
+ uErr = QCBORDecode_Private_GetItemChecks(pMe, uErr, uOffset, pDecodedItem);
return uErr;
}
@@ -3193,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;
@@ -3216,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);
}
@@ -3339,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);
}
@@ -3373,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
@@ -3912,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);
}
@@ -3953,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 */
+}
+
+
/**
@@ -4124,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
@@ -4142,179 +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. It will also error out
- * if the caller tries to require a tag because there is no way that can
- * ever be fulfilled.
- */
-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) {
- return QCBOR_ERR_UNEXPECTED_TYPE;
- }
-
- 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;
}
@@ -4324,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;
}
@@ -4352,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);
}
/*
@@ -4366,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
*
@@ -4391,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.
@@ -4398,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;
}
@@ -4429,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));
@@ -4556,7 +4256,7 @@
goto Done;
}
- QCBORDecode_Private_CopyTags(pMe, &Item);
+ QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
@@ -4696,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.
*
@@ -4714,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
@@ -4790,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
*/
@@ -4798,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);
}
@@ -4832,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);
}
@@ -4851,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);
}
@@ -5057,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
+
+}
+
+
+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;
}
+/*
+ **/
+ 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
@@ -5117,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;
}
@@ -5132,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;
}
@@ -5147,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;
}
@@ -5213,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;
}
@@ -5228,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;
}
@@ -5243,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;
}
}
@@ -5288,33 +5180,138 @@
* 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
+QCBOR_Private_ProcessBigNum(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ UsefulBufC *pValue,
+ 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}
- };
+ QCBORError uErr;
- 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;
+ // TODO: is this right? Tests are passing. Fix after merges.
+ // TODO: make this work for GetBigNum and GetBigNumber(). They are different.
if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
*pbIsNegative = false;
} else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
*pbIsNegative = true;
}
+ *pValue = pItem->val.bigNum;
- return QCBOR_SUCCESS;
+ uErr = QCBOR_SUCCESS;
+
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+static void
+QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ UsefulBufC *pValue,
+ bool *pbIsTag257,
+ size_t uOffset)
+{
+ 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;
+ }
+
+ if(pItem->uDataType == QCBOR_TYPE_MIME) {
+ *pbIsTag257 = false;
+ } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
+ *pbIsTag257 = true;
+ }
+ *pValue = pItem->val.string;
+
+
+ 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);
}
@@ -5328,19 +5325,17 @@
bool *pbIsNegative)
{
QCBORItem Item;
+ size_t uOffset;
- QCBORDecode_VGetNext(pMe, &Item);
- if(pMe->uLastError) {
- return;
- }
-
- pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
- &Item,
- pValue,
- pbIsNegative);
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBOR_Private_ProcessBigNum(pMe,
+ uTagRequirement,
+ &Item,
+ pValue,
+ pbIsNegative,
+ uOffset);
}
-
/*
* Public function, see header qcbor/qcbor_spiffy_decode.h
*/
@@ -5351,19 +5346,18 @@
UsefulBufC *pValue,
bool *pbIsNegative)
{
- QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, 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_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+ QCBOR_Private_ProcessBigNum(pMe,
+ uTagRequirement,
+ &Item,
+ pValue,
+ pbIsNegative,
+ uOffset);
}
-
/*
* Public function, see header qcbor/qcbor_spiffy_decode.h
*/
@@ -5374,73 +5368,20 @@
UsefulBufC *pValue,
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_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+ QCBOR_Private_ProcessBigNum(pMe,
+ uTagRequirement,
+ &Item,
+ pValue,
+ 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().
- */
-QCBORError
-QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
- const QCBORItem *pItem,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- 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}
- };
-
- 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;
-}
-
// Improvement: add methods for wrapped CBOR, a simple alternate
// to EnterBstrWrapped
@@ -7080,78 +7021,10 @@
}
-/**
- * @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
@@ -7182,11 +7055,26 @@
* 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_NONE};
+
+static const uint8_t QCBORDecode_Private_BigFloatTypes[] = {
+ QCBOR_TYPE_BIGFLOAT,
+ QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
+ QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM,
+ QCBOR_TYPE_NONE};
+
/**
* @brief Common processor for exponent and 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.
@@ -7194,23 +7082,44 @@
* 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 type does not meet the TagSpec.
*/
static void
QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
- const QCBOR_Private_TagSpec TagSpec,
+ const uint8_t uTagRequirement,
+ const uint64_t uTagNumber,
+ const size_t uOffset,
QCBORItem *pItem,
int64_t *pnMantissa,
int64_t *pnExponent)
{
- QCBORError uErr;
+ QCBORError uErr = QCBOR_SUCCESS;
+ 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;
}
switch (pItem->uDataType) {
@@ -7240,12 +7149,12 @@
uErr = QCBOR_ERR_UNEXPECTED_TYPE;
}
- Done:
+ // Done:
pMe->uLastError = (uint8_t)uErr;
}
-/**
+/*
* @brief Decode exponent and mantissa into a big number.
*
* @param[in] pMe The decode context.
@@ -7261,23 +7170,39 @@
* 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_ProcessExpMantissaBig(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;
+ QCBORError uErr = QCBOR_SUCCESS;
+ const uint8_t *qTypes;
- if(pMe->uLastError != QCBOR_SUCCESS) {
+ 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;
}
uint64_t uMantissa;
@@ -7323,7 +7248,6 @@
uErr = QCBOR_ERR_UNEXPECTED_TYPE;
}
-Done:
pMe->uLastError = (uint8_t)uErr;
}
@@ -7337,19 +7261,14 @@
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_Private_GetAndTell(pMe, &Item, &uOffset);
QCBOR_Private_ProcessExpMantissa(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_DECIMAL_FRACTION,
+ uOffset,
&Item,
pnMantissa,
pnExponent);
@@ -7367,21 +7286,17 @@
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_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBOR_Private_ProcessExpMantissa(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_DECIMAL_FRACTION,
+ uOffset,
&Item,
pnMantissa,
pnExponent);
+
}
@@ -7395,19 +7310,14 @@
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_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);
QCBOR_Private_ProcessExpMantissa(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_DECIMAL_FRACTION,
+ uOffset,
&Item,
pnMantissa,
pnExponent);
@@ -7425,19 +7335,14 @@
bool *pbMantissaIsNegative,
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_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ProcessExpMantissaBig(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_DECIMAL_FRACTION,
+ uOffset,
&Item,
MantissaBuffer,
pMantissa,
@@ -7458,20 +7363,14 @@
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_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ProcessExpMantissaBig(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_DECIMAL_FRACTION,
+ uOffset,
&Item,
BufferForMantissa,
pMantissa,
@@ -7493,18 +7392,13 @@
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_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ProcessExpMantissaBig(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_DECIMAL_FRACTION,
+ uOffset,
&Item,
BufferForMantissa,
pMantissa,
@@ -7523,18 +7417,13 @@
int64_t *pnExponent)
{
QCBORItem Item;
- QCBORDecode_VGetNext(pMe, &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_GetAndTell(pMe, &Item, &uOffset);
QCBOR_Private_ProcessExpMantissa(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_BIGFLOAT,
+ uOffset,
&Item,
pnMantissa,
pnExponent);
@@ -7552,18 +7441,13 @@
int64_t *pnExponent)
{
QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &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_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBOR_Private_ProcessExpMantissa(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_BIGFLOAT,
+ uOffset,
&Item,
pnMantissa,
pnExponent);
@@ -7580,22 +7464,17 @@
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}
- };
-
+ QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBOR_Private_ProcessExpMantissa(pMe,
- TagSpec,
- &Item,
- pnMantissa,
- pnExponent);
+ uTagRequirement,
+ CBOR_TAG_BIGFLOAT,
+ uOffset,
+ &Item,
+ pnMantissa,
+ pnExponent);
}
@@ -7610,19 +7489,14 @@
bool *pbMantissaIsNegative,
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_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ProcessExpMantissaBig(pMe,
- TagSpec,
+ uTagRequirement,
+ CBOR_TAG_BIGFLOAT,
+ uOffset,
&Item,
MantissaBuffer,
pMantissa,
@@ -7643,24 +7517,19 @@
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_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ProcessExpMantissaBig(pMe,
- TagSpec,
- &Item,
- BufferForMantissa,
- pMantissa,
- pbIsNegative,
- pnExponent);
+ uTagRequirement,
+ CBOR_TAG_BIGFLOAT,
+ uOffset,
+ &Item,
+ BufferForMantissa,
+ pMantissa,
+ pbIsNegative,
+ pnExponent);
}
@@ -7677,23 +7546,18 @@
int64_t *pnExponent)
{
QCBORItem Item;
- QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &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_ProcessExpMantissaBig(pMe,
- TagSpec,
- &Item,
- BufferForMantissa,
- pMantissa,
- pbIsNegative,
- pnExponent);
+ uTagRequirement,
+ CBOR_TAG_BIGFLOAT,
+ uOffset,
+ &Item,
+ BufferForMantissa,
+ pMantissa,
+ pbIsNegative,
+ pnExponent);
}
#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
@@ -7861,7 +7725,7 @@
*pDest = *pSource + 1;
while(1) {
/* Wrap around from 0xff to 0 is a defined operation for
- unsigned addition in C. */
+ * 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,
@@ -7907,6 +7771,7 @@
}
+
/*
* Public function, see header qcbor/qcbor_decode.h
*/
@@ -7936,7 +7801,7 @@
/* Compute required length so it can be returned if buffer is too small */
switch(uType) {
case QCBOR_TYPE_INT64:
- uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)(Item.val.int64 < 0 ? -Item.val.int64 : Item.val.int64));
+ uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)ABSOLUTE_VALUE(Item.val.int64));
break;
case QCBOR_TYPE_UINT64:
@@ -8006,33 +7871,70 @@
}
-static QCBORError
-QCBOR_Private_ProcessPreferredBigNum(const uint8_t uTagRequirement,
- const QCBORItem *pItem,
- UsefulBuf BigNumBuf,
- UsefulBufC *pValue,
- bool *pbIsNegative)
+
+
+static void
+QCBOR_Private_ProcessPreferredBigNum(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ const size_t uOffset,
+ UsefulBuf BigNumBuf,
+ UsefulBufC *pValue,
+ bool *pbIsNegative)
{
if(pItem->uDataType != QCBOR_TYPE_INT64 &&
pItem->uDataType != QCBOR_TYPE_UINT64 &&
pItem->uDataType != QCBOR_TYPE_65BIT_NEG_INT) {
- /* The integer types are always OK. If it's not an integer type drop
- * in to the tag type checking system. */
- 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}
- };
+ /* Two stage processing because big numbers are handled like that */
- 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;
}
}
- return QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
+ pMe->uLastError = (uint8_t)QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
+}
+
+
+static void
+QCBOR_Private_ProcessBigNumber(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ const size_t uOffset,
+ UsefulBuf BigNumBuf,
+ UsefulBufC *pValue,
+ bool *pbIsNegative)
+{
+ /* Two stage processing because big numbers are handled like that */
+
+ 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;
+ }
+
+ pMe->uLastError = (uint8_t)QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
}
@@ -8047,19 +7949,32 @@
bool *pbIsNegative)
{
QCBORItem Item;
+ size_t uOffset;
- if(pMe->uLastError != QCBOR_SUCCESS) {
- /* Already in error state, do nothing */
- return;
- }
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBOR_Private_ProcessPreferredBigNum(pMe, uTagRequirement, &Item, uOffset, BigNumBuf, pValue, pbIsNegative);
+}
- QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
- if(uError != QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)uError;
- return;
- }
- QCBOR_Private_ProcessPreferredBigNum(uTagRequirement, &Item, BigNumBuf, pValue, pbIsNegative);
+
+void
+QCBORDecode_GetBigNumber(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBuf BigNumberBuf,
+ UsefulBufC *pBigNumber,
+ bool *pbIsNegative)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBOR_Private_ProcessBigNumber(pMe,
+ uTagRequirement,
+ &Item,
+ uOffset,
+ BigNumberBuf,
+ pBigNumber,
+ pbIsNegative);
}
@@ -8074,17 +7989,17 @@
UsefulBufC *pValue,
bool *pbIsNegative)
{
- QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
+ QCBORItem Item;
+ size_t uOffset;
- pMe->uLastError = (uint8_t)QCBOR_Private_ProcessPreferredBigNum(uTagRequirement,
- &Item,
- BigNumBuf,
- pValue,
- pbIsNegative);
+ QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+ QCBOR_Private_ProcessPreferredBigNum(pMe,
+ uTagRequirement,
+ &Item,
+ uOffset,
+ BigNumBuf,
+ pValue,
+ pbIsNegative);
}
/*
@@ -8098,17 +8013,17 @@
UsefulBufC *pValue,
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_ProcessPreferredBigNum(uTagRequirement,
- &Item,
- BigNumBuf,
- pValue,
- pbIsNegative);
+ QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
+ QCBOR_Private_ProcessPreferredBigNum(pMe,
+ uTagRequirement,
+ &Item,
+ uOffset,
+ BigNumBuf,
+ pValue,
+ pbIsNegative);
}
-
+// TODO: re order above functions in tag number order
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 50ed8a3..28ff84d 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -187,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()
@@ -772,7 +772,7 @@
const UsefulBufC BigNum)
{
if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
- QCBOREncode_AddTag(pMe, uTag);
+ QCBOREncode_AddTagNumber(pMe, uTag);
}
QCBOREncode_AddBytes(pMe, BigNum);
}
@@ -833,7 +833,7 @@
UsefulBufC NextSubString;
if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
- QCBOREncode_AddTag(pMe, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddTagNumber(pMe, CBOR_TAG_NEG_BIGNUM);
}
/* This works on any length without the need of an additional buffer */
@@ -1105,7 +1105,7 @@
* that has no effect on the code here.
*/
if(uTag != CBOR_TAG_INVALID64) {
- QCBOREncode_AddTag(pMe, uTag);
+ QCBOREncode_AddTagNumber(pMe, uTag);
}
QCBOREncode_OpenArray(pMe);
QCBOREncode_AddInt64(pMe, nExponent);
@@ -1608,7 +1608,7 @@
/*
* Public functions for closing sorted maps. See qcbor/qcbor_encode.h
*/
-void
+void
QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pMe)
{
uint32_t uStart;
@@ -1629,7 +1629,7 @@
/*
* Public functions for closing sorted maps. See qcbor/qcbor_encode.h
*/
-void
+void
QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pMe)
{
uint32_t uStart;
diff --git a/src/qcbor_tag_decode.c b/src/qcbor_tag_decode.c
new file mode 100644
index 0000000..6479fa2
--- /dev/null
+++ b/src/qcbor_tag_decode.c
@@ -0,0 +1,414 @@
+/* ==========================================================================
+ * 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 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 uint64_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;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_ExpMantissaTagCB(QCBORDecodeContext *pDecodeCtx,
+ void *pTagDecodersContext,
+ uint64_t uTagNumber,
+ QCBORItem *pDecodedItem)
+{
+ (void)pTagDecodersContext;
+
+ 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 uint8_t uNestLevel = pDecodedItem->uNestingLevel + 1;
+
+ /* --- Get the exponent --- */
+ QCBORItem ExponentItem;
+ 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 --- */
+ QCBORItem MantissaItem;
+ 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 {
+ /* 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 == 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/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 8217053..f5c95e1 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"
@@ -1524,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) {
@@ -1867,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);
}
@@ -1907,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);
}
@@ -1927,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;
@@ -2043,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);
}
@@ -2061,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);
}
@@ -2600,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
@@ -2613,7 +2610,7 @@
}
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
- if(nIndex == 55) {
+ if(nIndex == 52) {
uCBORError = 9; /* For setting break points */
}
@@ -3433,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))) {
@@ -3478,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;
}
@@ -3678,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
@@ -3777,7 +3779,7 @@
int64_t nEpochDate2,
nEpochDateFail,
nEpochDate1400000000, nEpochDays1;
- UsefulBufC StringDays1;
+ UsefulBufC StringDays1, StringDate3;
uint64_t uTag1, uTag2;
// Tagged date string
@@ -3879,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;
@@ -3948,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
@@ -4015,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)
@@ -4025,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({
@@ -4104,23 +4141,23 @@
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.
};
static int32_t CheckCSRMaps(QCBORDecodeContext *pDC);
-
-int32_t OptTagParseTest(void)
+int32_t TagNumberDecodeTest(void)
{
QCBORDecodeContext DCtx;
QCBORItem Item;
QCBORError uError;
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
@@ -4130,8 +4167,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;
}
@@ -4142,7 +4178,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 ||
@@ -4226,68 +4262,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;
- }
@@ -4296,196 +4404,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
@@ -4497,7 +4499,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
@@ -4521,8 +4523,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;
@@ -4553,8 +4557,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) {
@@ -4569,8 +4575,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;
@@ -4601,8 +4609,9 @@
#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
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
@@ -4614,12 +4623,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
@@ -4634,8 +4643,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
@@ -4655,12 +4665,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
@@ -4671,6 +4681,7 @@
return 0;
}
+#endif /* ! QCBOR_DISABLE_TAGS */
/*
* These are showing the big numbers converted to integers.
@@ -4858,8 +4869,9 @@
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);
//
@@ -4948,6 +4960,8 @@
}
QCBORDecode_Init(&DCtx, pTest->Encoded, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
+
uErr = QCBORDecode_GetNext(&DCtx, &Item);
if(uErr != QCBOR_SUCCESS) {
return MakeTestResultCode(uTestIndex, 1, uErr);
@@ -4976,6 +4990,8 @@
}
QCBORDecode_Init(&DCtx, pTest->Encoded, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
+
QCBORDecode_GetBigNumPreferred(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, BignumBuf, &ResultBigNum, &bIsNeg);
uErr = QCBORDecode_GetError(&DCtx);
if(uErr != QCBOR_SUCCESS) {
@@ -5381,6 +5397,7 @@
IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5);
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_CompatibilityV1(&DC);
nResult = QCBORDecode_GetNext(&DC, &Item);
@@ -6056,11 +6073,11 @@
{(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 GetBigFloatBig */ // TODO: think about error code here
0,
{(const uint8_t []){0x00}, 1},
false
@@ -6078,11 +6095,11 @@
{(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 GetDecimalFractionBig */ // TODO: think about error code
0,
{(const uint8_t []){0x03}, 1},
false,
@@ -6096,7 +6113,6 @@
{(const uint8_t []){0x64}, 1},
false
},
-
{
"5. Tagged 4([-20, 4759477275222530853136]) decimal fraction, tag 4 required",
{(const uint8_t []){0xC4, 0x82, 0x33,
@@ -6160,6 +6176,7 @@
{(const uint8_t []){0x00}, 0},
false
},
+
{
"7. Tagged 5([-20, 4294967295]) big float, big num mantissa, tag 5 required",
{(const uint8_t []){0xC5, 0x82, 0x33,
@@ -6246,11 +6263,11 @@
{(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 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 GetBigFloatBig */
0,
{(const uint8_t []){0x00}, 1},
false
@@ -6274,6 +6291,7 @@
const struct EaMTest *pT = &pEaMTests[uIndex];
/* Decode with GetNext */
QCBORDecode_Init(&DCtx, pT->Input, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
if(uIndex + 1 == 9) {
nExponent = 99; // just to set a break point
@@ -6315,6 +6333,8 @@
/* Decode with GetDecimalFraction */
QCBORDecode_Init(&DCtx, pT->Input, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
+
QCBORDecode_GetDecimalFraction(&DCtx,
pT->uTagRequirement,
&nMantissa,
@@ -6345,6 +6365,8 @@
/* Decode with GetDecimalFractionBig */
QCBORDecode_Init(&DCtx, pT->Input, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
+
QCBORDecode_GetDecimalFractionBig(&DCtx,
pT->uTagRequirement,
MantissaBuf,
@@ -6380,6 +6402,8 @@
/* Decode with GetBigFloat */
QCBORDecode_Init(&DCtx, pT->Input, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
+
QCBORDecode_GetBigFloat(&DCtx,
pT->uTagRequirement,
&nMantissa,
@@ -6410,6 +6434,8 @@
/* Decode with GetBigFloatBig */
QCBORDecode_Init(&DCtx, pT->Input, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
+
QCBORDecode_GetBigFloatBig(&DCtx,
pT->uTagRequirement,
MantissaBuf,
@@ -6476,6 +6502,8 @@
QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_CompatibilityV1(&DC);
+
uErr = QCBORDecode_GetNext(&DC, &item);
if(uErr != QCBOR_SUCCESS) {
return 100;
@@ -7080,6 +7108,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;
@@ -7160,6 +7201,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;
}
@@ -7376,6 +7449,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);
@@ -7954,11 +8029,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 */
@@ -8670,6 +8747,7 @@
QCBORError uErr;
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedTypes), 0);
+ QCBORDecode_CompatibilityV1(&DC);
UsefulBufC String;
bool bNeg;
@@ -8988,6 +9066,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);
@@ -9958,7 +10037,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;
}
@@ -10593,11 +10677,12 @@
for(uTestIndex = 0; uTestIndex < uTestCount; uTestIndex++) {
pTest = &PreciseNumberConversions[uTestIndex];
- if(uTestIndex == 18) {
+ if(uTestIndex == 16) {
uErr = 99; // For break point only
}
QCBORDecode_Init(&DCtx, pTest->CBOR, 0);
+ QCBORDecode_CompatibilityV1(&DCtx);
QCBORDecode_GetNumberConvertPrecisely(&DCtx, &Item);
@@ -10801,6 +10886,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);
@@ -10810,9 +10897,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 31d9e48..37d061e 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -179,7 +179,7 @@
/*
Test decode of CBOR tagging like the CBOR magic number and many others.
*/
-int32_t OptTagParseTest(void);
+int32_t TagNumberDecodeTest(void);
/*
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index e2b8341..76572c6 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -535,10 +535,10 @@
/* 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_AddInt64(pECtx, -44);
@@ -567,7 +567,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_AddBytesToMap(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3}));
@@ -619,7 +619,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);
@@ -632,7 +632,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");
@@ -646,7 +646,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);
diff --git a/test/run_tests.c b/test/run_tests.c
index 386da72..578c34c 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -116,7 +116,7 @@
TEST_ENTRY(BignumDecodeTest),
#ifndef QCBOR_DISABLE_TAGS
- TEST_ENTRY(OptTagParseTest),
+ TEST_ENTRY(TagNumberDecodeTest),
TEST_ENTRY(DateParseTest),
TEST_ENTRY(DecodeTaggedTypeTests),
#endif /* QCBOR_DISABLE_TAGS */
@@ -377,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);
}