re sync with master; fix data parse bug
diff --git a/.gitignore b/.gitignore
index f5bad2a..4d0372d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,5 @@
# Compiled binaries
qcbortest
+qcbormin
+
diff --git a/Makefile b/Makefile
index db16964..543342f 100644
--- a/Makefile
+++ b/Makefile
@@ -7,39 +7,88 @@
# See BSD-3-Clause license in README.md
#
+CC=cc
+#CC=/usr/local/bin/gcc-9
-CFLAGS=-I inc -I test -Os -DQCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+CFLAGS=-I inc -I test -Os -fPIC
-QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o
+# The following are used before a release of QCBOR help to make sure
+# the code compiles and runs in the most strict environments, but not
+# all compilers support them so they are not turned on.
+#CFLAGS=-I inc -I test -Os -fpic -Wall -pedantic-errors -Wextra -Wshadow -Wparentheses -Wconversion -xc -std=c99
-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
+
+QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_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
+
+.PHONY: all so install uninstall clean
+
+all: qcbortest qcbormin libqcbor.a
+
+so: libqcbor.so
qcbortest: libqcbor.a $(TEST_OBJ) cmd_line_main.o
- cc -o $@ $^ libqcbor.a
+ $(CC) -o $@ $^ libqcbor.a
qcbormin: libqcbor.a min_use_main.o
- cc -dead_strip -o $@ $^ libqcbor.a
+ $(CC) -dead_strip -o $@ $^ libqcbor.a
libqcbor.a: $(QCBOR_OBJ)
ar -r $@ $^
-src/UsefulBuf.o: inc/UsefulBuf.h
-src/qcbor_decode.o: inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
-src/qcbor_encode.o: inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
-src/iee754.o: src/ieee754.h
+# The shared library is not made by default because of platform
+# variability For example MacOS and Linux behave differently and some
+# IoT OS's don't support them at all.
+libqcbor.so: $(QCBOR_OBJ)
+ $(CC) -shared $^ $(CFLAGS) -o $@
-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
-test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor.h inc/UsefulBuf.h
-test/qcbor_encode_tests.o: test/qcbor_encode_tests.h inc/qcbor.h inc/UsefulBuf.h
-test/qcbor_decode_tests.o: test/qcbor_decode_tests.h inc/qcbor.h inc/UsefulBuf.h
-test/float_tests.o: inc/qcbor.h inc/UsefulBuf.h test/float_tests.h test/half_to_double_from_rfc7049.h
-test/half_to_double_from_rfc7049.o: test/half_to_double_from_rfc7049.h
+PUBLIC_INTERFACE=inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_encode.h inc/qcbor/qcbor_decode.h
-cmd_line_main.o: test/run_tests.h inc/qcbor.h
+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_encode.h src/ieee754.h
+src/qcbor_encode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_decode.h src/ieee754.h
+src/iee754.o: src/ieee754.h
+src/qcbor_err_to_str.o: inc/qcbor/qcbor_common.h
-min_use_main.o: inc/qcbor.h inc/UsefulBuf.h
+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
+test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor/UsefulBuf.h
+test/qcbor_encode_tests.o: test/qcbor_encode_tests.h $(PUBLIC_INTERFACE)
+test/qcbor_decode_tests.o: test/qcbor_decode_tests.h $(PUBLIC_INTERFACE)
+test/float_tests.o: test/float_tests.h test/half_to_double_from_rfc7049.h $(PUBLIC_INTERFACE)
+test/half_to_double_from_rfc7049.o: test/half_to_double_from_rfc7049.h
+
+cmd_line_main.o: test/run_tests.h $(PUBLIC_INTERFACE)
+
+min_use_main.o: $(PUBLIC_INTERFACE)
+
+ifeq ($(PREFIX),)
+ PREFIX := /usr/local
+endif
+
+install: libqcbor.a $(PUBLIC_INTERFACE)
+ install -d $(DESTDIR)$(PREFIX)/lib/
+ install -m 644 libqcbor.a $(DESTDIR)$(PREFIX)/lib/
+ install -d $(DESTDIR)$(PREFIX)/include/qcbor
+ install -m 644 inc/qcbor/qcbor.h $(DESTDIR)$(PREFIX)/include/qcbor
+ install -m 644 inc/qcbor/qcbor_private.h $(DESTDIR)$(PREFIX)/include/qcbor
+ install -m 644 inc/qcbor/qcbor_common.h $(DESTDIR)$(PREFIX)/include/qcbor
+ install -m 644 inc/qcbor/qcbor_decode.h $(DESTDIR)$(PREFIX)/include/qcbor
+ install -m 644 inc/qcbor/qcbor_encode.h $(DESTDIR)$(PREFIX)/include/qcbor
+ install -m 644 inc/qcbor/UsefulBuf.h $(DESTDIR)$(PREFIX)/include/qcbor
+
+install_so: libqcbor.so
+ install -m 755 libqcbor.so $(DESTDIR)$(PREFIX)/lib/libqcbor.so.1.0.0
+ ln -sf libqcbor.so.1 $(DESTDIR)$(PREFIX)/lib/libqcbor.so
+ ln -sf libqcbor.so.1.0.0 $(DESTDIR)$(PREFIX)/lib/libqcbor.so.1
+
+uninstall: libqcbor.a $(PUBLIC_INTERFACE)
+ $(RM) -d $(DESTDIR)$(PREFIX)/include/qcbor/*
+ $(RM) -d $(DESTDIR)$(PREFIX)/include/qcbor/
+ $(RM) $(addprefix $(DESTDIR)$(PREFIX)/lib/, \
+ libqcbor.a libqcbor.so libqcbor.so.1 libqcbor.so.1.0.0)
clean:
- rm -f $(QCBOR_OBJ) $(TEST_OBJ) libqcbor.a min_use_main.o cmd_line_main.o
+ rm -f $(QCBOR_OBJ) $(TEST_OBJ) libqcbor.a min_use_main.o cmd_line_main.o libqcbor.a libqcbor.so qcbormin qcbortest
diff --git a/Makefile.gcc b/Makefile.gcc
deleted file mode 100644
index 38cfb78..0000000
--- a/Makefile.gcc
+++ /dev/null
@@ -1,45 +0,0 @@
-# Makefile -- UNIX-style make for qcbor as a lib and command line test
-#
-# Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-# See BSD-3-Clause license in README.md
-#
-
-CFLAGS=-I inc -I test -Os -Wcast-align -Wall -Werror -pedantic-errors -Wextra -Wshadow -Wparentheses -xc -std=c99 -Werror=maybe-uninitialized
-CC=/usr/local/bin/gcc-9
-
-QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.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
-
-qcbortest: libqcbor.a $(TEST_OBJ) cmd_line_main.o
- $(CC) -o $@ $^ libqcbor.a
-
-qcbormin: libqcbor.a min_use_main.o
- $(CC) -dead_strip -o $@ $^ libqcbor.a
-
-libqcbor.a: $(QCBOR_OBJ)
- ar -r $@ $^
-
-src/UsefulBuf.o: inc/UsefulBuf.h
-src/qcbor_decode.o: inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
-src/qcbor_encode.o: inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
-src/iee754.o: src/ieee754.h
-
-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
-test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor.h inc/UsefulBuf.h
-test/qcbor_encode_tests.o: test/qcbor_encode_tests.h inc/qcbor.h inc/UsefulBuf.h
-test/qcbor_decode_tests.o: test/qcbor_decode_tests.h inc/qcbor.h inc/UsefulBuf.h
-test/float_tests.o: inc/qcbor.h inc/UsefulBuf.h test/float_tests.h test/half_to_double_from_rfc7049.h
-test/half_to_double_from_rfc7049.o: test/half_to_double_from_rfc7049.h
-
-cmd_line_main.o: test/run_tests.h inc/qcbor.h
-
-min_use_main.o: inc/qcbor.h inc/UsefulBuf.h
-
-clean:
- rm -f $(QCBOR_OBJ) $(TEST_OBJ) libqcbor.a min_use_main.o cmd_line_main.o
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index 14b61be..baed191 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -68,6 +68,7 @@
E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = half_to_double_from_rfc7049.c; path = test/half_to_double_from_rfc7049.c; sourceTree = "<group>"; };
E73B57632161F8F70080D658 /* run_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = run_tests.c; path = test/run_tests.c; sourceTree = "<group>"; tabWidth = 3; };
E73B57642161F8F80080D658 /* run_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = run_tests.h; path = test/run_tests.h; sourceTree = "<group>"; };
+ E74BF411245D6713002CE8E8 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/qcbor/UsefulBuf.h; sourceTree = "<group>"; };
E772022723B52C02006E966E /* QCBOR_Disable_Exp_Mantissa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Exp_Mantissa; sourceTree = BUILT_PRODUCTS_DIR; };
E776E07C214ADF7F00E67947 /* QCBOR */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR; sourceTree = BUILT_PRODUCTS_DIR; };
E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; tabWidth = 3; };
@@ -77,6 +78,10 @@
E776E094214AE09700E67947 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/UsefulBuf.h; sourceTree = "<group>"; tabWidth = 3; };
E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = "<group>"; };
E776E161214EE19C00E67947 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
+ E78C91DE240C90C100F4CECE /* qcbor_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_decode.h; path = inc/qcbor/qcbor_decode.h; sourceTree = "<group>"; };
+ E78C91DF240C90C100F4CECE /* qcbor_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_common.h; path = inc/qcbor/qcbor_common.h; sourceTree = "<group>"; };
+ E78C91E0240C90C100F4CECE /* qcbor_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_private.h; path = inc/qcbor/qcbor_private.h; sourceTree = "<group>"; };
+ E78C91E1240C90C100F4CECE /* qcbor_encode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_encode.h; path = inc/qcbor/qcbor_encode.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -133,6 +138,11 @@
E776E092214AE07C00E67947 /* inc */ = {
isa = PBXGroup;
children = (
+ E74BF411245D6713002CE8E8 /* UsefulBuf.h */,
+ E78C91DF240C90C100F4CECE /* qcbor_common.h */,
+ E78C91DE240C90C100F4CECE /* qcbor_decode.h */,
+ E78C91E1240C90C100F4CECE /* qcbor_encode.h */,
+ E78C91E0240C90C100F4CECE /* qcbor_private.h */,
E776E093214AE08B00E67947 /* qcbor.h */,
E776E094214AE09700E67947 /* UsefulBuf.h */,
);
@@ -202,7 +212,7 @@
E776E074214ADF7F00E67947 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0940;
+ LastUpgradeCheck = 1140;
ORGANIZATIONNAME = "Laurence Lundblade";
TargetAttributes = {
E776E07B214ADF7F00E67947 = {
@@ -353,6 +363,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ "HEADER_SEARCH_PATHS[arch=*]" = inc;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -412,6 +423,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ "HEADER_SEARCH_PATHS[arch=*]" = inc;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
@@ -427,6 +439,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_PEDANTIC = YES;
+ "HEADER_SEARCH_PATHS[arch=*]" = inc;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -440,6 +453,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_PEDANTIC = YES;
+ "HEADER_SEARCH_PATHS[arch=*]" = inc;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
diff --git a/README.md b/README.md
index e3953aa..1f8a646 100644
--- a/README.md
+++ b/README.md
@@ -75,12 +75,15 @@
There is a simple makefile for the UNIX style command line binary that
compiles everything to run the tests.
-These seven files, the contents of the src and inc directories, make
+These ten files, the contents of the src and inc directories, make
up the entire implementation.
* inc
* UsefulBuf.h
- * qcbor.h
+ * qcbor_private.h
+ * qcbor_common.h
+ * qcbor_encode.h
+ * qcbor_decode.h
* src
* UsefulBuf.c
* qcbor_encode.c
@@ -116,6 +119,32 @@
See the comment sections on "Configuration" in inc/UsefulBuf.h.
+## Code Size
+
+These are approximate sizes on 64-bit x86 with the -Os optimization.
+
+ | | smallest | largest |
+ |---------------|----------|---------|
+ | encode only | 1000 | 1800 |
+ | decode only | 2600 | 4250 |
+ | combined | 3600 | 6050 |
+
+The following are some ways to make the code smaller.
+
+The gcc compiler output is usually smaller than llvm because stack guards are off by default.
+You can all turn of stack gaurds with llvm. It is safe to turn off stack guards with
+this code because Usefulbuf provides similar defenses and this code was carefully
+written to be defensive.
+
+Use fewer of the encode functions, particularly avoid floating point and bstr wrapping. This
+combined with dead-stripping works very well to automatically omit functions
+that are not needed on the encode side.
+
+Disable features with defines like QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA.
+This is the primary means of reducing code on the decode side. More of these defines are
+planned than are currently implemented, but they are a little complex to implement because
+all the configurations must be tested.
+
## Other Software Using QCBOR
* [t_cose](https://github.com/laurencelundblade/t_cose) implements enough of
@@ -124,6 +153,8 @@
[Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-01).
Specifically it supports signing and verification of the COSE_Sign1 message.
+* [ctoken](https://github.com/laurencelundblade/t_cose) is an implementation of
+EAT and CWT.
## Changes from CAF Version
* Float support is restored
diff --git a/TimeTag1FAQ.md b/TimeTag1FAQ.md
new file mode 100644
index 0000000..b13e8f3
--- /dev/null
+++ b/TimeTag1FAQ.md
@@ -0,0 +1,56 @@
+
+# Tag 1 Implementator’s FAQ
+
+ +-------------------------------+---------------------+------------------------+
+ | | 1 second resolution | microsecond resolution |
+ +-------------------------------+---------------------+------------------------+
+ | Recent Human Time Scale | 32-bit unsigned | double |
+ | 1970 - 2106 | | |
+ +-------------------------------+---------------------+------------------------+
+ | Recent Human Past | 32-bit negative | double |
+ | 1834 - 1970 | | |
+ +-------------------------------+---------------------+------------------------+
+ | Universal Scale, Now & Future | 64-bit unsigned | double |
+ | 1970 - 500 billion years | | |
+ +-------------------------------+---------------------+------------------------+
+ | Universal Scale, Past | 64-bit negative | double |
+ | 500 billion years ago - 1969 | | |
+ +-------------------------------+---------------------+------------------------+
+
+
+Q: I just want to implement the minimum, what should I do?
+A: You should support 64-bit unsigned encoding. This will cover just about every use case because it works from 1970 until over 500 billion years in the future and 1 second resolution is enough for most human activity. The earth is only 4.5 billion years old. Note that time values up to 2106 will be encoded as 32-bit integers even though 64-bit integers are supported because only 32-bits are needed to count seconds up to the year 2106.
+
+Q: I’m implementing on an 8-bit CPU and 64-bit integers are really a problem.
+A: You can support just 32-bit integers, but they will stop working in 2106.
+
+Q: Why 2106 and not 2038?
+A: Because CBOR encodes positive and negative integers with different major types and thus is able to use the full 32-bits for positive integers.
+
+Q: What if I need time values before 1970?
+A: Implement 64 or 32-bit negative time values, but note that there is no clear standard for this as POSIX and UTC time are not defined for this time period. If your implementation assumes every days is 86,400 seconds and follow the rules for leap years, you should have accuracy to within hours, if not minutes.
+
+Q: Is Tag 1 better than Tag 0 for time values?
+A: In a lot of ways it is, because it is just a simple integer. It takes up a lot less space. It is a lot simpler to parse. Most OS’s have the ability to turn POSIX time into a structure of month, day, year, hour, minute and second. Note however that POSIX time has a discontinuity of about once every year for leap second adjustment.
+
+Q: What is a leap second?
+A: It actually takes the earth about 1 year and 1 second to revolve around the sun, so 1 extra second has to be added almost every year. UTC Time handles this by counting the seconds from 0-60 (not 0-59) in the last minute of the year. This standard uses POSIX time which can be said to handle this by the clock stopping for 1 second in the last minute of the year.
+
+Q: Do I have to implement floating point time?
+A: No. There are not many use cases that need it. However, for maximal interoperability, it is good to support it.
+
+Q: When should I use floating point?
+A: Only if you need time resolution greater than one second. There is no benefit otherwise. 64-bit time can represent time +/-500 billion years in the same number of bits, so floating point time is unnecessary for very large times scales.
+
+Q: What resolution do I get with floating point?
+A: It varies over the years. For 1970 to 1971 you get almost nanosecond accuracy. For the current century, 2000-2099, you get microsecond accuracy. 285 million years from now, it will be less than a second and the 64-bit unsigned representation will have more resolution. This is because a double only has 52 bits of resolution.
+
+Q: Should I implement single or double floating point?
+A: If you are going to use floating point you should always implement double. Single has no advantage over 32-bit integers. It provides less range and less precision. It has only 23 bits of resolution. It is of course good to support decoding of single in case someone sends you one, but there no point to ever sending a tag 1 encoded time value as a single.
+
+Q: Can I disallow floating point time in the definition of my protocol?
+A: Yes. This is a good idea if you do not need resolution less than one second. It will make implementations simpler and more compact. Note that while most CPUs do support IEEE 754 floating point, particularly small ones do not.
+
+Q: What if I’m transmitting thousands of time stamps and space is a problem?
+A: If you want to maintain 1 second resolution, there is really no more compact way to transmit time than tag 1 with 32-bit or 64-bit integer. If you wish reduce resolution, use a different time, perhaps one that counts days rather than seconds.
+
diff --git a/inc/UsefulBuf.h b/inc/UsefulBuf.h
index a8da83b..f14084e 100644
--- a/inc/UsefulBuf.h
+++ b/inc/UsefulBuf.h
@@ -1,2134 +1 @@
-/*============================================================================
- Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors, nor the name "Laurence Lundblade" may be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- =============================================================================*/
-
-/*============================================================================
- FILE: UsefulBuf.h
-
- DESCRIPTION: General purpose input and output buffers
-
- EDIT HISTORY FOR FILE:
-
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
-
- when who what, where, why
- -------- ---- --------------------------------------------------
- 1/25/2020 llundblade Add some casts so static anlyzers don't complain.
- 5/21/2019 llundblade #define configs for efficient endianness handling.
- 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL().
- 3/23/2019 llundblade Big documentation & style update. No interface
- change.
- 3/6/2019 llundblade Add UsefulBuf_IsValue()
- 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
- 12/13/2018 llundblade Documentation improvements
- 09/18/2018 llundblade Cleaner distinction between UsefulBuf and
- UsefulBufC.
- 02/02/18 llundbla Full support for integers in and out; fix pointer
- alignment bug. Incompatible change: integers
- in/out are now in network byte order.
- 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
- 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected
- comparison for < or > for unequal length buffers.
- Added UsefulBuf_Set() function.
- 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
- 11/13/16 llundbla Initial Version.
-
- =============================================================================*/
-
-#ifndef _UsefulBuf_h
-#define _UsefulBuf_h
-
-
-/*
- Configuration Options
-
- This code is designed so it will work correctly and completely by
- default. No configuration is necessary to make it work. None of the
- following #defines need to be enabled. The code works and is very
- portable with them all turned off.
-
- All configuration options (USEFULBUF_CONFIG_XXX)
- 1) Reduce code size
- 2) Improve efficiency
- 3) Both of the above
-
- The efficiency improvements are not large, so the main reason really
- is to reduce code size.
-
- */
-
-
-/*
- Endianness Configuration
-
- By default, UsefulBuf does not need to know what the endianness of
- the device is. All the code will run correctly on either big or
- little endian CPUs.
-
- Here's the recipe for configuring the endianness-related #defines
- to use more efficient CPU/OS/compiler dependent features to reduce
- code size. Note these only affect the integer arrays (tagged
- arrays) feature of QCBOR. All other endianness handling in
- QCBOR is integrated with code that also handles alignment and
- preferred encoding.
-
- The first option is to not define anything. This will work fine on
- with all CPU's, OS's and compilers. The code for encoding
- integers will be a little larger and slower.
-
- If your CPU is big-endian then define USEFULBUF_CONFIG_BIG_ENDIAN. This
- will give the most efficient code for big-endian CPUs. It will be small
- and efficient because there will be no byte swapping.
-
- Try defining USEFULBUF_CONFIG_HTON. This will work on most CPU's,
- OS's and compilers, but not all. On big-endian CPUs this should give
- the most efficient code, the same as USEFULBUF_CONFIG_BIG_ENDIAN
- does. On little-endian CPUs it should call the system-defined byte
- swapping method which is presumably implemented efficiently. In some
- cases, this will be a dedicated byte swap instruction like Intel's
- bswap.
-
- If USEFULBUF_CONFIG_HTON works and you know your CPU is
- little-endian, it is also good to define
- USEFULBUF_CONFIG_LITTLE_ENDIAN.
-
- if USEFULBUF_CONFIG_HTON doesn't work and you know your system is
- little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and
- USEFULBUF_CONFIG_BSWAP. This should call the most efficient
- system-defined byte swap method. However, note
- https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps
- this is fixed now. Often hton() and ntoh() will call the built-in
- __builtin_bswapXX()() function, so this size issue could affect
- USEFULBUF_CONFIG_HTON.
-
- Last, run the tests. They must all pass.
-
- These #define config options affect the inline implementation of
- UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
- also affect the 16-, 32-bit, float and double versions of these
- instructions. Since they are inline, they size effect is not in the
- UsefulBuf object code, but in the calling code.
-
- Summary:
- USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian.
- USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian.
- USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to
- handle big and little-endian with system option.
- USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
- use __builtin_bswapXX().
- */
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
-#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN"
-#endif
-
-
-#include <stdint.h> // for uint8_t, uint16_t....
-#include <string.h> // for strlen, memcpy, memmove, memset
-#include <stddef.h> // for size_t
-
-
-#ifdef USEFULBUF_CONFIG_HTON
-#include <arpa/inet.h> // for htons, htonl, htonll, ntohs...
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- @file UsefulBuf.h
-
- The goal of this code is to make buffer and pointer manipulation
- easier and safer when working with binary data.
-
- The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf
- structures are used to represent buffers rather than ad hoc pointers and
- lengths.
-
- With these it will often be possible to write code that does little
- or no direct pointer manipulation for copying and formatting
- data. For example, the QCBOR encoder was written using these and
- has no less pointer manipulation.
-
- While it is true that object code using these functions will be a
- little larger and slower than a white-knuckle clever use of pointers
- might be, but not by that much or enough to have an effect for most
- use cases. For security-oriented code this is highly
- worthwhile. Clarity, simplicity, reviewability and are more
- important.
-
- There are some extra sanity and double checks in this code to help
- catch coding errors and simple memory corruption. They are helpful,
- but not a substitute for proper code review, input validation and
- such.
-
- This code consists of a lot of inline functions and a few that are
- not. It should not generate very much object code, especially with
- the optimizer turned up to @c -Os or @c -O3.
- */
-
-
-/**
- @ref UsefulBufC and @ref UsefulBuf are simple data structures to hold
- a pointer and length for binary data. In C99 this data structure can
- be passed on the stack making a lot of code cleaner than carrying
- around a pointer and length as two parameters.
-
- This is also conducive to secure coding practice as the length is
- always carried with the pointer and the convention for handling a
- pointer and a length is clear.
-
- While it might be possible to write buffer and pointer code more
- efficiently in some use cases, the thought is that unless there is an
- extreme need for performance (e.g., you are building a
- gigabit-per-second IP router), it is probably better to have cleaner
- code you can be most certain about the security of.
-
- The non-const @ref UsefulBuf is usually used to refer a buffer to be
- filled in. The length is the size of the buffer.
-
- The const @ref UsefulBufC is usually used to refer to some data that
- has been filled in. The length is amount of valid data pointed to.
-
- A common use is to pass a @ref UsefulBuf to a function, the function
- fills it in, the function returns a @ref UsefulBufC. The pointer is
- the same in both.
-
- A @ref UsefulBuf is null, it has no value, when @c ptr in it is @c NULL.
-
- There are utility functions for the following:
- - Initializing
- - Create initialized const @ref UsefulBufC from compiler literals
- - Create initialized const @ref UsefulBufC from NULL-terminated string
- - Make an empty @ref UsefulBuf on the stack
- - Checking whether a @ref UsefulBuf is null, empty or both
- - Copying, copying with offset, copying head or tail
- - Comparing and finding substrings
-
- See also @ref UsefulOutBuf. It is a richer structure that has both
- the size of the valid data and the size of the buffer.
-
- @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it
- can go on the stack and be a function parameter or return value.
-
- Another way to look at it is this. C has the NULL-terminated string
- as a means for handling text strings, but no means or convention for
- binary strings. Other languages do have such means, Rust, an
- efficient compiled language, for example.
-
- @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his
- birthday. Eeyore's balloon fits beautifully, "it goes in and out
- like anything".
-*/
-typedef struct q_useful_buf_c {
- const void *ptr;
- size_t len;
-} UsefulBufC;
-
-
-/**
- This non-const @ref UsefulBuf is typically used for some allocated
- memory that is to be filled in. The @c len is the amount of memory,
- not the length of the valid data in the buffer.
- */
-typedef struct q_useful_buf {
- void *ptr;
- size_t len;
-} UsefulBuf;
-
-
-/**
- A null @ref UsefulBufC is one that has no value in the same way a @c
- NULL pointer has no value. A @ref UsefulBufC is @c NULL when the @c
- ptr field is @c NULL. It doesn't matter what @c len is. See
- UsefulBuf_IsEmpty() for the distinction between null and empty.
- */
-#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
-
-
-/**
- A null @ref UsefulBuf is one that has no memory associated the same
- way @c NULL points to nothing. It does not matter what @c len is.
- */
-#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
-
-
-/**
- @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not.
-
- @param[in] UB The UsefulBuf to check.
-
- @return 1 if it is @ref NULLUsefulBuf, 0 if not.
- */
-static inline int UsefulBuf_IsNULL(UsefulBuf UB);
-
-
-/**
- @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not.
-
- @param[in] UB The @ref UsefulBufC to check.
-
- @return 1 if it is @c NULLUsefulBufC, 0 if not.
- */
-static inline int UsefulBuf_IsNULLC(UsefulBufC UB);
-
-
-/**
- @brief Check if a @ref UsefulBuf is empty or not.
-
- @param[in] UB The @ref UsefulBuf to check.
-
- @return 1 if it is empty, 0 if not.
-
- An "empty" @ref UsefulBuf is one that has a value and can be
- considered to be set, but that value is of zero length. It is empty
- when @c len is zero. It doesn't matter what the @c ptr is.
-
- A lot of uses will not need to clearly distinguish a @c NULL @ref
- UsefulBuf from an empty one and can have the @c ptr @c NULL and the
- @c len 0. However if a use of @ref UsefulBuf needs to make a
- distinction then @c ptr should not be @c NULL when the @ref UsefulBuf
- is considered empty, but not @c NULL.
- */
-static inline int UsefulBuf_IsEmpty(UsefulBuf UB);
-
-
-/**
- @brief Check if a @ref UsefulBufC is empty or not.
-
- @param[in] UB The @ref UsefulBufC to check.
-
- @return 1 if it is empty, 0 if not.
- */
-static inline int UsefulBuf_IsEmptyC(UsefulBufC UB);
-
-
-/**
- @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty.
-
- @param[in] UB The @ref UsefulBuf to check.
-
- @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not.
- */
-static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB);
-
-
-/**
- @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty.
-
- @param[in] UB The @ref UsefulBufC to check.
-
- @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not.
- */
-static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB);
-
-
-/**
- @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC.
-
- @param[in] UB The @ref UsefulBuf to convert.
-
- @return A @ref UsefulBufC struct.
- */
-static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB);
-
-
-/**
- @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf.
-
- @param[in] UBC The @ref UsefulBuf to convert.
-
- @return A non-const @ref UsefulBuf struct.
- */
-static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
-
-
-/**
- Convert a literal string to a @ref UsefulBufC.
-
- @c szString must be a literal string that @c sizeof() works on. This
- is better for literal strings than UsefulBuf_FromSZ() because it
- generates less code. It will not work on non-literal strings.
-
- The terminating \0 (NULL) is NOT included in the length!
- */
-#define UsefulBuf_FROM_SZ_LITERAL(szString) \
- ((UsefulBufC) {(szString), sizeof(szString)-1})
-
-
-/**
- Convert a literal byte array to a @ref UsefulBufC.
-
- @c pBytes must be a literal string that @c sizeof() works on. It
- will not work on non-literal arrays.
- */
-#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
- ((UsefulBufC) {(pBytes), sizeof(pBytes)})
-
-
-/**
- Make an automatic variable named @c name of type @ref UsefulBuf and
- point it to a stack variable of the given @c size.
- */
-#define UsefulBuf_MAKE_STACK_UB(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
-
-
-/**
- Make a byte array in to a @ref UsefulBuf. This is usually used on
- stack variables or static variables. Also see @ref
- UsefulBuf_MAKE_STACK_UB.
- */
-#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
- ((UsefulBuf) {(pBytes), sizeof(pBytes)})
-
-
-/**
- @brief Convert a NULL-terminated string to a @ref UsefulBufC.
-
- @param[in] szString The string to convert.
-
- @return A @ref UsefulBufC struct.
-
- @c UsefulBufC.ptr points to the string so its lifetime must be
- maintained.
-
- The terminating \0 (NULL) is NOT included in the length.
- */
-static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
-
-
-/**
- @brief Copy one @ref UsefulBuf into another at an offset.
-
- @param[in] Dest Destination buffer to copy into.
- @param[in] uOffset The byte offset in @c Dest at which to copy to.
- @param[in] Src The bytes to copy.
-
- @return Pointer and length of the copy or @ref NULLUsefulBufC.
-
- This fails and returns @ref NULLUsefulBufC if @c offset is beyond the
- size of @c Dest.
-
- This fails and returns @ref NULLUsefulBufC if the @c Src length plus
- @c uOffset is greater than the length of @c Dest.
-
- The results are undefined if @c Dest and @c Src overlap.
-
- This assumes that there is valid data in @c Dest up to @c
- uOffset. The @ref UsefulBufC returned starts at the beginning of @c
- Dest and goes to @c Src.len @c + @c uOffset.
- */
-UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
-
-
-/**
- @brief Copy one @ref UsefulBuf into another.
-
- @param[in] Dest The destination buffer to copy into.
- @param[out] Src The source to copy from.
-
- @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
- on failure.
-
- This fails if @c Src.len is greater than @c Dest.len.
-
- Note that like @c memcpy(), the pointers are not checked and this
- will crash rather than return @ref NULLUsefulBufC if they are @c
- NULL or invalid.
-
- The results are undefined if @c Dest and @c Src overlap.
- */
-static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
-
-
-/**
- @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0.
-
- @param[in] pDest The destination buffer to copy into.
- @param[in] value The value to set the bytes to.
-
- Note that like @c memset(), the pointer in @c pDest is not checked
- and this will crash if @c NULL or invalid.
- */
-static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value);
-
-
-/**
- @brief Copy a pointer into a @ref UsefulBuf.
-
- @param[in,out] Dest The destination buffer to copy into.
- @param[in] ptr The source to copy from.
- @param[in] uLen Length of the source; amount to copy.
-
- @return 0 on success, 1 on failure.
-
- This fails and returns @ref NULLUsefulBufC if @c uLen is greater than
- @c pDest->len.
-
- Note that like @c memcpy(), the pointers are not checked and this
- will crash, rather than return 1 if they are @c NULL or invalid.
- */
-static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest,
- const void *ptr,
- size_t uLen);
-
-
-/**
- @brief Returns a truncation of a @ref UsefulBufC.
-
- @param[in] UB The buffer to get the head of.
- @param[in] uAmount The number of bytes in the head.
-
- @return A @ref UsefulBufC that is the head of UB.
- */
-static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount);
-
-
-/**
- @brief Returns bytes from the end of a @ref UsefulBufC.
-
- @param[in] UB The buffer to get the tail of.
- @param[in] uAmount The offset from the start where the tail is to begin.
-
- @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC
- if @c uAmount is greater than the length of the @ref UsefulBufC.
-
- If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will
- be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length
- of the tail.
- */
-static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount);
-
-
-/**
- @brief Compare one @ref UsefulBufC to another.
-
- @param[in] UB1 The first buffer to compare.
- @param[in] UB2 The second buffer to compare.
-
- @return 0, positive or negative value.
-
- Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is
- less than @c UB2 if it is shorter or the first byte that is not the
- same is less.
-
- Returns 0 if the inputs are the same.
-
- Returns a positive value if @c UB2 is less than @c UB1.
-
- All that is of significance is that the result is positive, negative
- or 0. (This doesn't return the difference between the first
- non-matching byte like @c memcmp() ).
- */
-int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
-
-
-/**
- @brief Find first byte that is not a particular byte value.
-
- @param[in] UB The destination buffer for byte comparison.
- @param[in] uValue The byte value to compare to.
-
- @return Offset of first byte that isn't @c uValue or
- @c SIZE_MAX if all bytes are @c uValue.
-
- Note that unlike most comparison functions, 0
- does not indicate a successful comparison, so the
- test for match is:
-
- UsefulBuf_IsValue(...) == SIZE_MAX
-
- If @c UB is null or empty, there is no match
- and 0 is returned.
- */
-size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
-
-
-/**
- @brief Find one @ref UsefulBufC in another.
-
- @param[in] BytesToSearch Buffer to search through.
- @param[in] BytesToFind Buffer with bytes to be found.
-
- @return Position of found bytes or @c SIZE_MAX if not found.
- */
-size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
-
-
-#if 1 // NOT_DEPRECATED
-/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
-#define SZLiteralToUsefulBufC(szString) \
- ((UsefulBufC) {(szString), sizeof(szString)-1})
-
-/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
-#define MakeUsefulBufOnStack(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
-
-/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
-#define ByteArrayLiteralToUsefulBufC(pBytes) \
- ((UsefulBufC) {(pBytes), sizeof(pBytes)})
-
-/** Deprecated function; use UsefulBuf_Unconst() instead */
-static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
-{
- return (UsefulBuf){(void *)UBC.ptr, UBC.len};
-}
-#endif
-
-
-
-
-/**
- @brief Copy a @c float to a @c uint32_t.
-
- @param[in] f Float value to copy.
-
- @return A @c uint32_t with the float bits.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f);
-
-
-/**
- @brief Copy a @c double to a @c uint64_t.
-
- @param[in] d Double value to copy.
-
- @return A @c uint64_t with the double bits.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d);
-
-
-/**
- @brief Copy a @c uint32_t to a @c float.
-
- @param[in] u32 Integer value to copy.
-
- @return The value as a @c float.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32);
-
-
-/**
- @brief Copy a @c uint64_t to a @c double.
-
- @param[in] u64 Integer value to copy.
-
- @return The value as a @c double.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
-
-
-
-
-/**
- UsefulOutBuf is a structure and functions (an object) for serializing
- data into a buffer when encoding a network protocol or writing data
- to file.
-
- The main idea is that all the pointer manipulation is performed by
- @ref UsefulOutBuf functions so the caller doesn't have to do any
- pointer manipulation. The pointer manipulation is centralized. This
- code will have been reviewed and written carefully so it spares the
- caller of much of this work and results in safer code with less work.
-
- The @ref UsefulOutBuf methods that add data to the output buffer
- always check the length and will never write off the end of the
- output buffer. If an attempt to add data that will not fit is made,
- an internal error flag will be set and further attempts to add data
- will not do anything.
-
- There is no way to ever write off the end of that buffer when calling
- the @c UsefulOutBuf_AddXxx() and @c UsefulOutBuf_InsertXxx()
- functions.
-
- The functions to add data do not return an error. The working model
- is that all calls to add data are made without an error check. Errors
- are just checked for once after all the data has been added before the
- and before serialized data is to be used. This makes the calling code
- cleaner.
-
- There is a utility function to get the error status anytime along the
- way for a special circumstance. There are functions to see how much
- room is left and see if some data will fit too, but their use is
- generally not necessary.
-
- The general call flow is:
-
- - Initialize by calling @ref UsefulOutBuf_Init(). The output
- buffer given to it can be from the heap, stack or
- otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience macro
- that makes a buffer on the stack and initializes it.
-
- - Call methods like UsefulOutBuf_InsertString(),
- UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf()
- to output data. The append calls add data to the end of the
- valid data. The insert calls take a position argument.
-
- - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see
- there were no errors and to get the serialized output bytes.
-
- @ref UsefulOutBuf can be used in a size calculation mode to calculate
- the size of output that would be generated. This is useful to
- calculate the size of a buffer that is to be allocated to hold the
- output. To use @ref UsefulOutBuf in this mode, call
- UsefulOutBuf_Init() with the @c Storage @ref UsefulBuf as
- @c (UsefulBuf){NULL,MAX_UINT32}. Then call all the Insert and Add
- functions. No attempt will made to actually copy data, so only the
- lengths have to be valid for these calls.
-
- Methods like UsefulOutBuf_InsertUint64() always output in network
- bytes order (big endian).
-
- The possible errors are:
- - The @ref UsefulOutBuf was not initialized or was corrupted.
-
- - An attempt was made to add data that will not fit.
-
- - An attempt was made to insert data at a position beyond the end of
- the buffer.
-
- - An attempt was made to insert data at a position beyond the valid
- data in the buffer.
-
- Some inexpensive simple sanity checks are performed before every data
- addition to guard against use of an uninitialized or corrupted
- UsefulOutBuf.
-
- This has been used to create a CBOR encoder. The CBOR encoder has
- almost no pointer manipulation in it, is easier to read, and easier
- to review.
-
- A @ref UsefulOutBuf is small and can go on the stack:
- - 32 bytes (27 bytes plus alignment padding) on a 64-bit machine
- - 16 bytes (15 bytes plus alignment padding) on a 32-bit machines
- */
-typedef struct useful_out_buf {
- // PRIVATE DATA STRUCTURE
- UsefulBuf UB; // Memory that is being output to
- size_t data_len; // length of the data
- uint16_t magic; // Used to detect corruption and lack of initialization
- uint8_t err;
-} UsefulOutBuf;
-
-
-/**
- @brief Initialize and supply the actual output buffer.
-
- @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
- @param[in] Storage Buffer to output into.
-
- Initializes the @ref UsefulOutBuf with storage. Sets the current
- position to the beginning of the buffer clears the error.
-
- This must be called before the @ref UsefulOutBuf is used.
- */
-void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage);
-
-
-/**
- Convenience macro to make a @ref UsefulOutBuf on the stack and
- initialize it with a stack buffer of the given size. The variable
- will be named @c name.
- */
-#define UsefulOutBuf_MakeOnStack(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulOutBuf name;\
- UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)});
-
-
-/**
- @brief Reset a @ref UsefulOutBuf for re use
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
-
- This sets the amount of data in the output buffer to none and clears
- the error state.
-
- The output buffer is still the same one and size as from the
- UsefulOutBuf_Init() call.
-
- This doesn't zero the data, just resets to 0 bytes of valid data.
- */
-static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns position of end of data in the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return position of end of data.
-
- On a freshly initialized @ref UsefulOutBuf with no data added, this
- will return 0. After 10 bytes have been added, it will return 10 and
- so on.
-
- Generally callers will not need this function for most uses of @ref
- UsefulOutBuf.
- */
-static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns whether any data has been added to the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return 1 if output position is at start.
- */
-static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Inserts bytes into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] NewData The bytes to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- @c NewData is the pointer and length for the bytes to be added to the
- output buffer. There must be room in the output buffer for all of @c
- NewData or an error will occur.
-
- The insertion point must be between 0 and the current valid data. If
- not, an error will occur. Appending data to the output buffer is
- achieved by inserting at the end of the valid data. This can be
- retrieved by calling UsefulOutBuf_GetEndPosition().
-
- When insertion is performed, the bytes between the insertion point
- and the end of data previously added to the output buffer are slid to
- the right to make room for the new data.
-
- Overlapping buffers are OK. @c NewData can point to data in the
- output buffer.
-
- If an error occurs an error state is set in the @ref UsefulOutBuf. No
- error is returned. All subsequent attempts to add data will do
- nothing.
-
- The intended use is that all additions are made without checking for
- an error. The error will be taken into account when
- UsefulOutBuf_OutUBuf() returns @c NullUsefulBufC.
- UsefulOutBuf_GetError() can also be called to check for an error.
- */
-void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf,
- UsefulBufC NewData,
- size_t uPos);
-
-
-/**
- @brief Insert a data buffer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] pBytes Pointer to the bytes to insert
- @param[in] uLen Length of the bytes to insert
- @param[in] uPos Index in output buffer at which to insert
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a pointer and length is passed in rather than an
- @ref UsefulBufC.
- */
-static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf,
- const void *pBytes,
- size_t uLen,
- size_t uPos);
-
-
-/**
- @brief Insert a NULL-terminated string into the UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] szString NULL-terminated string to insert.
- @param[in] uPos Index in output buffer at which to insert.
- */
-static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf,
- const char *szString,
- size_t uPos);
-
-
-/**
- @brief Insert a byte into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the UsefulOutBuf.
- @param[in] byte Bytes to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a single byte is to be inserted.
- */
-static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf,
- uint8_t byte,
- size_t uPos);
-
-
-/**
- @brief Insert a 16-bit integer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger16 Integer to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a two-byte integer is to be inserted.
-
- The integer will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf,
- uint16_t uInteger16,
- size_t uPos);
-
-
-/**
- @brief Insert a 32-bit integer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger32 Integer to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a four-byte integer is to be inserted.
-
- The integer will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf,
- uint32_t uInteger32,
- size_t uPos);
-
-
-/**
- @brief Insert a 64-bit integer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger64 Integer to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being an eight-byte integer is to be inserted.
-
- The integer will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf,
- uint64_t uInteger64,
- size_t uPos);
-
-
-/**
- @brief Insert a @c float into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] f @c float to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a @c float is to be inserted.
-
- The @c float will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf,
- float f,
- size_t uPos);
-
-
-/**
- @brief Insert a @c double into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] d @c double to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a @c double is to be inserted.
-
- The @c double will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
- double d,
- size_t uPos);
-
-
-/**
- @brief Append a @ref UsefulBuf into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] NewData The @ref UsefulBuf with the bytes to append.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
- with the insertion point at the end of the valid data.
-*/
-static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf,
- UsefulBufC NewData);
-
-
-/**
- @brief Append bytes to the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] pBytes Pointer to bytes to append.
- @param[in] uLen Length of @c pBytes to append.
-
- See UsefulOutBuf_InsertData() for details. This does the same
- with the insertion point at the end of the valid data.
- */
-static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf,
- const void *pBytes,
- size_t uLen);
-
-
-/**
- @brief Append a NULL-terminated string to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] szString NULL-terminated string to append.
- */
-static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf,
- const char *szString);
-
-
-/**
- @brief Append a byte to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] byte Bytes to append.
-
- See UsefulOutBuf_InsertByte() for details. This does the same
- with the insertion point at the end of the valid data.
- */
-static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf,
- uint8_t byte);
-
-
-/**
- @brief Append an integer to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger16 Integer to append.
-
- See UsefulOutBuf_InsertUint16() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The integer will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf,
- uint16_t uInteger16);
-
-
-/**
- @brief Append an integer to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger32 Integer to append.
-
- See UsefulOutBuf_InsertUint32() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The integer will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf,
- uint32_t uInteger32);
-
-
-/**
- @brief Append an integer to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger64 Integer to append.
-
- See UsefulOutBuf_InsertUint64() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The integer will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf,
- uint64_t uInteger64);
-
-
-/**
- @brief Append a @c float to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] f @c float to append.
-
- See UsefulOutBuf_InsertFloat() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The float will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf,
- float f);
-
-
-/**
- @brief Append a @c double to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] d @c double to append.
-
- See UsefulOutBuf_InsertDouble() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The double will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
- double d);
-
-
-/**
- @brief Returns the current error status.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return 0 if all OK, 1 on error.
-
- This is the error status since the call to either
- UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error
- state it will stay until one of those functions is called.
-
- Possible error conditions are:
- - bytes to be inserted will not fit
- - insertion point is out of buffer or past valid data
- - current position is off end of buffer (probably corrupted or uninitialized)
- - detect corruption / uninitialized by bad magic number
- */
-static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns number of bytes unused used in the output buffer.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return Number of unused bytes or zero.
-
- Because of the error handling strategy and checks in
- UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
- this.
- */
-static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
- @param[in] uLen Number of bytes for which to check
-
- @return 1 if @c uLen bytes will fit, 0 if not.
-
- Because of the error handling strategy and checks in
- UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
- this.
- */
-static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen);
-
-
- /**
- @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
-
- @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
-
- Giving a @c NULL output buffer to UsefulOutBuf_Init() is used
- when just calculating the length of the encoded data.
- */
-static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns the resulting valid data in a UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return The valid data in @ref UsefulOutBuf or
- @ref NULLUsefulBufC if there was an error adding data.
-
- The storage for the returned data is the @c Storage parameter passed
- to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
-
- This can be called anytime and many times to get intermediate
- results. It doesn't change the data or reset the current position
- so you can keep adding data.
- */
-UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Copies the valid data into a supplied buffer
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[out] Dest The destination buffer to copy into.
-
- @return Pointer and length of copied data or @c NULLUsefulBufC
- if it will not fit in the @c Dest buffer.
-
- This is the same as UsefulOutBuf_OutUBuf() except it copies the data
- to @c Dest.
-*/
-UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
-
-
-
-
-/**
- @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf and is
- for parsing data read or received. Initialize it with the data from
- the network. Then use the functions here to get data chunks of
- various types. A position cursor is maintained internally.
-
- As long as the functions here are used, there will never be a
- reference off the end of the given buffer. This is true even if they
- care called incorrectly, an attempt is made to seek of the end of the
- buffer, etc. This makes it easier to write safe and correct code.
- For example, the QCBOR decoder implementation is safer and easier to
- review through its use of @ref UsefulInputBuf.
-
- @ref UsefulInputBuf maintains an internal error state. The
- intended use is that data chunks can be fetched without error
- checking until the end. Once data has been requested off the end of
- the buffer, the error state is entered. In the error state the
- @c UsefulInputBuf_GetXxxx() functions return 0, or @c NULL or
- @ref NULLUsefulBufC. As long as null are not dereferenced, the
- error check can be put off until the end, simplifying the calling
- code.
-
- The integer and float parsing expects network byte order (big
- endian). Network byte order is what is used by TCP/IP, CBOR and most
- internet protocols.
-
- Lots of inline functions are used to keep code size down. The code
- optimizer, particularly with the @c -Os or @c -O3, also reduces code
- size a lot. The only non-inline code is UsefulInputBuf_GetBytes()
- which is less than 100 bytes so use of @ref UsefulInputBuf doesn't
- add much code for all the messy hard-to-get right issues with parsing
- in C that is solves.
-
- The parse context size is:
- - 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
- - 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
- */
-typedef struct useful_input_buf {
- // PRIVATE DATA STRUCTURE
- UsefulBufC UB; // Data being parsed
- size_t cursor; // Current offset in data being parse
- uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf
- uint8_t err; // Set request goes off end or magic number is bad
-} UsefulInputBuf;
-
-#define UIB_MAGIC (0xB00F)
-
-
-/**
- @brief Initialize the UsefulInputBuf structure before use.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf instance.
- @param[in] UB The data to parse.
- */
-static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB);
-
-
-/**
- @brief Returns current position in input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return Integer position of the cursor.
-
- The position that the next bytes will be returned from.
- */
-static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Sets the current position in input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uPos Position to set to.
-
- If the position is off the end of the input buffer, the error state
- is entered, and all functions will do nothing.
-
- Seeking to a valid position in the buffer will not reset the error
- state. Only re initialization will do that.
- */
-static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos);
-
-
-/**
- @brief Returns the number of bytes from the cursor to the end of the buffer,
- the unconsumed bytes.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return Number of bytes unconsumed or 0 on error.
-
- This is a critical function for input length validation.
-
- Returns 0 if the cursor it invalid or corruption of the structure is
- detected.
- */
-static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Check if there are any unconsumed bytes.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uLen Number of bytes to check availability for.
-
- @return 1 if @c uLen bytes are available after the cursor, and 0 if not.
- */
-static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
-
-
-/**
- @brief Get pointer to bytes out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uNum Number of bytes to get.
-
- @return Pointer to bytes.
-
- This consumes @c uNum bytes from the input buffer. It returns a
- pointer to the start of the @c uNum bytes.
-
- If there are not @c uNum bytes in the input buffer, @c NULL will be
- returned and an error will be set.
-
- It advances the current position by @c uNum bytes.
- */
-const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum);
-
-
-/**
- @brief Get @ref UsefulBuf out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uNum Number of bytes to get.
-
- @return A @ref UsefulBufC with ptr and length of bytes consumed.
-
- This consumes @c uNum bytes from the input buffer and returns the
- pointer and length for them as a @ref UsefulBufC. The length returned
- will always be @c uNum.
-
- If there are not @c uNum bytes in the input buffer, @ref NULLUsefulBufC
- will be returned and the error state is set.
-
- It advances the current position by @c uNum bytes.
- */
-static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum);
-
-
-/**
- @brief Get a byte out of the input buffer.
-
- @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
-
- @return The byte.
-
- This consumes 1 byte from the input buffer. It returns the byte.
-
- If there is not 1 byte in the buffer, 0 will be returned for the byte
- and an error set internally. You must check the error at some point
- to know whether the 0 was the real value or just returned in error,
- but you may not have to do that right away. Check the error state
- with UsefulInputBuf_GetError(). You can also know you are in the
- error state if UsefulInputBuf_GetBytes() returns @c NULL or the @c
- ptr from UsefulInputBuf_GetUsefulBuf() is @c NULL.
-
- It advances the current position by 1 byte.
- */
-static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a @c uint16_t out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The @c uint16_t.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a @c uint16_t and two bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a uint32_t out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The @c uint32_t.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a @c uint32_t and four bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a uint64_t out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The uint64_t.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a @c uint64_t and eight bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a float out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The float.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a float and four bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a double out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The double.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a double and eight bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get the error status.
-
- @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
-
- @return 0 if there is no error, 1 if there is.
-
- The error state is entered for one of these reasons:
- - Attempt to fetch data past the end of the buffer
- - Attempt to seek to a position past the end of the buffer
- - Attempt to get data from an uninitialized or corrupt instance
- of @ref UsefulInputBuf
-
- Once in the error state, it can only be cleared by calling
- UsefulInputBuf_Init().
-
- You may be able to only check the error state at the end after all
- the UsefulInputBuf_GetXxxx() calls have been made, but if what you
- get later depends on what you get sooner you cannot. For example,
- if you get a length or count of following items you will have to
- check the error.
- */
-static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf);
-
-
-
-
-/*----------------------------------------------------------
- Inline implementations.
- */
-static inline int UsefulBuf_IsNULL(UsefulBuf UB)
-{
- return !UB.ptr;
-}
-
-
-static inline int UsefulBuf_IsNULLC(UsefulBufC UB)
-{
- return !UB.ptr;
-}
-
-
-static inline int UsefulBuf_IsEmpty(UsefulBuf UB)
-{
- return !UB.len;
-}
-
-
-static inline int UsefulBuf_IsEmptyC(UsefulBufC UB)
-{
- return !UB.len;
-}
-
-
-static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB)
-{
- return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
-}
-
-
-static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB)
-{
- return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
-}
-
-
-static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
-{
- return (UsefulBufC){UB.ptr, UB.len};
-}
-
-
-static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
-{
- return (UsefulBuf){(void *)UBC.ptr, UBC.len};
-}
-
-
-static inline UsefulBufC UsefulBuf_FromSZ(const char *szString)
-{
- return ((UsefulBufC) {szString, strlen(szString)});
-}
-
-
-static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src)
-{
- return UsefulBuf_CopyOffset(Dest, 0, Src);
-}
-
-
-static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
-{
- memset(pDest.ptr, value, pDest.len);
- return (UsefulBufC){pDest.ptr, pDest.len};
-}
-
-
-static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
-{
- return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
-}
-
-
-static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
-{
- if(uAmount > UB.len) {
- return NULLUsefulBufC;
- }
- return (UsefulBufC){UB.ptr, uAmount};
-}
-
-
-static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
-{
- UsefulBufC ReturnValue;
-
- if(uAmount > UB.len) {
- ReturnValue = NULLUsefulBufC;
- } else if(UB.ptr == NULL) {
- ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
- } else {
- ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
- }
-
- return ReturnValue;
-}
-
-
-
-static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
-{
- uint32_t u32;
- memcpy(&u32, &f, sizeof(uint32_t));
- return u32;
-}
-
-static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
-{
- uint64_t u64;
- memcpy(&u64, &d, sizeof(uint64_t));
- return u64;
-}
-
-static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
-{
- double d;
- memcpy(&d, &u64, sizeof(uint64_t));
- return d;
-}
-
-static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
-{
- float f;
- memcpy(&f, &u32, sizeof(uint32_t));
- return f;
-}
-
-
-
-
-static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe)
-{
- pMe->data_len = 0;
- pMe->err = 0;
-}
-
-
-static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe)
-{
- return pMe->data_len;
-}
-
-
-static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe)
-{
- return 0 == pMe->data_len;
-}
-
-
-static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe,
- const void *pBytes,
- size_t uLen,
- size_t uPos)
-{
- UsefulBufC Data = {pBytes, uLen};
- UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe,
- const char *szString,
- size_t uPos)
-{
- UsefulOutBuf_InsertUsefulBuf(pMe,
- (UsefulBufC){szString, strlen(szString)},
- uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me,
- uint8_t byte,
- size_t uPos)
-{
- UsefulOutBuf_InsertData(me, &byte, 1, uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
- uint16_t uInteger16,
- size_t uPos)
-{
- // See UsefulOutBuf_InsertUint64() for comments on this code
-
- const void *pBytes;
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- pBytes = &uInteger16;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- uint16_t uTmp = htons(uInteger16);
- pBytes = &uTmp;
-
-#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
- uint16_t uTmp = __builtin_bswap16(uInteger16);
- pBytes = &uTmp;
-
-#else
- uint8_t aTmp[2];
-
- aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
- aTmp[1] = (uint8_t)(uInteger16 & 0xff);
-
- pBytes = aTmp;
-#endif
-
- UsefulOutBuf_InsertData(me, pBytes, 2, uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
- uint32_t uInteger32,
- size_t uPos)
-{
- // See UsefulOutBuf_InsertUint64() for comments on this code
-
- const void *pBytes;
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- pBytes = &uInteger32;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- uint32_t uTmp = htonl(uInteger32);
- pBytes = &uTmp;
-
-#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
- uint32_t uTmp = __builtin_bswap32(uInteger32);
-
- pBytes = &uTmp;
-
-#else
- uint8_t aTmp[4];
-
- aTmp[0] = (uint8_t)((uInteger32 & 0xff000000) >> 24);
- aTmp[1] = (uint8_t)((uInteger32 & 0xff0000) >> 16);
- aTmp[2] = (uint8_t)((uInteger32 & 0xff00) >> 8);
- aTmp[3] = (uint8_t)(uInteger32 & 0xff);
-
- pBytes = aTmp;
-#endif
-
- UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
-}
-
-static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
- uint64_t uInteger64,
- size_t uPos)
-{
- const void *pBytes;
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- // We have been told explicitly we are running on a big-endian
- // machine. Network byte order is big endian, so just copy. There
- // is no issue with alignment here because uInter64 is always
- // aligned (and it doesn't matter if pBytes is aligned).
- pBytes = &uInteger64;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- // Use system function to handle big- and little-endian. This works
- // on both big- and little-endian machines, but hton() is not
- // always available or in a standard place so it is not used by
- // default. With some compilers and CPUs the code for this is very
- // compact through use of a special swap instruction and on
- // big-endian machines hton() will reduce to nothing.
- uint64_t uTmp = htonll(uInteger64);
-
- pBytes = &uTmp;
-
-#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
- // Use built-in function for byte swapping. This usually compiles
- // to an efficient special byte swap instruction. Unlike hton() it
- // does not do this conditionally on the CPU endianness, so this
- // code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN
- uint64_t uTmp = __builtin_bswap64(uInteger64);
-
- pBytes = &uTmp;
-
-#else
- // Default which works on every CPU with no dependency on anything
- // from the CPU, compiler, libraries or OS. This always works, but
- // it is usually a little larger and slower than hton().
- uint8_t aTmp[8];
-
- aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56);
- aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48);
- aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40);
- aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32);
- aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24);
- aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16);
- aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8);
- aTmp[7] = (uint8_t)(uInteger64 & 0xff);
-
- pBytes = aTmp;
-#endif
-
- // Do the insert
- UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
- float f,
- size_t uPos)
-{
- UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe,
- double d,
- size_t uPos)
-{
- UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
-}
-
-
-static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
- UsefulBufC NewData)
-{
- // An append is just a insert at the end
- UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe,
- const void *pBytes,
- size_t uLen)
-{
- UsefulBufC Data = {pBytes, uLen};
- UsefulOutBuf_AppendUsefulBuf(pMe, Data);
-}
-
-
-static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe,
- const char *szString)
-{
- UsefulOutBuf_AppendUsefulBuf(pMe, (UsefulBufC){szString, strlen(szString)});
-}
-
-
-static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe,
- uint8_t byte)
-{
- UsefulOutBuf_AppendData(pMe, &byte, 1);
-}
-
-
-static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe,
- uint16_t uInteger16)
-{
- UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe,
- uint32_t uInteger32)
-{
- UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe,
- uint64_t uInteger64)
-{
- UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
- float f)
-{
- UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe,
- double d)
-{
- UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
-{
- return pMe->err;
-}
-
-
-static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe)
-{
- return pMe->UB.len - pMe->data_len;
-}
-
-
-static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen)
-{
- return uLen <= UsefulOutBuf_RoomLeft(pMe);
-}
-
-
-static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe)
-{
- return pMe->UB.ptr == NULL;
-}
-
-
-
-static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
-{
- pMe->cursor = 0;
- pMe->err = 0;
- pMe->magic = UIB_MAGIC;
- pMe->UB = UB;
-}
-
-static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe)
-{
- return pMe->cursor;
-}
-
-
-static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos)
-{
- if(uPos > pMe->UB.len) {
- pMe->err = 1;
- } else {
- pMe->cursor = uPos;
- }
-}
-
-
-static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe)
-{
- // Code Reviewers: THIS FUNCTION DOES POINTER MATH
-
- // Magic number is messed up. Either the structure got overwritten
- // or was never initialized.
- if(pMe->magic != UIB_MAGIC) {
- return 0;
- }
-
- // The cursor is off the end of the input buffer given.
- // Presuming there are no bugs in this code, this should never happen.
- // If it so, the struct was corrupted. The check is retained as
- // as a defense in case there is a bug in this code or the struct is
- // corrupted.
- if(pMe->cursor > pMe->UB.len) {
- return 0;
- }
-
- // subtraction can't go neative because of check above
- return pMe->UB.len - pMe->cursor;
-}
-
-
-static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen)
-{
- return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0;
-}
-
-
-static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
-{
- const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
- if(!pResult) {
- return NULLUsefulBufC;
- } else {
- return (UsefulBufC){pResult, uNum};
- }
-}
-
-
-static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
-{
- const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
-
- // The ternery operator is subject to integer promotion, because the
- // operands are smaller than int, so cast back to uint8_t is needed
- // to be completely explicit about types (for static analyzers)
- return (uint8_t)(pResult ? *(uint8_t *)pResult : 0);
-}
-
-static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
-{
- const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t));
-
- if(!pResult) {
- return 0;
- }
-
- // See UsefulInputBuf_GetUint64() for comments on this code
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
- uint16_t uTmp;
- memcpy(&uTmp, pResult, sizeof(uint16_t));
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- return uTmp;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- return ntohs(uTmp);
-
-#else
- return __builtin_bswap16(uTmp);
-
-#endif
-
-#else
-
- // The operations here are subject to integer promotion because the
- // operands are smaller than int. They will be promoted to unsigned
- // int for the shift and addition. The cast back to uint16_t is is needed
- // to be completely explicit about types (for static analyzers)
- return (uint16_t)((pResult[0] << 8) + pResult[1]);
-
-#endif
-}
-
-
-static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe)
-{
- const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t));
-
- if(!pResult) {
- return 0;
- }
-
- // See UsefulInputBuf_GetUint64() for comments on this code
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
- uint32_t uTmp;
- memcpy(&uTmp, pResult, sizeof(uint32_t));
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- return uTmp;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- return ntohl(uTmp);
-
-#else
- return __builtin_bswap32(uTmp);
-
-#endif
-
-#else
- return ((uint32_t)pResult[0]<<24) +
- ((uint32_t)pResult[1]<<16) +
- ((uint32_t)pResult[2]<<8) +
- (uint32_t)pResult[3];
-#endif
-}
-
-
-static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe)
-{
- const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t));
-
- if(!pResult) {
- return 0;
- }
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
- // pResult will probably not be aligned. This memcpy() moves the
- // bytes into a temp variable safely for CPUs that can or can't do
- // unaligned memory access. Many compilers will optimize the
- // memcpy() into a simple move instruction.
- uint64_t uTmp;
- memcpy(&uTmp, pResult, sizeof(uint64_t));
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- // We have been told expliclity this is a big-endian CPU. Since
- // network byte order is big-endian, there is nothing to do.
-
- return uTmp;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- // We have been told to use ntoh(), the system function to handle
- // big- and little-endian. This works on both big- and
- // little-endian machines, but ntoh() is not always available or in
- // a standard place so it is not used by default. On some CPUs the
- // code for this is very compact through use of a special swap
- // instruction.
-
- return ntohll(uTmp);
-
-#else
- // Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and
- // USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON).
- // __builtin_bswap64() and friends are not conditional on CPU
- // endianness so this must only be used on little-endian machines.
-
- return __builtin_bswap64(uTmp);
-
-
-#endif
-
-#else
- // This is the default code that works on every CPU and every
- // endianness with no dependency on ntoh(). This works on CPUs
- // that either allow or do not allow unaligned access. It will
- // always work, but usually is a little less efficient than ntoh().
-
- return ((uint64_t)pResult[0]<<56) +
- ((uint64_t)pResult[1]<<48) +
- ((uint64_t)pResult[2]<<40) +
- ((uint64_t)pResult[3]<<32) +
- ((uint64_t)pResult[4]<<24) +
- ((uint64_t)pResult[5]<<16) +
- ((uint64_t)pResult[6]<<8) +
- (uint64_t)pResult[7];
-#endif
-}
-
-
-static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
-{
- uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
-
- return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
-}
-
-
-static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe)
-{
- uint64_t uResult = UsefulInputBuf_GetUint64(pMe);
-
- return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
-}
-
-
-static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
-{
- return pMe->err;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _UsefulBuf_h
-
-
+#include "qcbor/UsefulBuf.h"
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 4f0c068..bef0dcd 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -3,3721 +3,33 @@
Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors, nor the name "Laurence Lundblade" may be used to
- endorse or promote products derived from this software without
- specific prior written permission.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
-/*=============================================================================
- FILE: qcbor.h
-
- DESCRIPTION: This is the full public API and data structures for QCBOR
-
- EDIT HISTORY FOR FILE:
-
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
-
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 02/07/2020 llundblade QCBOREncode_EncodeHead() and other for bstr hashing.
- 01/25/2020 llundblade Cleaner handling of too-long encoded string input.
- 01/08/2020 llundblade Documentation corrections & improved code formatting.
- 12/30/19 llundblade Add support for decimal fractions and bigfloats.
- 08/7/19 llundblade Better handling of not well-formed encode and decode.
- 07/31/19 llundblade New error code for better end of data handling.
- 7/25/19 janjongboom Add indefinite length encoding for maps and arrays.
- 05/26/19 llundblade Add QCBOREncode_GetErrorState() and _IsBufferNULL().
- 04/26/19 llundblade Big documentation & style update. No interface change.
- 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug.
- 12/18/18 llundblade Move decode malloc optional code to separate repo.
- 12/13/18 llundblade Documentatation improvements.
- 11/29/18 llundblade Rework to simpler handling of tags and labels.
- 11/9/18 llundblade Error codes are now enums.
- 11/1/18 llundblade Floating support.
- 10/31/18 llundblade Switch to one license that is almost BSD-3.
- 10/15/18 llundblade indefinite-length maps and arrays supported
- 10/8/18 llundblade indefinite-length strings supported
- 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
- 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE.
- 03/01/17 llundbla More data types; decoding improvements and fixes.
- 11/13/16 llundbla Integrate most TZ changes back into github version.
- 09/30/16 gkanike Porting to TZ.
- 03/15/16 llundbla Initial Version.
-
- =============================================================================*/
-
-#ifndef __QCBOR__qcbor__
-#define __QCBOR__qcbor__
-
-
-/* ===========================================================================
- BEGINNING OF PRIVATE PART OF THIS FILE
-
- Caller of QCBOR should not reference any of the details below up until
- the start of the public part.
- ========================================================================== */
-
-/*
- Standard integer types are used in the interface to be precise about
- sizes to be better at preventing underflow/overflow errors.
- */
-#include <stdint.h>
-#include <stdbool.h>
-#include "UsefulBuf.h"
-
-#ifdef __cplusplus
-extern "C" {
-#ifdef 0
-} // Keep editor indention formatting happy
-#endif
-#endif
-
-/*
- The maxium nesting of arrays and maps when encoding or decoding.
- (Further down in the file there is a definition that refers to this
- that is public. This is done this way so there can be a nice
- separation of public and private parts in this file.
-*/
-#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255
-
-
-/* The largest offset to the start of an array or map. It is slightly
- less than UINT32_MAX so the error condition can be tests on 32-bit machines.
- UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t.
-
- This will cause trouble on a machine where size_t is less than 32-bits.
- */
-#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100)
-
-/*
- PRIVATE DATA STRUCTURE
-
- Holds the data for tracking array and map nesting during encoding. Pairs up
- with the Nesting_xxx functions to make an "object" to handle nesting encoding.
-
- uStart is a uint32_t instead of a size_t to keep the size of this
- struct down so it can be on the stack without any concern. It would be about
- double if size_t was used instead.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
- 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
-*/
-typedef struct __QCBORTrackNesting {
- // PRIVATE DATA STRUCTURE
- struct {
- // See function QCBOREncode_OpenMapOrArray() for details on how this works
- uint32_t uStart; // uStart is the byte position where the array starts
- uint16_t uCount; // Number of items in the arrary or map; counts items
- // in a map, not pairs of items
- uint8_t uMajorType; // Indicates if item is a map or an array
- } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
- *pCurrentNesting; // the current nesting level
-} QCBORTrackNesting;
-
-
-/*
- PRIVATE DATA STRUCTURE
-
- Context / data object for encoding some CBOR. Used by all encode functions to
- form a public "object" that does the job of encdoing.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
- 32-bit machine: 15 + 1 + 132 = 148 bytes
-*/
-struct _QCBOREncodeContext {
- // PRIVATE DATA STRUCTURE
- UsefulOutBuf OutBuf; // Pointer to output buffer, its length and
- // position in it
- uint8_t uError; // Error state, always from QCBORError enum
- QCBORTrackNesting nesting; // Keep track of array and map nesting
-};
-
-
-/*
- PRIVATE DATA STRUCTURE
-
- Holds the data for array and map nesting for decoding work. This structure
- and the DecodeNesting_xxx functions form an "object" that does the work
- for arrays and maps.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: 4 * 16 + 8 = 72
- 32-bit machine: 4 * 16 + 4 = 68
- */
-typedef struct __QCBORDecodeNesting {
- // PRIVATE DATA STRUCTURE
- struct {
- uint16_t uCount;
- uint8_t uMajorType;
- } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1],
- *pCurrent;
-} QCBORDecodeNesting;
-
-
-typedef struct {
- // PRIVATE DATA STRUCTURE
- void *pAllocateCxt;
- UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
-} QCORInternalAllocator;
-
-
-/*
- PRIVATE DATA STRUCTURE
-
- The decode context. This data structure plus the public QCBORDecode_xxx
- functions form an "object" that does CBOR decoding.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes
- 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes
- */
-struct _QCBORDecodeContext {
- // PRIVATE DATA STRUCTURE
- UsefulInputBuf InBuf;
-
- uint8_t uDecodeMode;
- uint8_t bStringAllocateAll;
-
- QCBORDecodeNesting nesting;
-
- // If a string allocator is configured for indefinite-length
- // strings, it is configured here.
- QCORInternalAllocator StringAllocator;
-
- // These are special for the internal MemPool allocator.
- // They are not used otherwise. We tried packing these
- // in the MemPool itself, but there are issues
- // with memory alignment.
- uint32_t uMemPoolSize;
- uint32_t uMemPoolFreeOffset;
-
- // This is NULL or points to QCBORTagList.
- // It is type void for the same reason as above.
- const void *pCallerConfiguredTagList;
-};
-
-// Used internally in the impementation here
-// Must not conflict with any of the official CBOR types
-#define CBOR_MAJOR_NONE_TYPE_RAW 9
-#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
-#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
-#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN 12
-#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN 13
-
-
-/* ==========================================================================
- END OF PRIVATE PART OF THIS FILE
-
- BEGINNING OF PUBLIC PART OF THIS FILE
- ========================================================================== */
-
-
-
-/* ==========================================================================
- BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
-
- It is not necessary to use these directly when encoding or decoding
- CBOR with this implementation.
- ========================================================================== */
-
-/* Standard CBOR Major type for positive integers of various lengths */
-#define CBOR_MAJOR_TYPE_POSITIVE_INT 0
-
-/* Standard CBOR Major type for negative integer of various lengths */
-#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1
-
-/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */
-#define CBOR_MAJOR_TYPE_BYTE_STRING 2
-
-/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8
- with no encoding and no NULL termination */
-#define CBOR_MAJOR_TYPE_TEXT_STRING 3
-
-/* Standard CBOR Major type for an ordered array of other CBOR data items */
-#define CBOR_MAJOR_TYPE_ARRAY 4
-
-/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The
- first item in the pair is the "label" (key, name or identfier) and the second
- item is the value. */
-#define CBOR_MAJOR_TYPE_MAP 5
-
-/* Standard CBOR optional tagging. This tags things like dates and URLs */
-#define CBOR_MAJOR_TYPE_OPTIONAL 6
-
-/* Standard CBOR extra simple types like floats and the values true and false */
-#define CBOR_MAJOR_TYPE_SIMPLE 7
-
-
-/*
- These are special values for the AdditionalInfo bits that are part of
- the first byte. Mostly they encode the length of the data item.
- */
-#define LEN_IS_ONE_BYTE 24
-#define LEN_IS_TWO_BYTES 25
-#define LEN_IS_FOUR_BYTES 26
-#define LEN_IS_EIGHT_BYTES 27
-#define ADDINFO_RESERVED1 28
-#define ADDINFO_RESERVED2 29
-#define ADDINFO_RESERVED3 30
-#define LEN_IS_INDEFINITE 31
-
-
-/*
- 24 is a special number for CBOR. Integers and lengths
- less than it are encoded in the same byte as the major type.
- */
-#define CBOR_TWENTY_FOUR 24
-
-
-/*
- Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These
- are types defined in RFC 7049 and some additional ones
- in the IANA CBOR tags registry.
- */
-/** See QCBOREncode_AddDateString(). */
-#define CBOR_TAG_DATE_STRING 0
-/** See QCBOREncode_AddDateEpoch(). */
-#define CBOR_TAG_DATE_EPOCH 1
-/** See QCBOREncode_AddPositiveBignum(). */
-#define CBOR_TAG_POS_BIGNUM 2
-/** See QCBOREncode_AddNegativeBignum(). */
-#define CBOR_TAG_NEG_BIGNUM 3
-/** CBOR tag for a two-element array representing a fraction with a
- mantissa and base-10 scaling factor. See QCBOREncode_AddDecimalFraction()
- and @ref expAndMantissa.
- */
-#define CBOR_TAG_DECIMAL_FRACTION 4
-/** CBOR tag for a two-element array representing a fraction with a
- mantissa and base-2 scaling factor. See QCBOREncode_AddBigFloat()
- and @ref expAndMantissa. */
-#define CBOR_TAG_BIGFLOAT 5
-/** Tag for COSE format encryption with no recipient
- identification. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_COSE_ENCRYPTO 16
-/** Tag for COSE format MAC'd data with no recipient
- identification. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag.*/
-#define CBOR_TAG_COSE_MAC0 17
-/** Tag for COSE format single signature signing. No API is provided
- for this tag. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). */
-#define CBOR_TAG_COSE_SIGN1 18
-/** 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_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_AddBytes(). */
-#define CBOR_TAG_ENC_AS_B64 22
-/** A hint that the following byte string should be encoded in base-16
- format per [RFC 4648] (https://tools.ietf.org/html/rfc4648) 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) before
- the call to QCBOREncode_AddBytes(). */
-#define CBOR_TAG_ENC_AS_B16 23
-/** Tag to indicate a byte string contains encoded CBOR. No API is
- provided for this tag. */
-#define CBOR_TAG_CBOR 24
-/** See QCBOREncode_AddURI(). */
-#define CBOR_TAG_URI 32
-/** See QCBOREncode_AddB64URLText(). */
-#define CBOR_TAG_B64URL 33
-/** See QCBOREncode_AddB64Text(). */
-#define CBOR_TAG_B64 34
-/** See QCBOREncode_AddRegex(). */
-#define CBOR_TAG_REGEX 35
-/** See QCBOREncode_AddMIMEData(). */
-#define CBOR_TAG_MIME 36
-/** See QCBOREncode_AddBinaryUUID(). */
-#define CBOR_TAG_BIN_UUID 37
-/** The data is a CBOR Web Token per [RFC 8392]
- (https://tools.ietf.org/html/rfc8932). No API is provided for this
- tag. */
-#define CBOR_TAG_CWT 61
-/** Tag for COSE format encryption. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_ENCRYPT 96
-/** Tag for COSE format MAC. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_MAC 97
-/** Tag for COSE format signed data. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_SIGN 98
-/** World geographic coordinates. See ISO 6709, [RFC 5870]
- (https://tools.ietf.org/html/rfc5870) and WGS-84. No API is
- provided for this tag. */
-#define CBOR_TAG_GEO_COORD 103
-/** The magic number, self-described CBOR. No API is provided for this
- tag. */
-#define CBOR_TAG_CBOR_MAGIC 55799
-
-#define CBOR_TAG_NONE UINT64_MAX
-
-
-/*
- Values for the 5 bits for items of major type 7
- */
-#define CBOR_SIMPLEV_FALSE 20
-#define CBOR_SIMPLEV_TRUE 21
-#define CBOR_SIMPLEV_NULL 22
-#define CBOR_SIMPLEV_UNDEF 23
-#define CBOR_SIMPLEV_ONEBYTE 24
-#define HALF_PREC_FLOAT 25
-#define SINGLE_PREC_FLOAT 26
-#define DOUBLE_PREC_FLOAT 27
-#define CBOR_SIMPLE_BREAK 31
-#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE
-#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK
-
-
-
-/* ===========================================================================
-
- END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
-
- BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER
-
- =========================================================================== */
-
-/**
-
- @file qcbor.h
-
- Q C B O R E n c o d e / D e c o d e
-
- This implements CBOR -- Concise Binary Object Representation as
- defined in [RFC 7049] (https://tools.ietf.org/html/rfc7049). More
- info is at http://cbor.io. This is a near-complete implementation of
- the specification. Limitations are listed further down.
-
- CBOR is intentionally designed to be translatable to JSON, but not
- all CBOR can convert to JSON. See RFC 7049 for more info on how to
- construct CBOR that is the most JSON friendly.
-
- The memory model for encoding and decoding is that encoded CBOR must
- be in a contiguous buffer in memory. During encoding the caller must
- supply an output buffer and if the encoding would go off the end of
- the buffer an error is returned. During decoding the caller supplies
- the encoded CBOR in a contiguous buffer and the decoder returns
- pointers and lengths into that buffer for strings.
-
- This implementation does not require malloc. All data structures
- passed in/out of the APIs can fit on the stack.
-
- Decoding of indefinite-length strings is a special case that requires
- a "string allocator" to allocate memory into which the segments of
- the string are coalesced. Without this, decoding will error out if an
- indefinite-length string is encountered (indefinite-length maps and
- arrays do not require the string allocator). A simple string
- allocator called MemPool is built-in and will work if supplied with a
- block of memory to allocate. The string allocator can optionally use
- malloc() or some other custom scheme.
-
- Here are some terms and definitions:
-
- - "Item", "Data Item": An integer or string or such. The basic "thing" that
- CBOR is about. An array is an item itself that contains some items.
-
- - "Array": An ordered sequence of items, the same as JSON.
-
- - "Map": A collection of label/value pairs. Each pair is a data
- item. A JSON "object" is the same as a CBOR "map".
-
- - "Label": The data item in a pair in a map that names or identifies
- the pair, not the value. This implementation refers to it as a
- "label". JSON refers to it as the "name". The CBOR RFC refers to it
- this as a "key". This implementation chooses label instead because
- key is too easily confused with a cryptographic key. The COSE
- standard, which uses CBOR, has also chosen to use the term "label"
- rather than "key" for this same reason.
-
- - "Key": See "Label" above.
-
- - "Tag": Optional integer that can be added before each data item
- usually to indicate it is new or more specific data type. For
- example, a tag can indicate an integer is a date, or that a map is to
- be considered a type (analogous to a typedef in C).
-
- - "Initial Byte": The first byte of an encoded item. Encoding and
- decoding of this byte is taken care of by the implementation.
-
- - "Additional Info": In addition to the major type, all data items
- have some other info. This is usually the length of the data but can
- be several other things. Encoding and decoding of this is taken care
- of by the implementation.
-
- CBOR has two mechanisms for tagging and labeling the data values like
- integers and strings. For example, an integer that represents
- someone's birthday in epoch seconds since Jan 1, 1970 could be
- encoded like this:
-
- - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64),
- the primitive positive integer.
-
- - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer
- represents a date in the form of the number of seconds since Jan 1,
- 1970.
-
- - Last it has a string "label" like "BirthDate" indicating the
- meaning of the data.
-
- The encoded binary looks like this:
-
- a1 # Map of 1 item
- 69 # Indicates text string of 9 bytes
- 426972746844617465 # The text "BirthDate"
- c1 # Tags next integer as epoch date
- 1a # Indicates a 4-byte integer
- 580d4172 # unsigned integer date 1477263730
-
- Implementors using this API will primarily work with
- labels. Generally, tags are only needed for making up new data
- types. This implementation covers most of the data types defined in
- the RFC using tags. It also, allows for the use of custom tags if
- necessary.
-
- This implementation explicitly supports labels that are text strings
- and integers. Text strings translate nicely into JSON objects and are
- very readable. Integer labels are much less readable but can be very
- compact. If they are in the range of 0 to 23, they take up only one
- byte.
-
- CBOR allows a label to be any type of data including an array or a
- map. It is possible to use this API to construct and parse such
- labels, but it is not explicitly supported.
-
- A common encoding usage mode is to invoke the encoding twice. First
- with no output buffer to compute the length of the needed output
- buffer. Then the correct sized output buffer is allocated. Last the
- encoder is invoked again, this time with the output buffer.
-
- The double invocation is not required if the maximum output buffer
- size can be predicted. This is usually possible for simple CBOR
- structures. If the double invocation is implemented, it can be in a
- loop or function as in the example code so that the code doesn't have
- to actually be written twice, saving code size.
-
- If a buffer too small to hold the encoded output is given, the error
- @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be
- written off the end of the output buffer no matter which functions
- here are called or what parameters are passed to them.
-
- The encoding error handling is simple. The only possible errors are
- trying to encode structures that are too large or too complex. There
- are no internal malloc calls so there will be no failures for out of
- memory. The error state is tracked internally, so there is no need
- to check for errors when encoding. Only the return code from
- QCBOREncode_Finish() need be checked as once an error happens, the
- encoder goes into an error state and calls to it to add more data
- will do nothing. An error check is not needed after every data item
- is added.
-
- Encoding generally proceeds by calling QCBOREncode_Init(), calling
- lots of @c QCBOREncode_AddXxx() functions and calling
- QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx()
- functions for various data types. The input buffers need only to be
- valid during the @c QCBOREncode_AddXxx() calls as the data is copied
- into the output buffer.
-
- There are three `Add` functions for each data type. The first / main
- one for the type is for adding the data item to an array. The second
- one's name ends in `ToMap`, is used for adding data items to maps and
- takes a string argument that is its label in the map. The third one
- ends in `ToMapN`, is also used for adding data items to maps, and
- takes an integer argument that is its label in the map.
-
- The simplest aggregate type is an array, which is a simple ordered
- set of items without labels the same as JSON arrays. Call
- QCBOREncode_OpenArray() to open a new array, then various @c
- QCBOREncode_AddXxx() functions to put items in the array and then
- QCBOREncode_CloseArray(). Nesting to the limit @ref
- QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by
- closes or an encoding error will be returned.
-
- The other aggregate type is a map which does use labels. The `Add`
- functions that end in `ToMap` and `ToMapN` are convenient ways to add
- labeled data items to a map. You can also call any type of `Add`
- function once to add a label of any time and then call any type of
- `Add` again to add its value.
-
- Note that when you nest arrays or maps in a map, the nested array or
- map has a label.
-
- @anchor Tags-Overview
- Any CBOR data item can be tagged to add semantics, define a new data
- type or such. Some tags are fully standardized and some are just
- registered. Others are not registered and used in a proprietary way.
-
- Encoding and decoding of many of the registered tags is fully
- implemented by QCBOR. It is also possible to encode and decode tags
- that are not directly supported. For many use cases the built-in tag
- support should be adequate.
-
- For example, the registered epoch date tag is supported in encoding
- by QCBOREncode_AddDateEpoch() and in decoding by @ref
- QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref
- QCBORItem. This is typical of the built-in tag support. There is an
- API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded.
-
- Tags are registered in the [IANA CBOR Tags Registry]
- (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There
- are roughly three options to create a new tag. First, a public
- specification can be created and the new tag registered with IANA.
- This is the most formal. Second, the new tag can be registered with
- IANA with just a short description rather than a full specification.
- These tags must be greater than 256. Third, a tag can be used without
- any IANA registration, though the registry should be checked to see
- that the new value doesn't collide with one that is registered. The
- value of these tags must be 256 or larger.
-
- The encoding side of tags not built-in is handled by
- QCBOREncode_AddTag() 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.
-
- By default full IEEE 754 floating-point support is enabled including
- preferred serialization of floating-point numbers as per section 4
- of the CBOR RFC (TODO: fix this) . With preferred
- serialization, the decoder outputs the smallest representation
- of the double or float that preserves precision. Zero,
- NaN and infinity are always output as a half-precision, each taking
- just 2 bytes. This reduces the number of bytes needed to
- encode doubles and floats, especially if a zero, NaN and
- infinity are frequently used. On the decode side, half-precision and single-precision
- floats are always returned as doubles.
-
- Preferred floating point serialization does NOT depend on
- the CPU having floating-point HW or the compiler
- bringing a (sometimes large) library to compensate for
- lack of CPU support.
-
- If preferred floating point serialization is disabled, then
- floats and doubles may still be encoded, but they will
- be encoded as their normal size and returned as a
- float or double during decoding. There is no way to
- encode half-precision and when
- a half-precision data item is encountered during decoding, an
- error will be returned.
-
- QCBOR can always encode and decode floats and doubles
- even if the CPU HW doesn't support them, even if
- preferred serialization is disabled and doesn't need SW-based
- floating-point to be brought in by the compiler.
-
- TODO: should there be a runtime option to disable preferred float serialization as some protocols will not want half-precision support. Maybe a mode? Maybe an API?
- TODO: a way to explicitly encode half-precision?
-
- In order to process floating-point epoch dates, QCBOR needs
- floating point arithmetic. On CPUs that have no floating-point
- hardware, QCBOR may be set up to not using floating-point
- aritthmetic, in which case floating-point epoch date values
- will be considered and error when encoding. QCBOR never
- generates floating-point values when encoding dates.
-
-
-
-
- . For environments with
- no floating point HW, or to save some object code , some floating
- point features may be disabled. In this limited mode float and double values may still be encoded
- and decoded, but there will be no preferred encoding of them.
-When decoding half-precison values and floating-point format
- dates will be treated as an error. In this limited mode no
- floating point operations like conversion in size or to integers
- are used so in environments with no floating point HW, the
- compiler will not have to add in support with SW.
-
- -----
- Default full float support
-
- Disable: preferred float encoding / decoding. Savs 300 bytes during
- decoding and 300 bytes during encodeing. Can still encode / decode
- float and double values. This need not be disabled on devices
- with no floating point HW because preferred encoding / decoding
- is all done internally with shifts and masks.
-
- QCBOR_DISABLE_FLOAT_HW_USE. Disable use of floating point HW. Saves a very small amount of
- code on devices with no floating point HW and a lot of code on
- devices without floating point HW. The compiler won't bring in
- the floating point SW that emulates the HW. When this is done
- floating point dates are not supported. When this is disabled,
- the following is not available: handling of floating-point epoch dates.
-
-
- QCBOR_DISABLE_FLOAT_PREFERRED_SERIALIZATION. This disables
- preferred serialization of floating-point values. It also
- disables all support for half-precision floating-point. The main
- reason to disable this is to reduce object code in the decoder
- by a few hundred bytes. It is not as necessary to
- disable this to reduce size of the encoder, because avoiding
- calls to the floating-point encode functions has the same effect.
-
- Even when this is disabled, QCBOR
- can encode and decode float and double values. What is
- unavailable is the reduction in size of encoded floats and
- the ability to decode half-precision.
-
- Preferred serialization encoding and decoding
- does not use floating-point HW, so it is not necessary to
- disable this on CPUs without floating-point support. However,
- if a CPU doesn't support floating point, then use of floating
- point is usually very expensive and slow because the compiler
- must bring in large SW libraries. For that reason some may
- choose to disable floating-point preferred serialization because it is
- unlikely to be needed.
-
- QCBOR_DISABLE_FLOAT_HW_USE. This disables
- all use of CPU floating-point HW and the
- often large and slow SW libraries the compiler substitutes if
- there is no floating-point HW.
- The only effect on QCBOR features
- is that floating-point epoch date formats will result in a decoding error. Disabling
- this reduces QCBOR in size by very little, but reduces
- the overall executable size a lot on CPUs with no floating-point
- HW by avoiding the compiler-supplied SW libraries. Since
- floaing-point dates are not a very necessary feature, it
- is advisable to define this on CPUs with no floating-point HW.
-
-
-
- If you are running on a CPU with no floating point HW and you
- don't need floating point date support, definitely disable XXX. If
- you don't the compiler is likely to bring in large SW libraries
- to provide the functions the HW does not.
-
- If you want to save object ocde by disabling preferred encoding
- of floats turn off QCBOR_DISABLE_PREFERRED_FLOAT. Note that this doesn't use floating point
- HW so it is OK to leave enabled on CPUs with no floating
- point support if you don't mind the extra 300 bytes of object
- code on the decode side. On the encode side the floating
- point code will be dead-stripped if not used.
-
- Float features
- - preferred encoding, encode side
- - preferred encoding, decode side
- - floating-point dates
-
-
- Two modes?
-
- disable use of preferred encoding / decoding and half precision support? This still
- needs no floating point HW or SW.
-
-
- -----
-
- Summary Limits of this implementation:
- - The entire encoded CBOR must fit into contiguous memory.
- - Max size of encoded / decoded CBOR data is @c UINT32_MAX (4GB).
- - Max array / map nesting level when encoding / decoding is
- @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
- - Max items in an array or map when encoding / decoding is
- @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
- - Does not directly support labels in maps other than text strings & integers.
- - Does not directly support integer labels greater than @c INT64_MAX.
- - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
- - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX.
- - Tags on labels are ignored during decoding.
- - There is no duplicate detection of map labels (but duplicates are passed on).
- - Works only on 32- and 64-bit CPUs (modifications could make it work
- on 16-bit CPUs).
-
- The public interface uses @c size_t for all lengths. Internally the
- implementation uses 32-bit lengths by design to use less memory and
- fit structures on the stack. This limits the encoded CBOR it can work
- with to size @c UINT32_MAX (4GB) which should be enough.
-
- This implementation assumes two's compliment integer machines. @c
- <stdint.h> also requires this. It is possible to modify this
- implementation for another integer representation, but all modern
- machines seem to be two's compliment.
-
- */
-
-
-/**
- The maximum number of items in a single array or map when encoding of
- decoding.
-*/
-// -1 is because the value UINT16_MAX is used to track indefinite-length arrays
-#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1)
-
-/**
- The maximum nesting of arrays and maps when encoding or decoding. The
- error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on
- encoding of decoding if it is exceeded.
-*/
-#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1
-
-/**
- The maximum number of tags that can be in @ref QCBORTagListIn and passed to
- QCBORDecode_SetCallerConfiguredTagList()
- */
-#define QCBOR_MAX_CUSTOM_TAGS 16
-
-/*
- The size of the buffer to be passed to QCBOREncode_EncodeHead(). It is one
- byte larger than sizeof(uint64_t) + 1, the actual maximum size of the
- head of a CBOR data item. because QCBOREncode_EncodeHead() needs
- one extra byte to work.
- */
-#define QCBOR_HEAD_BUFFER_SIZE (sizeof(uint64_t) + 2)
-
-/**
- Error codes returned by QCBOR Encoder and Decoder.
- */
-typedef enum {
- /** The encode or decode completely correctly. */
- QCBOR_SUCCESS = 0,
-
- /** The buffer provided for the encoded output when doing encoding
- was too small and the encoded output will not fit. Also, when
- the buffer given to QCBORDecode_SetMemPool() is too small. */
- QCBOR_ERR_BUFFER_TOO_SMALL = 1,
-
- /** During encoding or decoding, the array or map nesting was
- deeper than this implementation can handle. Note that in the
- interest of code size and memory use, this implementation has a
- hard limit on array nesting. The limit is defined as the
- constant @ref QCBOR_MAX_ARRAY_NESTING. */
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 2,
-
- /** During decoding or encoding, the array or map had too many
- items in it. This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY,
- typically 65,535. */
- QCBOR_ERR_ARRAY_TOO_LONG = 3,
-
- /** During encoding, more arrays or maps were closed than
- opened. This is a coding error on the part of the caller of the
- encoder. */
- QCBOR_ERR_TOO_MANY_CLOSES = 4,
-
- /** During decoding, some CBOR construct was encountered that this
- decoder doesn't support, primarily this is the reserved
- additional info values, 28 through 30. During encoding,
- an attempt to create simple value between 24 and 31. */
- QCBOR_ERR_UNSUPPORTED = 5,
-
- /** During decoding, hit the end of the given data to decode. For
- example, a byte string of 100 bytes was expected, but the end
- of the input was hit before finding those 100 bytes. Corrupted
- CBOR input will often result in this error. See also @ref
- QCBOR_ERR_NO_MORE_ITEMS.
- */
- QCBOR_ERR_HIT_END = 6,
-
- /** During encoding, the length of the encoded CBOR exceeded @c
- UINT32_MAX. */
- QCBOR_ERR_BUFFER_TOO_LARGE = 7,
-
- /** During decoding, an integer smaller than INT64_MIN was received
- (CBOR can represent integers smaller than INT64_MIN, but C
- cannot). */
- QCBOR_ERR_INT_OVERFLOW = 8,
-
- /** During decoding, the label for a map entry is bad. What causes
- this error depends on the decoding mode. */
- QCBOR_ERR_MAP_LABEL_TYPE = 9,
-
- /** During encoding or decoding, the number of array or map opens
- was not matched by the number of closes. */
- QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 10,
-
- /** During decoding, a date greater than +- 292 billion years from
- Jan 1 1970 encountered during parsing. */
- QCBOR_ERR_DATE_OVERFLOW = 11,
-
- /** During decoding, the CBOR is not valid, primarily a simple type
- is encoded in a prohibited way. */
- QCBOR_ERR_BAD_TYPE_7 = 12,
-
- /** Optional tagging that doesn't make sense (an integer is tagged
- as a date string) or can't be handled. */
- QCBOR_ERR_BAD_OPT_TAG = 13,
-
- /** Returned by QCBORDecode_Finish() if all the inputs bytes have
- not been consumed. */
- QCBOR_ERR_EXTRA_BYTES = 14,
-
- /** During encoding, @c QCBOREncode_CloseXxx() called with a
- different type than is currently open. */
- QCBOR_ERR_CLOSE_MISMATCH = 15,
-
- /** Unable to decode an indefinite-length string because no string
- allocator was configured. See QCBORDecode_SetMemPool() or
- QCBORDecode_SetUpAllocator(). */
- QCBOR_ERR_NO_STRING_ALLOCATOR = 16,
-
- /** One of the chunks in an indefinite-length string is not of the
- type of the start of the string. */
- QCBOR_ERR_INDEFINITE_STRING_CHUNK = 17,
-
- /** Error allocating space for a string, usually for an
- indefinite-length string. */
- QCBOR_ERR_STRING_ALLOCATE = 18,
-
- /** During decoding, a break occurred outside an indefinite-length
- item. */
- QCBOR_ERR_BAD_BREAK = 19,
-
- /** During decoding, too many tags in the caller-configured tag
- list, or not enough space in @ref QCBORTagListOut. */
- QCBOR_ERR_TOO_MANY_TAGS = 20,
-
- /** An integer type is encoded with a bad length (an indefinite length) */
- QCBOR_ERR_BAD_INT = 21,
-
- /** All well-formed data items have been consumed and there are no
- more. If parsing a CBOR stream this indicates the non-error
- end of the stream. If parsing a CBOR stream / sequence, this
- probably indicates that some data items expected are not present.
- See also @ref QCBOR_ERR_HIT_END. */
- QCBOR_ERR_NO_MORE_ITEMS = 22,
-
- /** Something is wrong with a decimal fraction or bigfloat such as
- it not consisting of an array with two integers */
- QCBOR_ERR_BAD_EXP_AND_MANTISSA = 23,
-
- /** When decoding, a string's size is greater than size_t. In all but some
- very strange situations this is because of corrupt input CBOR and
- should be treated as such. The strange situation is a CPU with a very
- small size_t (e.g., a 16-bit CPU) and a large string (e.g., > 65KB).
- */
- QCBOR_ERR_STRING_TOO_LONG = 24,
-
- /** Decoding of floating-point epoch dates is unsupported and a
- floating-point date was encountered by the decoder. */
- QCBOR_ERR_FLOAT_DATE_UNSUPPORTED = 25,
-
-} QCBORError;
-
-
-/**
- The decode mode options.
- */
-typedef enum {
- /** See QCBORDecode_Init() */
- QCBOR_DECODE_MODE_NORMAL = 0,
- /** See QCBORDecode_Init() */
- QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
- /** See QCBORDecode_Init() */
- QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
-} QCBORDecodeMode;
-
-
-
-
-
-/* Do not renumber these. Code depends on some of these values. */
-/** The data type is unknown, unset or invalid. */
-#define QCBOR_TYPE_NONE 0
-/** Type for an integer that decoded either between @c INT64_MIN and
- @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member
- @c val.int64. */
-#define QCBOR_TYPE_INT64 2
-/** Type for an integer that decoded to a more than @c INT64_MAX and
- @c UINT64_MAX. Data is in member @c val.uint64. */
-#define QCBOR_TYPE_UINT64 3
-/** Type for an array. The number of items in the array is in @c
- val.uCount. */
-#define QCBOR_TYPE_ARRAY 4
-/** Type for a map; number of items in map is in @c val.uCount. */
-#define QCBOR_TYPE_MAP 5
-/** Type for a buffer full of bytes. Data is in @c val.string. */
-#define QCBOR_TYPE_BYTE_STRING 6
-/** Type for a UTF-8 string. It is not NULL-terminated. Data is in @c
- val.string. */
-#define QCBOR_TYPE_TEXT_STRING 7
-/** Type for a positive big number. Data is in @c val.bignum, a
- pointer and a length. */
-#define QCBOR_TYPE_POSBIGNUM 9
-/** Type for a negative big number. Data is in @c val.bignum, a
- pointer and a length. */
-#define QCBOR_TYPE_NEGBIGNUM 10
-/** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date
- string, possibly with time zone. Data is in @c val.dateString */
-#define QCBOR_TYPE_DATE_STRING 11
-/** Type for integer seconds since Jan 1970 + floating-point
- fraction. Data is in @c val.epochDate */
-#define QCBOR_TYPE_DATE_EPOCH 12
-/** A simple type that this CBOR implementation doesn't know about;
- Type is in @c val.uSimple. */
-#define QCBOR_TYPE_UKNOWN_SIMPLE 13
-
-/** A decimal fraction made of decimal exponent and integer mantissa.
- See @ref expAndMantissa and QCBOREncode_AddDecimalFraction(). */
-#define QCBOR_TYPE_DECIMAL_FRACTION 14
-
-/** A decimal fraction made of decimal exponent and positive big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddDecimalFractionBigNum(). */
-#define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15
-
-/** A decimal fraction made of decimal exponent and negative big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddDecimalFractionBigNum(). */
-#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16
-
-/** A floating-point number made of base-2 exponent and integer
- mantissa. See @ref expAndMantissa and
- QCBOREncode_AddBigFloat(). */
-#define QCBOR_TYPE_BIGFLOAT 17
-
-/** A floating-point number made of base-2 exponent and positive big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddBigFloatBigNum(). */
-#define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18
-
-/** A floating-point number made of base-2 exponent and negative big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddBigFloatBigNum(). */
-#define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19
-
-/** Type for the value false. */
-#define QCBOR_TYPE_FALSE 20
-/** Type for the value true. */
-#define QCBOR_TYPE_TRUE 21
-/** Type for the value null. */
-#define QCBOR_TYPE_NULL 22
-/** Type for the value undef. */
-#define QCBOR_TYPE_UNDEF 23
-/** Type for a floating-point number. Data is in @c val.float. */
-#define QCBOR_TYPE_FLOAT 26
-/** Type for a double floating-point number. Data is in @c val.double. */
-#define QCBOR_TYPE_DOUBLE 27
-/** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is
- being traversed as an array. See QCBORDecode_Init() */
-#define QCBOR_TYPE_MAP_AS_ARRAY 32
-
-#define QCBOR_TYPE_BREAK 31 // Used internally; never returned
-
-#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned
-
-
-
-/*
- Approx Size of this:
- 8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding) = 24 for first part
- (20 on a 32-bit machine)
- 16 bytes for the val union
- 16 bytes for label union
- total = 56 bytes (52 bytes on 32-bit machine)
- */
-
-/**
- The main data structure that holds the type, value and other info for
- a decoded item returned by QCBORDecode_GetNext() and
- QCBORDecode_GetNextWithTags().
- */
-typedef struct _QCBORItem {
- /** Tells what element of the @c val union to use. One of @c
- QCBOR_TYPE_XXXX */
- uint8_t uDataType;
- /** How deep the nesting from arrays and maps are. 0 is the top
- level with no arrays or maps entered. */
- uint8_t uNestingLevel;
- /** Tells what element of the label union to use. */
- uint8_t uLabelType;
- /** 1 if allocated with string allocator, 0 if not. See
- QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() */
- uint8_t uDataAlloc;
- /** Like @c uDataAlloc, but for label. */
- uint8_t uLabelAlloc;
- /** If not equal to @c uNestingLevel, this item closed out at least
- one map/array */
- uint8_t uNextNestLevel;
-
- /** The union holding the item's value. Select union member based
- on @c uDataType */
- union {
- /** The value for @c uDataType @ref QCBOR_TYPE_INT64. */
- int64_t int64;
- /** The value for uDataType @ref QCBOR_TYPE_UINT64. */
- uint64_t uint64;
- /** The value for @c uDataType @ref QCBOR_TYPE_BYTE_STRING and
- @ref QCBOR_TYPE_TEXT_STRING. */
- UsefulBufC string;
- /** The "value" for @c uDataType @ref QCBOR_TYPE_ARRAY or @ref
- QCBOR_TYPE_MAP -- the number of items in the array or map.
- It is @c UINT16_MAX when decoding indefinite-lengths maps
- and arrays. */
- uint16_t uCount;
- /** The value for @c uDataType @ref QCBOR_TYPE_FLOAT. */
- double fnum;
- /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
- double dfnum;
- /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
- struct {
- int64_t nSeconds;
- double fSecondsFraction;
- } epochDate;
- /** The value for @c uDataType @ref QCBOR_TYPE_DATE_STRING. */
- UsefulBufC dateString;
- /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and
- @ref QCBOR_TYPE_NEGBIGNUM. */
- UsefulBufC bigNum;
- /** The integer value for unknown simple types. */
- uint8_t uSimple;
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
- /** @anchor expAndMantissa
-
- The value for bigfloats and decimal fractions. The use of the
- fields in this structure depend on @c uDataType.
-
- When @c uDataType is a @c DECIMAL_FRACTION, the exponent is
- base-10. When it is a @c BIG_FLOAT it is base-2.
-
- When @c uDataType is a @c POS_BIGNUM or a @c NEG_BIGNUM then the
- @c bigNum part of @c Mantissa is valid. Otherwise the
- @c nInt part of @c Mantissa is valid.
-
- See @ref QCBOR_TYPE_DECIMAL_FRACTION,
- @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
- @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
- @ref QCBOR_TYPE_BIGFLOAT, @ref QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
- and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
-
- Also see QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
- QCBOREncode_AddDecimalFractionBigNum() and
- QCBOREncode_AddBigFloatBigNum().
- */
- struct {
- int64_t nExponent;
- union {
- int64_t nInt;
- UsefulBufC bigNum;
- } Mantissa;
- } expAndMantissa;
-#endif
- uint64_t uTagV; // Used internally during decoding
- } val;
-
- /** Union holding the different label types selected based on @c
- uLabelType */
- union {
- /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and
- @ref QCBOR_TYPE_TEXT_STRING */
- UsefulBufC string;
- /** The label for @c uLabelType for @ref QCBOR_TYPE_INT64 */
- int64_t int64;
- /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */
- uint64_t uint64;
- } label;
-
- /** Bit indicating which tags (major type 6) on this item. See
- QCBORDecode_IsTagged(). */
- uint64_t uTagBits;
-
-} QCBORItem;
-
-
-
-/**
- @brief The type defining what a string allocator function must do.
-
- @param[in] pAllocateCxt Pointer to context for the particular
- allocator implementation What is in the
- context is dependent on how a particular
- string allocator works. Typically, it
- will contain a pointer to the memory pool
- and some booking keeping data.
- @param[in] pOldMem Points to some memory allocated by the
- allocator that is either to be freed or
- to be reallocated to be larger. It is
- @c NULL for new allocations and when called as
- a destructor to clean up the whole
- allocation.
- @param[in] uNewSize Size of memory to be allocated or new
- size of chunk to be reallocated. Zero for
- a new allocation or when called as a
- destructor.
-
- @return Either the allocated buffer is returned, or @ref
- NULLUsefulBufC. @ref NULLUsefulBufC is returned on a failed
- allocation and in the two cases where there is nothing to
- return.
-
- This is called in one of four modes:
-
- Allocate -- @c uNewSize is the amount to allocate. @c pOldMem is @c
- NULL.
-
- Free -- @c uNewSize is 0. @c pOldMem points to the memory to be
- freed. When the decoder calls this, it will always be the most
- recent block that was either allocated or reallocated.
-
- Reallocate -- @c pOldMem is the block to reallocate. @c uNewSize is
- its new size. When the decoder calls this, it will always be the
- most recent block that was either allocated or reallocated.
-
- Destruct -- @c pOldMem is @c NULL and @c uNewSize is 0. This is called
- when the decoding is complete by QCBORDecode_Finish(). Usually the
- strings allocated by a string allocator are in use after the decoding
- is completed so this usually will not free those strings. Many string
- allocators will not need to do anything in this mode.
-
- The strings allocated by this will have @c uDataAlloc set to true in
- the @ref QCBORItem when they are returned. The user of the strings
- will have to free them. How they free them, depends on the string
- allocator.
-
- If QCBORDecode_SetMemPool() is called, the internal MemPool will be
- used. It has its own internal implementation of this function, so
- one does not need to be implemented.
- */
-typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
-
-
-/**
- This only matters if you use the built-in string allocator by setting
- it up with QCBORDecode_SetMemPool(). This is the size of the overhead
- needed by QCBORDecode_SetMemPool(). The amount of memory available
- for decoded strings will be the size of the buffer given to
- QCBORDecode_SetMemPool() less this amount.
-
- If you write your own string allocator or use the separately
- available malloc based string allocator, this size will not apply.
- */
-#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 8
-
-
-/**
- This is used by QCBORDecode_SetCallerConfiguredTagList() to set a
- list of tags beyond the built-in ones.
-
- See also QCBORDecode_GetNext() for general description of tag
- decoding.
- */
-typedef struct {
- /** The number of tags in the @c puTags. The maximum size is @ref
- QCBOR_MAX_CUSTOM_TAGS. */
- uint8_t uNumTags;
- /** An array of tags to add to recognize in addition to the
- built-in ones. */
- const uint64_t *puTags;
-} QCBORTagListIn;
-
-
-/**
- This is for QCBORDecode_GetNextWithTags() to be able to return the
- full list of tags on an item. It is not needed for most CBOR protocol
- implementations. Its primary use is for pretty-printing CBOR or
- protocol conversion to another format.
-
- 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.
-
- 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;
-
-
-/**
- QCBOREncodeContext is the data type that holds context for all the
- encoding functions. It is less than 200 bytes, so it can go on the
- stack. The contents are opaque, and the caller should not access
- internal members. A context may be re used serially as long as it is
- re initialized.
- */
-typedef struct _QCBOREncodeContext QCBOREncodeContext;
-
-
-/**
- Initialize the encoder to prepare to encode some CBOR.
-
- @param[in,out] pCtx The encoder context to initialize.
- @param[in] Storage The buffer into which this encoded result
- will be placed.
-
- Call this once at the start of an encoding of a CBOR structure. Then
- call the various @c QCBOREncode_AddXxx() functions to add the data
- items. Then call QCBOREncode_Finish().
-
- The maximum output buffer is @c UINT32_MAX (4GB). This is not a
- practical limit in any way and reduces the memory needed by the
- implementation. The error @ref QCBOR_ERR_BUFFER_TOO_LARGE will be
- returned by QCBOREncode_Finish() if a larger buffer length is passed
- in.
-
- If this is called with @c Storage.ptr as @c NULL and @c Storage.len a
- large value like @c UINT32_MAX, all the QCBOREncode_AddXxx()
- functions and QCBOREncode_Finish() can still be called. No data will
- be encoded, but the length of what would be encoded will be
- calculated. The length of the encoded structure will be handed back
- in the call to QCBOREncode_Finish(). You can then allocate a buffer
- of that size and call all the encoding again, this time to fill in
- the buffer.
-
- A @ref QCBOREncodeContext can be reused over and over as long as
- QCBOREncode_Init() is called.
- */
-void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage);
-
-
-/**
- @brief Add a signed 64-bit integer to the encoded output.
-
- @param[in] pCtx The encoding context to add the integer to.
- @param[in] nNum The integer to add.
-
- The integer will be encoded and added to the CBOR output.
-
- This function figures out the size and the sign and encodes in the
- correct minimal CBOR. Specifically, it will select CBOR major type 0
- or 1 based on sign and will encode to 1, 2, 4 or 8 bytes depending on
- the value of the integer. Values less than 24 effectively encode to
- one byte because they are encoded in with the CBOR major type. This
- is a neat and efficient characteristic of CBOR that can be taken
- advantage of when designing CBOR-based protocols. If integers like
- tags can be kept between -23 and 23 they will be encoded in one byte
- including the major type.
-
- If you pass a smaller int, say an @c int16_t or a small value, say
- 100, the encoding will still be CBOR's most compact that can
- represent the value. For example, CBOR always encodes the value 0 as
- one byte, 0x00. The representation as 0x00 includes identification of
- the type as an integer too as the major type for an integer is 0. See
- [RFC 7049] (https://tools.ietf.org/html/rfc7049) Appendix A for more
- examples of CBOR encoding. This compact encoding is also canonical
- CBOR as per section 3.9 in RFC 7049.
-
- There are no functions to add @c int16_t or @c int32_t because they
- are not necessary because this always encodes to the smallest number
- of bytes based on the value (If this code is running on a 32-bit
- machine having a way to add 32-bit integers would reduce code size
- some).
-
- If the encoding context is in an error state, this will do
- nothing. If an error occurs when adding this integer, the internal
- error flag will be set, and the error will be returned when
- QCBOREncode_Finish() is called.
-
- See also QCBOREncode_AddUInt64().
- */
-void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum);
-
-static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum);
-
-static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum);
-
-
-/**
- @brief Add an unsigned 64-bit integer to the encoded output.
-
- @param[in] pCtx The encoding context to add the integer to.
- @param[in] uNum The integer to add.
-
- The integer will be encoded and added to the CBOR output.
-
- The only reason so use this function is for integers larger than @c
- INT64_MAX and smaller than @c UINT64_MAX. Otherwise
- QCBOREncode_AddInt64() will work fine.
-
- Error handling is the same as for QCBOREncode_AddInt64().
- */
-void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
-
-static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
-
-static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum);
-
-
-/**
- @brief Add a UTF-8 text string to the encoded output.
-
- @param[in] pCtx The encoding context to add the text to.
- @param[in] Text Pointer and length of text to add.
-
- The text passed in must be unencoded UTF-8 according to [RFC 3629]
- (https://tools.ietf.org/html/rfc3629). There is no NULL
- termination. The text is added as CBOR major type 3.
-
- If called with @c nBytesLen equal to 0, an empty string will be
- added. When @c nBytesLen is 0, @c pBytes may be @c NULL.
-
- Note that the restriction of the buffer length to a @c uint32_t is
- entirely intentional as this encoder is not capable of encoding
- lengths greater. This limit to 4GB for a text string should not be a
- problem.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text);
-
-static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text);
-
-static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text);
-
-
-/**
- @brief Add a UTF-8 text string to the encoded output.
-
- @param[in] pCtx The encoding context to add the text to.
- @param[in] szString Null-terminated text to add.
-
- This works the same as QCBOREncode_AddText().
- */
-static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString);
-
-static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString);
-
-static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString);
-
-
-/**
- @brief Add a floating-point number to the encoded output.
-
- @param[in] pCtx The encoding context to add the double to.
- @param[in] dNum The double-precision number to add.
-
- This outputs a floating-point number with CBOR major type 7.
-
- This will selectively encode the double-precision floating-point
- number as either double-precision, single-precision or
- half-precision. It will always encode infinity, NaN and 0 has half
- precision. If no precision will be lost in the conversion to
- half-precision, then it will be converted and encoded. If not and no
- precision will be lost in conversion to single-precision, then it
- will be converted and encoded. If not, then no conversion is
- performed, and it encoded as a double.
-
- Half-precision floating-point numbers take up 2 bytes, half that of
- single-precision, one quarter of double-precision
-
- This automatically reduces the size of encoded messages a lot, maybe
- even by four if most of values are 0, infinity or NaN.
-
- On decode, these will always be returned as a double.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
-
-static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum);
-
-static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum);
-
-
-/**
- @brief Add an optional tag.
-
- @param[in] pCtx The encoding context to add the tag to.
- @param[in] uTag The tag to add
-
- This outputs a CBOR major type 6 item that tags the next data item
- that is output usually to indicate it is some new data type.
-
- For many of the common standard tags, a function to encode data using
- it is provided and this is not needed. For example,
- QCBOREncode_AddDateEpoch() already exists to output integers
- representing dates with the right tag.
-
- The tag is applied to the next data item added to the encoded
- output. That data item that is to be tagged can be of any major CBOR
- type. Any number of tags can be added to a data item by calling this
- multiple times before the data item is added.
-
- See @ref Tags-Overview for discussion of creating new non-standard
- tags. See QCBORDecode_GetNext() for discussion of decoding custom
- tags.
-*/
-void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag);
-
-
-/**
- @brief Add an epoch-based date.
-
- @param[in] pCtx The encoding context to add the date to.
- @param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time.
-
- As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is
- the most compact way to specify a date and time in CBOR. Note that
- this is always UTC and does not include the time zone. Use
- QCBOREncode_AddDateString() if you want to include the time zone.
-
- The integer encoding rules apply here so the date will be encoded in
- a minimal number of bytes. Until about the year 2106 these dates will
- encode in 6 bytes -- one byte for the tag, one byte for the type and
- 4 bytes for the integer. After that it will encode to 10 bytes.
-
- Negative values are supported for dates before 1970.
-
- If you care about leap-seconds and that level of accuracy, make sure
- the system you are running this code on does it correctly. This code
- just takes the value passed in.
-
- This implementation cannot encode fractional seconds using float or
- double even though that is allowed by CBOR, but you can encode them
- if you want to by calling QCBOREncode_AddDouble() and
- QCBOREncode_AddTag().
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date);
-
-static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date);
-
-static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date);
-
-
-/**
- @brief Add a byte string to the encoded output.
-
- @param[in] pCtx The encoding context to add the bytes to.
- @param[in] Bytes Pointer and length of the input data.
-
- Simply adds the bytes to the encoded output as CBOR major type 2.
-
- If called with @c Bytes.len equal to 0, an empty string will be
- added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-
-/**
- @brief Add a binary UUID to the encoded output.
-
- @param[in] pCtx The encoding context to add the UUID to.
- @param[in] Bytes Pointer and length of the binary UUID.
-
- A binary UUID as defined in [RFC 4122]
- (https://tools.ietf.org/html/rfc4122) is added to the output.
-
- It is output as CBOR major type 2, a binary string, with tag @ref
- CBOR_TAG_BIN_UUID indicating the binary string is a UUID.
- */
-static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-/**
- @brief Add a positive big number to the encoded output.
-
- @param[in] pCtx The encoding context to add the big number to.
- @param[in] Bytes Pointer and length of the big number.
-
- Big numbers are integers larger than 64-bits. Their format is
- described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
-
- It is output as CBOR major type 2, a binary string, with tag @ref
- CBOR_TAG_POS_BIGNUM indicating the binary string is a positive big
- number.
-
- Often big numbers are used to represent cryptographic keys, however,
- COSE which defines representations for keys chose not to use this
- particular type.
- */
-static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-/**
- @brief Add a negative big number to the encoded output.
-
- @param[in] pCtx The encoding context to add the big number to.
- @param[in] Bytes Pointer and length of the big number.
-
- Big numbers are integers larger than 64-bits. Their format is
- described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
-
- It is output as CBOR major type 2, a binary string, with tag @ref
- CBOR_TAG_NEG_BIGNUM indicating the binary string is a negative big
- number.
-
- Often big numbers are used to represent cryptographic keys, however,
- COSE which defines representations for keys chose not to use this
- particular type.
- */
-static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
-/**
- @brief Add a decimal fraction to the encoded output.
-
- @param[in] pCtx The encoding context to add the decimal fraction to.
- @param[in] nMantissa The mantissa.
- @param[in] nBase10Exponent The exponent.
-
- The value is nMantissa * 10 ^ nBase10Exponent.
-
- A decimal fraction is good for exact representation of some values
- that can't be represented exactly with standard C (IEEE 754)
- floating-point numbers. Much larger and much smaller numbers can
- also be represented than floating-point because of the larger number
- of bits in the exponent.
-
- The decimal fraction is conveyed as two integers, a mantissa and a
- base-10 scaling factor.
-
- For example, 273.15 is represented by the two integers 27315 and -2.
-
- The exponent and mantissa have the range from @c INT64_MIN to
- @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
- to @c UINT64_MAX, but this implementation doesn't support this range to
- reduce code size and interface complexity a little).
-
- CBOR Preferred encoding of the integers is used, thus they will be encoded
- in the smallest number of bytes possible.
-
- See also QCBOREncode_AddDecimalFractionBigNum() for a decimal
- fraction with arbitrarily large precision and QCBOREncode_AddBigFloat().
-
- There is no representation of positive or negative infinity or NaN
- (Not a Number). Use QCBOREncode_AddDouble() to encode them.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent);
-
-/**
- @brief Add a decimal fraction with a big number mantissa to the encoded output.
-
- @param[in] pCtx The encoding context to add the decimal fraction to.
- @param[in] Mantissa The mantissa.
- @param[in] bIsNegative false if mantissa is positive, true if negative.
- @param[in] nBase10Exponent The exponent.
-
- This is the same as QCBOREncode_AddDecimalFraction() except the
- mantissa is a big number (See QCBOREncode_AddPositiveBignum())
- allowing for arbitrarily large precision.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent);
-
-/**
- @brief Add a big floating-point number to the encoded output.
-
- @param[in] pCtx The encoding context to add the bigfloat to.
- @param[in] nMantissa The mantissa.
- @param[in] nBase2Exponent The exponent.
-
- The value is nMantissa * 2 ^ nBase2Exponent.
-
- "Bigfloats", as CBOR terms them, are similar to IEEE floating-point
- numbers in having a mantissa and base-2 exponent, but they are not
- supported by hardware or encoded the same. They explicitly use two
- CBOR-encoded integers to convey the mantissa and exponent, each of which
- can be 8, 16, 32 or 64 bits. With both the mantissa and exponent
- 64 bits they can express more precision and a larger range than an
- IEEE double floating-point number. See
- QCBOREncode_AddBigFloatBigNum() for even more precision.
-
- For example, 1.5 would be represented by a mantissa of 3 and an
- exponent of -1.
-
- The exponent and mantissa have the range from @c INT64_MIN to
- @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
- to @c UINT64_MAX, but this implementation doesn't support this range to
- reduce code size and interface complexity a little).
-
- CBOR Preferred encoding of the integers is used, thus they will be encoded
- in the smallest number of bytes possible.
-
- This can also be used to represent floating-point numbers in
- environments that don't support IEEE 754.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent);
-
-
-/**
- @brief Add a big floating-point number with a big number mantissa to
- the encoded output.
-
- @param[in] pCtx The encoding context to add the bigfloat to.
- @param[in] Mantissa The mantissa.
- @param[in] bIsNegative false if mantissa is positive, true if negative.
- @param[in] nBase2Exponent The exponent.
-
- This is the same as QCBOREncode_AddBigFloat() except the mantissa is
- a big number (See QCBOREncode_AddPositiveBignum()) allowing for
- arbitrary precision.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent);
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
-
-
-/**
- @brief Add a text URI to the encoded output.
-
- @param[in] pCtx The encoding context to add the URI to.
- @param[in] URI Pointer and length of the URI.
-
- The format of URI must be per [RFC 3986]
- (https://tools.ietf.org/html/rfc3986).
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_URI indicating the text string is a URI.
-
- A URI in a NULL-terminated string, @c szURI, can be easily added with
- this code:
-
- QCBOREncode_AddURI(pCtx, UsefulBuf_FromSZ(szURI));
- */
-static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI);
-
-static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI);
-
-static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI);
-
-
-/**
- @brief Add Base64-encoded text to encoded output.
-
- @param[in] pCtx The encoding context to add the base-64 text to.
- @param[in] B64Text Pointer and length of the base-64 encoded text.
-
- The text content is Base64 encoded data per [RFC 4648]
- (https://tools.ietf.org/html/rfc4648).
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_B64 indicating the text string is Base64 encoded.
- */
-static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
-
-
-/**
- @brief Add base64url encoded data to encoded output.
-
- @param[in] pCtx The encoding context to add the base64url to.
- @param[in] B64Text Pointer and length of the base64url encoded text.
-
- The text content is base64URL encoded text as per [RFC 4648]
- (https://tools.ietf.org/html/rfc4648).
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_B64URL indicating the text string is a Base64url encoded.
- */
-static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
-
-
-/**
- @brief Add Perl Compatible Regular Expression.
-
- @param[in] pCtx The encoding context to add the regular expression to.
- @param[in] Regex Pointer and length of the regular expression.
-
- The text content is Perl Compatible Regular
- Expressions (PCRE) / JavaScript syntax [ECMA262].
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_REGEX indicating the text string is a regular expression.
- */
-static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex);
-
-static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex);
-
-static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex);
-
-
-/**
- @brief MIME encoded text to the encoded output.
-
- @param[in] pCtx The encoding context to add the MIME data to.
- @param[in] MIMEData Pointer and length of the regular expression.
-
- The text content is in MIME format per [RFC 2045]
- (https://tools.ietf.org/html/rfc2045) including the headers. Note
- that this only supports text-format MIME. Binary MIME is not
- supported.
-
- It is output as CBOR major type 3, a text string, with tag
- @ref CBOR_TAG_MIME indicating the text string is MIME data.
- */
-static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData);
-
-static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData);
-
-static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData);
-
-
-/**
- @brief Add an RFC 3339 date string
-
- @param[in] pCtx The encoding context to add the date to.
- @param[in] szDate Null-terminated string with date to add.
-
- The string szDate should be in the form of [RFC 3339]
- (https://tools.ietf.org/html/rfc3339) as defined by section 3.3 in
- [RFC 4287] (https://tools.ietf.org/html/rfc4287). This is as
- described in section 2.4.1 in [RFC 7049]
- (https://tools.ietf.org/html/rfc7049).
-
- Note that this function doesn't validate the format of the date string
- at all. If you add an incorrect format date string, the generated
- CBOR will be incorrect and the receiver may not be able to handle it.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate);
-
-static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate);
-
-static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate);
-
-
-/**
- @brief Add a standard Boolean.
-
- @param[in] pCtx The encoding context to add the Boolean to.
- @param[in] b true or false from @c <stdbool.h>.
-
- Adds a Boolean value as CBOR major type 7.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b);
-
-static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b);
-
-static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b);
-
-
-
-/**
- @brief Add a NULL to the encoded output.
-
- @param[in] pCtx The encoding context to add the NULL to.
-
- Adds the NULL value as CBOR major type 7.
-
- This NULL doesn't have any special meaning in CBOR such as a
- terminating value for a string or an empty value.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Add an "undef" to the encoded output.
-
- @param[in] pCtx The encoding context to add the "undef" to.
-
- Adds the undef value as CBOR major type 7.
-
- Note that this value will not translate to JSON.
-
- This Undef doesn't have any special meaning in CBOR such as a
- terminating value for a string or an empty value.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Indicates that the next items added are in an array.
-
- @param[in] pCtx The encoding context to open the array in.
-
- Arrays are the basic CBOR aggregate or structure type. Call this
- function to start or open an array. Then call the various @c
- QCBOREncode_AddXxx() functions to add the items that go into the
- array. Then call QCBOREncode_CloseArray() when all items have been
- added. The data items in the array can be of any type and can be of
- mixed types.
-
- Nesting of arrays and maps is allowed and supported just by calling
- QCBOREncode_OpenArray() again before calling
- QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this
- implementation does in order to keep it smaller and simpler. The
- limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of
- times this can be called without calling
- QCBOREncode_CloseArray(). QCBOREncode_Finish() will return @ref
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function
- just sets an error state and returns no value when this occurs.
-
- If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to a
- single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be returned
- when QCBOREncode_Finish() is called.
-
- An array itself must have a label if it is being added to a map.
- Note that array elements do not have labels (but map elements do).
-
- An array itself may be tagged by calling QCBOREncode_AddTag() before this call.
- */
-static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Close an open array.
-
- @param[in] pCtx The encoding context to close the array in.
-
- The closes an array opened by QCBOREncode_OpenArray(). It reduces
- nesting level by one. All arrays (and maps) must be closed before
- calling QCBOREncode_Finish().
-
- When an error occurs as a result of this call, the encoder records
- the error and enters the error state. The error will be returned when
- QCBOREncode_Finish() is called.
-
- If this has been called more times than QCBOREncode_OpenArray(), then
- @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish()
- is called.
-
- If this is called and it is not an array that is currently open, @ref
- QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
- is called.
- */
-static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
-
-
-/**
- @brief Indicates that the next items added are in a map.
-
- @param[in] pCtx The encoding context to open the map in.
-
- See QCBOREncode_OpenArray() for more information, particularly error
- handling.
-
- CBOR maps are an aggregate type where each item in the map consists
- of a label and a value. They are similar to JSON objects.
-
- The value can be any CBOR type including another map.
-
- The label can also be any CBOR type, but in practice they are
- typically, integers as this gives the most compact output. They might
- also be text strings which gives readability and translation to JSON.
-
- Every @c QCBOREncode_AddXxx() call has one version that ends with @c
- InMap for adding items to maps with string labels and one that ends
- with @c InMapN that is for adding with integer labels.
-
- RFC 7049 uses the term "key" instead of "label".
-
- If you wish to use map labels that are neither integer labels nor
- text strings, then just call the QCBOREncode_AddXxx() function
- explicitly to add the label. Then call it again to add the value.
-
- See the [RFC 7049] (https://tools.ietf.org/html/rfc7049) for a lot
- more information on creating maps.
- */
-static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-
-/**
- @brief Close an open map.
-
- @param[in] pCtx The encoding context to close the map in .
-
- This closes a map opened by QCBOREncode_OpenMap(). It reduces nesting
- level by one.
-
- When an error occurs as a result of this call, the encoder records
- the error and enters the error state. The error will be returned when
- QCBOREncode_Finish() is called.
-
- If this has been called more times than QCBOREncode_OpenMap(),
- then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
- QCBOREncode_Finish() is called.
-
- If this is called and it is not a map that is currently open, @ref
- QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
- is called.
- */
-static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx);
-
-
-/**
- @brief Indicate start of encoded CBOR to be wrapped in a bstr.
-
- @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in.
-
- All added encoded items between this call and a call to
- QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will
- appear in the final output as a byte string. That byte string will
- contain encoded CBOR. This increases nesting level by one.
-
- The typical use case is for encoded CBOR that is to be
- cryptographically hashed, as part of a [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152) implementation.
-
- Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() avoids
- having to encode the items first in one buffer (e.g., the COSE
- payload) and then add that buffer as a bstr to another encoding
- (e.g. the COSE to-be-signed bytes, the @c Sig_structure) potentially
- halving the memory needed.
-
- RFC 7049 states the purpose of this wrapping is to prevent code
- relaying the signed data but not verifying it from tampering with the
- signed data thus making the signature unverifiable. It is also quite
- beneficial for the signature verification code. Standard CBOR
- decoders usually do not give access to partially decoded CBOR as
- would be needed to check the signature of some CBOR. With this
- wrapping, standard CBOR decoders can be used to get to all the data
- needed for a signature verification.
- */
-static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Close a wrapping bstr.
-
- @param[in] pCtx The encoding context to close of bstr wrapping in.
- @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr
- as well as the bytes in @c pWrappedCBOR.
- @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes.
-
- The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces
- nesting level by one.
-
- A pointer and length of the enclosed encoded CBOR is returned in @c
- *pWrappedCBOR if it is not @c NULL. The main purpose of this is so
- this data can be hashed (e.g., with SHA-256) as part of a [RFC 8152,
- COSE] (https://tools.ietf.org/html/rfc8152)
- implementation. **WARNING**, this pointer and length should be used
- right away before any other calls to @c QCBOREncode_CloseXxx() as
- they will move data around and the pointer and length will no longer
- be to the correct encoded CBOR.
-
- When an error occurs as a result of this call, the encoder records
- the error and enters the error state. The error will be returned when
- QCBOREncode_Finish() is called.
-
- If this has been called more times than QCBOREncode_BstrWrap(), then
- @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
- QCBOREncode_Finish() is called.
-
- If this is called and it is not a wrapping bstr that is currently
- open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when
- QCBOREncode_Finish() is called.
-
- QCBOREncode_CloseBstrWrap() is a deprecated version of this function
- that is equivalent to the call with @c bIncludeCBORHead @c true.
- */
-void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR);
-
-static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR);
-
-
-/**
- @brief Add some already-encoded CBOR bytes.
-
- @param[in] pCtx The encoding context to add the already-encode CBOR to.
- @param[in] Encoded The already-encoded CBOR to add to the context.
-
- The encoded CBOR being added must be fully conforming CBOR. It must
- be complete with no arrays or maps that are incomplete. While this
- encoder doesn't ever produce indefinite lengths, it is OK for the
- raw CBOR added here to have indefinite lengths.
-
- The raw CBOR added here is not checked in anyway. If it is not
- conforming or has open arrays or such, the final encoded CBOR
- will probably be wrong or not what was intended.
-
- If the encoded CBOR being added here contains multiple items, they
- must be enclosed in a map or array. At the top level the raw
- CBOR must be a single data item.
- */
-static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded);
-
-static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded);
-
-static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded);
-
-
-/**
- @brief Get the encoded result.
-
- @param[in] pCtx The context to finish encoding with.
- @param[out] pEncodedCBOR Pointer and length of encoded CBOR.
-
- @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error
-
- @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error
-
- @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error
-
- @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size
-
- @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size
-
- @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit
-
- @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit
-
- If this returns success @ref QCBOR_SUCCESS the encoding was a success
- and the return length is correct and complete.
-
- If no buffer was passed to QCBOREncode_Init(), then only the length
- was computed. If a buffer was passed, then the encoded CBOR is in the
- buffer.
-
- Encoding errors primarily manifest here as most other encoding function
- do no return an error. They just set the error state in the encode
- context after which no encoding function does anything.
-
- Three types of errors manifest here. The first type are nesting
- errors where the number of @c QCBOREncode_OpenXxx() calls do not
- match the number @c QCBOREncode_CloseXxx() calls. The solution is to
- fix the calling code.
-
- The second type of error is because the buffer given is either too
- small or too large. The remedy is to give a correctly sized buffer.
-
- The third type are due to limits in this implementation. @ref
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by encoding the
- CBOR in two (or more) phases and adding the CBOR from the first phase
- to the second with @c QCBOREncode_AddEncoded().
-
- If an error is returned, the buffer may have partially encoded
- incorrect CBOR in it and it should not be used. Likewise, the length
- may be incorrect and should not be used.
-
- Note that the error could have occurred in one of the many @c
- QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was
- called. This error handling reduces the CBOR implementation size but
- makes debugging harder.
-
- This may be called multiple times. It will always return the same. It
- can also be interleaved with calls to QCBOREncode_FinishGetSize().
-
- QCBOREncode_GetErrorState() can be called to get the current
- error state and abort encoding early as an optimization, but is
- is never required.
- */
-QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
-
-
-/**
- @brief Get the encoded CBOR and error status.
-
- @param[in] pCtx The context to finish encoding with.
- @param[out] uEncodedLen The length of the encoded or potentially
- encoded CBOR in bytes.
-
- @return The same errors as QCBOREncode_Finish().
-
- This functions the same as QCBOREncode_Finish(), but only returns the
- size of the encoded output.
- */
-QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen);
-
-
-/**
- @brief Indicate whether output buffer is NULL or not.
-
- @param[in] pCtx The encoding context.
-
- @return 1 if the output buffer is @c NULL.
-
- Sometimes a @c NULL input buffer is given to QCBOREncode_Init() so
- that the size of the generated CBOR can be calculated without
- allocating a buffer for it. This returns 1 when the output buffer is
- NULL and 0 when it is not.
-*/
-static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);
-
- /**
- @brief Get the encoding error state.
-
- @param[in] pCtx The encoding context.
-
- @return One of \ref QCBORError. See return values from
- QCBOREncode_Finish()
-
- Normally encoding errors need only be handled at the end of encoding
- when QCBOREncode_Finish() is called. This can be called to get the
- error result before finish should there be a need to halt encoding
- before QCBOREncode_Finish() is called.
-*/
-static QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx);
-
-
-/**
- Encode the "head" of a CBOR data item.
-
- @param buffer Buffer to output the encoded head to; must be
- @ref QCBOR_HEAD_BUFFER_SIZE bytes in size.
- @param uMajorType One of CBOR_MAJOR_TYPE_XX.
- @param uMinLen The minimum number of bytes to encode uNumber. Almost always
- this is 0 to use preferred minimal encoding. If this is 4,
- then even the values 0xffff and smaller will be encoded
- as in 4 bytes. This is used primarily when encoding a
- float or double put into uNumber as the leading zero bytes
- for them must be encoded.
- @param uNumber The numeric argument part of the CBOR head.
- @return Pointer and length of the encoded head or
- @NULLUsefulBufC if the output buffer is too small.
-
- Callers to need to call this for normal CBOR encoding. Note that it doesn't even
- take a @ref QCBOREncodeContext argument.
-
- This encodes the major type and argument part of a data item. The
- argument is an integer that is usually either the value or the length
- of the data item.
-
- This is exposed in the public interface to allow hashing of some CBOR
- data types, bstr in particular, a chunk at a time so the full CBOR
- doesn't have to be encoded in a contiguous buffer.
-
- For example, if you have a 100,000 byte binary blob in a buffer that
- needs to be a bstr encoded and then hashed. You could allocate a
- 100,010 byte buffer and encode it normally. Alternatively, you can
- encode the head in a 10 byte buffer with this function, hash that and
- then hash the 100,000 bytes using the same hash context.
-
- See also QCBOREncode_AddBytesLenOnly();
- */
-UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
- uint8_t uMajorType,
- uint8_t uMinLen,
- uint64_t uNumber);
-
-
-/**
- QCBORDecodeContext is the data type that holds context decoding the
- data items for some received CBOR. It is about 100 bytes, so it can
- go on the stack. The contents are opaque, and the caller should not
- access any internal items. A context may be re used serially as long
- as it is re initialized.
- */
-typedef struct _QCBORDecodeContext QCBORDecodeContext;
-
-
-/**
- Initialize the CBOR decoder context.
-
- @param[in] pCtx The context to initialize.
- @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded.
- @param[in] nMode See below and @ref QCBORDecodeMode.
-
- Initialize context for a pre-order traversal of the encoded CBOR
- tree.
-
- Most CBOR decoding can be completed by calling this function to start
- and QCBORDecode_GetNext() in a loop.
-
- If indefinite-length strings are to be decoded, then
- QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
- called to set up a string allocator.
-
- If tags other than built-in tags are to be recognized and recorded in
- @c uTagBits, then QCBORDecode_SetCallerConfiguredTagList() must be
- called. The built-in tags are those for which a macro of the form @c
- CBOR_TAG_XXX is defined.
-
- Three decoding modes are supported. In normal mode, @ref
- QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers
- are accepted as map labels. If a label is other than these, the error
- @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
-
- 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
- returned by QCBORDecode_GetNext() if anything but a text string label
- is encountered.
-
- In @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special
- arrays. They will be return with special @c uDataType @ref
- QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the number of items, will be
- double what it would be for a normal map because the labels are also
- counted. This mode is useful for decoding CBOR that has labels that
- are not integers or text strings, but the caller must manage much of
- the map decoding.
- */
-void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
-
-
-/**
- @brief Set up the MemPool string allocator for indefinite-length strings.
-
- @param[in] pCtx The decode context.
- @param[in] MemPool The pointer and length of the memory pool.
- @param[in] bAllStrings If true, all strings, even of definite
- length, will be allocated with the string
- allocator.
-
- @return Error if the MemPool was less than @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE.
-
- indefinite-length strings (text and byte) cannot be decoded unless
- there is a string allocator configured. MemPool is a simple built-in
- string allocator that allocates bytes from a memory pool handed to it
- by calling this function. The memory pool is just a pointer and
- length for some block of memory that is to be used for string
- allocation. It can come from the stack, heap or other.
-
- The memory pool must be @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE plus
- space for all the strings allocated. There is no overhead per string
- allocated. A conservative way to size this buffer is to make it the
- same size as the CBOR being decoded plus @ref
- QCBOR_DECODE_MIN_MEM_POOL_SIZE.
-
- This memory pool is used for all indefinite-length strings that are
- text strings or byte strings, including strings used as labels.
-
- The pointers to strings in @ref QCBORItem will point into the memory
- pool set here. They do not need to be individually freed. Just
- discard the buffer when they are no longer needed.
-
- If @c bAllStrings is set, then the size will be the overhead plus the
- space to hold **all** strings, definite and indefinite-length, value
- or label. The advantage of this is that after the decode is complete,
- the original memory holding the encoded CBOR does not need to remain
- valid.
-
- If this function is never called because there is no need to support
- indefinite-length strings, the internal MemPool implementation should
- be dead-stripped by the loader and not add to code size.
- */
-QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings);
-
-
-/**
- @brief Sets up a custom string allocator for indefinite-length strings
-
- @param[in] pCtx The decoder context to set up an
- allocator for.
- @param[in] pfAllocateFunction Pointer to function that will be
- called by QCBOR for allocations and
- frees.
- @param[in] pAllocateContext Context passed to @c
- pfAllocateFunction.
- @param[in] bAllStrings If true, all strings, even of definite
- length, will be allocated with the
- string allocator.
-
- indefinite-length strings (text and byte) cannot be decoded unless
- there a string allocator is configured. QCBORDecode_SetUpAllocator()
- allows the caller to configure an external string allocator
- implementation if the internal string allocator is not suitable. See
- QCBORDecode_SetMemPool() to configure the internal allocator. Note
- that the internal allocator is not automatically set up.
-
- The string allocator configured here can be a custom one designed and
- implemented by the caller. See @ref QCBORStringAllocate for the
- requirements for a string allocator implementation.
-
- A malloc-based string external allocator can be obtained by calling
- @c QCBORDecode_MakeMallocStringAllocator(). It will return a function
- and pointer that can be given here as @c pAllocatorFunction and @c
- pAllocatorContext. It uses standard @c malloc() so @c free() must be
- called on all strings marked by @c uDataAlloc @c == @c 1 or @c
- uLabelAlloc @c == @c 1 in @ref QCBORItem.
-
- Note that an older version of this function took an allocator
- structure, rather than single function and pointer. The older
- version @c QCBORDecode_MakeMallocStringAllocator() also implemented
- the older interface.
- */
-void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx,
- QCBORStringAllocate pfAllocateFunction,
- void *pAllocateContext,
- bool bAllStrings);
-
-/**
- @brief Configure list of caller-selected tags to be recognized.
-
- @param[in] pCtx The decode context.
- @param[out] pTagList Structure holding the list of tags to configure.
-
- This is used to tell the decoder about tags beyond those that are
- built-in that should be recognized. The built-in tags are those with
- macros of the form @c CBOR_TAG_XXX.
-
- The list pointed to by @c pTagList must persist during decoding. No
- copy of it is made.
-
- The maximum number of tags that can be added is @ref
- QCBOR_MAX_CUSTOM_TAGS. If a list larger than this is given, the
- error will be returned when QCBORDecode_GetNext() is called, not
- here.
-
- See description of @ref QCBORTagListIn.
- */
-void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList);
-
-
-/**
- @brief Gets the next item (integer, byte string, array...) in
- preorder traversal of CBOR tree.
-
- @param[in] pCtx The decoder context.
- @param[out] pDecodedItem Holds the CBOR item just decoded.
-
- @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Not well-formed, one of the
- chunks in indefinite-length
- string is wrong type.
-
- @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Not well-formed, array or map
- not closed.
-
- @retval QCBOR_ERR_UNSUPPORTED Not well-formed, input contains
- unsupported CBOR.
-
- @retval QCBOR_ERR_HIT_END Not well-formed, unexpectedly ran out
- of bytes.
-
- @retval QCBOR_ERR_BAD_TYPE_7 Not well-formed, bad simple type value.
-
- @retval QCBOR_ERR_BAD_BREAK Not well-formed, break occurs where
- not allowed.
-
- @retval QCBOR_ERR_EXTRA_BYTES Not well-formed, unprocessed bytes at
- the end.
-
- @retval QCBOR_ERR_BAD_INT Not well-formed, length of integer is
- bad.
-
- @retval QCBOR_ERR_BAD_OPT_TAG Invalid CBOR, tag on wrong type.
-
- @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit, array or map
- too long.
-
- @retval QCBOR_ERR_INT_OVERFLOW Implementation limit, negative
- integer too large.
-
- @retval QCBOR_ERR_DATE_OVERFLOW Implementation limit, date larger
- than can be handled.
-
- @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit, nesting
- too deep.
-
- @retval QCBOR_ERR_STRING_ALLOCATE Resource exhaustion, string allocator
- failed.
-
- @retval QCBOR_ERR_MAP_LABEL_TYPE Configuration error / Implementation
- limit encountered a map label this is
- not a string on an integer.
-
- @retval QCBOR_ERR_NO_STRING_ALLOCATOR Configuration error, encountered
- indefinite-length string with no
- allocator configured.
- @retval QCBOR_ERR_NO_MORE_ITEMS No more bytes to decode. The previous
- item was successfully decoded. This
- is usually how the non-error end of
- a CBOR stream / sequence is detected.
-
- @c pDecodedItem is filled in with the value parsed. Generally, the
- following data is returned in the structure:
-
- - @c uDataType which indicates which member of the @c val union the
- data is in. This decoder figures out the type based on the CBOR
- major type, the CBOR "additionalInfo", the CBOR optional tags and
- the value of the integer.
-
- - The value of the item, which might be an integer, a pointer and a
- length, the count of items in an array, a floating-point number or
- other.
-
- - The nesting level for maps and arrays.
-
- - The label for an item in a map, which may be a text or byte string
- or an integer.
-
- - The CBOR optional tag or tags.
-
- See documentation on in the data type @ref _QCBORItem for all the
- details on what is returned.
-
- This function handles arrays and maps. When first encountered a @ref
- QCBORItem will be returned with major type @ref QCBOR_TYPE_ARRAY or
- @ref QCBOR_TYPE_MAP. @c QCBORItem.val.uCount will indicate the number
- of Items in the array or map. Typically, an implementation will call
- QCBORDecode_GetNext() in a for loop to fetch them all. When decoding
- indefinite-length maps and arrays, @c QCBORItem.val.uCount is @c
- UINT16_MAX and @c uNextNestLevel must be used to know when the end of
- a map or array is reached.
-
- Nesting level 0 is the outside top-most nesting level. For example,
- in a CBOR structure with two items, an integer and a byte string
- only, both would be at nesting level 0. A CBOR structure with an
- array open, an integer and a byte string, would have the integer and
- byte string as nesting level 1.
-
- Here is an example of how the nesting level is reported with no arrays
- or maps at all.
-
- @verbatim
- CBOR Structure Nesting Level
- Integer 0
- Byte String 0
- @endverbatim
-
- Here is an example of how the nesting level is reported with a simple
- array and some top-level items.
-
- @verbatim
- Integer 0
- Array (with 2 items) 0
- Byte String 1
- Byte string 1
- Integer 0
- @endverbatim
-
-
- Here's a more complex example
- @verbatim
-
- Map with 2 items 0
- Text string 1
- Array with 3 integers 1
- integer 2
- integer 2
- integer 2
- text string 1
- byte string 1
- @endverbatim
-
- In @ref _QCBORItem, @c uNextNestLevel is the nesting level for the
- next call to QCBORDecode_GetNext(). It indicates if any maps or
- arrays were closed out during the processing of the just-fetched @ref
- QCBORItem. This processing includes a look-ahead for any breaks that
- close out indefinite-length arrays or maps. This value is needed to
- be able to understand the hierarchical structure. If @c
- uNextNestLevel is not equal to @c uNestLevel the end of the current
- map or array has been encountered. This works the same for both
- definite and indefinite-length arrays.
-
- This decoder support CBOR type 6 tagging. The decoding of particular
- given tag value may be supported in one of three different ways.
-
- First, some common tags are fully and transparently supported by
- automatically decoding them and returning them in a @ref QCBORItem.
- These tags have a @c QCBOR_TYPE_XXX associated with them and manifest
- pretty much the same as a standard CBOR type. @ref
- QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref QCBORItem
- is an example.
-
- Second are tags that are automatically recognized, but not decoded.
- These are tags that have a @c \#define of the form @c CBOR_TAG_XXX.
- These are recorded in the @c uTagBits member of @ref QCBORItem. There
- is an internal table that maps each bit to a particular tag value
- allowing up to 64 tags on an individual item to be reported (it is
- rare to have more than one or two). To find out if a particular tag
- value is set call QCBORDecode_IsTagged() on the @ref QCBORItem. See
- also QCBORDecode_GetNextWithTags().
-
- Third are tags that are not automatically recognized, because they
- are proprietary, custom or more recently registered with [IANA]
- (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). The
- internal mapping table has to be configured to recognize these. Call
- QCBORDecode_SetCallerConfiguredTagList() to do that. Then
- QCBORDecode_IsTagged() will work with them.
-
- The actual decoding of tags supported in the second and third way
- must be handled by the caller. Often this is simply verifying that
- the expected tag is present on a map, byte string or such. In other
- cases, there might a complicated map structure to decode.
-
- 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.
-
- If any error occurs, \c uDataType and \c uLabelType will be set
- to \ref QCBOR_TYPE_NONE. If there is no need to know the specific
- error, \ref QCBOR_TYPE_NONE can be checked for and the return value
- ignored.
-
- Errors fall in several categories as noted in list above:
-
- - Not well-formed errors are those where there is something
- syntactically and fundamentally wrong with the CBOR being
- decoded. Encoding should stop completely.
-
- - Invalid CBOR is well-formed, but still not correct. It is probably
- best to stop decoding, but not necessary.
-
- - This implementation has some size limits. They should rarely be
- encountered. If they are it may because something is wrong with the
- CBOR, for example an array size is incorrect.
-
- - Resource exhaustion. This only occurs when a string allocator is
- configured to handle indefinite-length strings as other than that,
- this implementation does no dynamic memory allocation.
-
- - There are a few CBOR constructs that are not handled without some
- extra configuration. These are indefinite length strings and maps
- with labels that are not strings or integers. See QCBORDecode_Init().
-
- */
-QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
-
-
-/**
- @brief Gets the next item including full list of tags for item.
-
- @param[in] pCtx The decoder context.
- @param[out] pDecodedItem Holds the CBOR item just decoded.
- @param[in,out] pTagList On input array to put tags in; on output
- the tags on this item. See
- @ref QCBORTagListOut.
-
- @return See return values for QCBORDecode_GetNext().
-
- @retval QCBOR_ERR_TOO_MANY_TAGS The size of @c pTagList is too small.
-
- This works the same as QCBORDecode_GetNext() except that it also
- returns the full list of tags for the data item. This function should
- only be needed when parsing CBOR to print it out or convert it to
- some other format. It should not be needed to implement a CBOR-based
- protocol. See QCBORDecode_GetNext() for the main description of tag
- decoding.
-
- Tags will be returned here whether or not they are in the built-in or
- caller-configured tag lists.
-
- CBOR has no upper bound of limit on the number of tags that can be
- associated with a data item though in practice the number of tags on
- an item will usually be small, perhaps less than five. 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 function is separate from QCBORDecode_GetNext() so as to not
- have to make @ref QCBORItem large enough to be able to hold a full
- list of tags. Even a list of five tags would nearly double its size
- because tags can be a @c uint64_t ).
- */
-QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList);
-
-
-/**
- @brief Determine if a CBOR item was tagged with a particular tag
-
- @param[in] pCtx The decoder context.
- @param[in] pItem The CBOR item to check.
- @param[in] uTag The tag to check, one of @c CBOR_TAG_XXX.
-
- @return 1 if it was tagged, 0 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.
- */
-int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag);
-
-
-/**
- Check whether all the bytes have been decoded and maps and arrays closed.
-
- @param[in] pCtx The context to check.
-
- @return An error or @ref QCBOR_SUCCESS.
-
- This tells you if all the bytes given to QCBORDecode_Init() have been
- consumed and whether all maps and arrays were closed. The decode is
- considered to be incorrect or incomplete if not and an error will be
- returned.
- */
-QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
-
-
-
-
-/**
- @brief Convert int64_t to smaller integers safely.
-
- @param [in] src An @c int64_t.
- @param [out] dest A smaller sized integer to convert to.
-
- @return 0 on success -1 if not
-
- When decoding an integer, the CBOR decoder will return the value as
- an int64_t unless the integer is in the range of @c INT64_MAX and @c
- UINT64_MAX. That is, unless the value is so large that it can only be
- represented as a @c uint64_t, it will be an @c int64_t.
-
- CBOR itself doesn't size the individual integers it carries at
- all. The only limits it puts on the major integer types is that they
- are 8 bytes or less in length. Then encoders like this one use the
- smallest number of 1, 2, 4 or 8 bytes to represent the integer based
- on its value. There is thus no notion that one data item in CBOR is
- a 1-byte integer and another is a 4-byte integer.
-
- The interface to this CBOR encoder only uses 64-bit integers. Some
- CBOR protocols or implementations of CBOR protocols may not want to
- work with something smaller than a 64-bit integer. Perhaps an array
- of 1000 integers needs to be sent and none has a value larger than
- 50,000 and are represented as @c uint16_t.
-
- The sending / encoding side is easy. Integers are temporarily widened
- to 64-bits as a parameter passing through QCBOREncode_AddInt64() and
- encoded in the smallest way possible for their value, possibly in
- less than an @c uint16_t.
-
- On the decoding side the integers will be returned at @c int64_t even if
- they are small and were represented by only 1 or 2 bytes in the
- encoded CBOR. The functions here will convert integers to a small
- representation with an overflow check.
-
- (The decoder could have support 8 different integer types and
- represented the integer with the smallest type automatically, but
- this would have made the decoder more complex and code calling the
- decoder more complex in most use cases. In most use cases on 64-bit
- machines it is no burden to carry around even small integers as
- 64-bit values).
- */
-static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest)
-{
- if(src > INT32_MAX || src < INT32_MIN) {
- return -1;
- } else {
- *dest = (int32_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest)
-{
- if(src > INT16_MAX || src < INT16_MIN) {
- return -1;
- } else {
- *dest = (int16_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest)
-{
- if(src > INT8_MAX || src < INT8_MIN) {
- return -1;
- } else {
- *dest = (int8_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest)
-{
- if(src > UINT32_MAX || src < 0) {
- return -1;
- } else {
- *dest = (uint32_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest)
-{
- if(src > UINT16_MAX || src < 0) {
- return -1;
- } else {
- *dest = (uint16_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest)
-{
- if(src > UINT8_MAX || src < 0) {
- return -1;
- } else {
- *dest = (uint8_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest)
-{
- if(src > 0) {
- return -1;
- } else {
- *dest = (uint64_t) src;
- }
- return 0;
-}
-
-
-
-
-
-/* ===========================================================================
- BEGINNING OF PRIVATE INLINE IMPLEMENTATION
-
- =========================================================================== */
-
-/**
- @brief Semi-private method to add a buffer full of bytes to encoded output
-
- @param[in] pCtx The encoding context to add the integer to.
- @param[in] uMajorType The CBOR major type of the bytes.
- @param[in] Bytes The bytes to add.
-
- Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
- QCBOREncode_AddEncoded() instead. They are inline functions that call
- this and supply the correct major type. This function is public to
- make the inline functions work to keep the overall code size down and
- because the C language has no way to make it private.
-
- If this is called the major type should be @c
- CBOR_MAJOR_TYPE_TEXT_STRING, @c CBOR_MAJOR_TYPE_BYTE_STRING or @c
- CBOR_MAJOR_NONE_TYPE_RAW. The last one is special for adding
- already-encoded CBOR.
- */
-void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes);
-
-
-/**
- @brief Semi-private method to open a map, array or bstr-wrapped CBOR
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close
-
- Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
- QCBOREncode_BstrWrap() instead of this.
- */
-void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to open a map, array with indefinite length
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close
-
- Call QCBOREncode_OpenArrayIndefiniteLength() or
- QCBOREncode_OpenMapIndefiniteLength() instead of this.
- */
-void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to close a map, array or bstr wrapped CBOR
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close.
-
- Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
- */
-void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to close a map, array with indefinite length
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close.
-
- Call QCBOREncode_CloseArrayIndefiniteLength() or
- QCBOREncode_CloseMapIndefiniteLength() instead of this.
- */
-void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx,
- uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to add simple types.
-
- @param[in] pCtx The encoding context to add the simple value to.
- @param[in] uMinLen Minimum encoding size for uNum. Usually 0.
- @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
-
- This is used to add simple types like true and false.
-
- Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
- QCBOREncode_AddUndef() instead of this.
-
- This function can add simple values that are not defined by CBOR
- yet. This expansion point in CBOR should not be used unless they are
- standardized.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, uint8_t uMinLen, uint64_t uNum);
-
-
-/**
- @brief Semi-private method to add bigfloats and decimal fractions.
-
- @param[in] pCtx The encoding context to add the value to.
- @param[in] uTag The type 6 tag indicating what this is to be
- @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
- @c int64_t or the actual big number mantissa
- if not.
- @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
- @param[in] nExponent The exponent.
-
- This adds a tagged array with two members, the mantissa and exponent. The
- mantissa can be either a big number or an @c int64_t.
-
- Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
- QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
- is called instead of this.
- */
-void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pCtx,
- uint64_t uTag,
- UsefulBufC BigNumMantissa,
- bool bBigNumIsNegative,
- int64_t nMantissa,
- int64_t nExponent);
-
-/**
- @brief Semi-private method to add only the type and length of a byte string.
-
- @param[in] pCtx The context to initialize.
- @param[in] Bytes Pointer and length of the input data.
-
- This is the same as QCBOREncode_AddBytes() except it only adds the
- CBOR encoding for the type and the length. It doesn't actually add
- the bytes. You can't actually produce correct CBOR with this and the
- rest of this API. It is only used for a special case where
- the valid CBOR is created manually by putting this type and length in
- and then adding the actual bytes. In particular, when only a hash of
- the encoded CBOR is needed, where the type and header are hashed
- separately and then the bytes is hashed. This makes it possible to
- implement COSE Sign1 with only one copy of the payload in the output
- buffer, rather than two, roughly cutting memory use in half.
-
- This is only used for this odd case, but this is a supported
- tested function.
-
- See also QCBOREncode_EncodeHead().
-*/
-static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-
-
-
-static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
-{
- // Use _AddBuffer() because _AddSZString() is defined below, not above
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
- QCBOREncode_AddInt64(pCtx, uNum);
-}
-
-static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddInt64(pCtx, uNum);
-}
-
-
-static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum)
-{
- // Use _AddBuffer() because _AddSZString() is defined below, not above
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
- QCBOREncode_AddUInt64(pCtx, uNum);
-}
-
-static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddUInt64(pCtx, uNum);
-}
-
-
-static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
-}
-
-static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text)
-{
- // Use _AddBuffer() because _AddSZString() is defined below, not above
- QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel));
- QCBOREncode_AddText(pCtx, Text);
-}
-
-static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddText(pCtx, Text);
-}
-
-
-inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString)
-{
- QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString));
-}
-
-static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddSZString(pCtx, szString);
-}
-
-static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddSZString(pCtx, szString);
-}
-
-
-static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddDouble(pCtx, dNum);
-}
-
-static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddDouble(pCtx, dNum);
-}
-
-
-static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
- QCBOREncode_AddInt64(pCtx, date);
-}
-
-static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
- QCBOREncode_AddInt64(pCtx, date);
-}
-
-static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
- QCBOREncode_AddInt64(pCtx, date);
-}
-
-
-static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-
-static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-
-static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
-
-static inline void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx,
- CBOR_TAG_DECIMAL_FRACTION,
- NULLUsefulBufC,
- false,
- nMantissa,
- nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx,
- CBOR_TAG_DECIMAL_FRACTION,
- Mantissa, bIsNegative,
- 0,
- nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, NULLUsefulBufC, false, nMantissa, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, Mantissa, bIsNegative, 0, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
-}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
-
-
-static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
- QCBOREncode_AddText(pCtx, URI);
-}
-
-static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
- QCBOREncode_AddText(pCtx, URI);
-}
-
-static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
- QCBOREncode_AddText(pCtx, URI);
-}
-
-
-
-static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-
-static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-
-static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
- QCBOREncode_AddText(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
- QCBOREncode_AddText(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
- QCBOREncode_AddText(pCtx, Bytes);
-}
-
-
-static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
- QCBOREncode_AddText(pCtx, MIMEData);
-}
-
-static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
- QCBOREncode_AddText(pCtx, MIMEData);
-}
-
-static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
- QCBOREncode_AddText(pCtx, MIMEData);
-}
-
-
-static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
- QCBOREncode_AddSZString(pCtx, szDate);
-}
-
-static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
- QCBOREncode_AddSZString(pCtx, szDate);
-}
-
-static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
- QCBOREncode_AddSZString(pCtx, szDate);
-}
-
-
-static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum)
-{
- QCBOREncode_AddType7(pCtx, 0, uNum);
-}
-
-static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddSimple(pCtx, uSimple);
-}
-
-static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddSimple(pCtx, uSimple);
-}
-
-
-static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b)
-{
- uint8_t uSimple = CBOR_SIMPLEV_FALSE;
- if(b) {
- uSimple = CBOR_SIMPLEV_TRUE;
- }
- QCBOREncode_AddSimple(pCtx, uSimple);
-}
-
-static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBool(pCtx, b);
-}
-
-static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBool(pCtx, b);
-}
-
-
-static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL);
-}
-
-static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddNULL(pCtx);
-}
-
-static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddNULL(pCtx);
-}
-
-
-static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF);
-}
-
-static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddUndef(pCtx);
-}
-
-static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddUndef(pCtx);
-}
-
-
-static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
-}
-
-static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenArray(pCtx);
-}
-
-static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenArray(pCtx);
-}
-
-static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
-}
-
-
-static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
-}
-
-static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenMap(pCtx);
-}
-
-static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenMap(pCtx);
-}
-
-static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
-}
-
-static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
-}
-
-static inline void QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenArrayIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenArrayIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
-}
-
-
-static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
-}
-
-static inline void QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenMapIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenMapIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
-}
-
-
-static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING);
-}
-
-static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_BstrWrap(pCtx);
-}
-
-static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_BstrWrap(pCtx);
-}
-
-static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR)
-{
- QCBOREncode_CloseBstrWrap2(pCtx, true, pWrappedCBOR);
-}
-
-
-static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded);
-}
-
-static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddEncoded(pCtx, Encoded);
-}
-
-static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddEncoded(pCtx, Encoded);
-}
-
-
-static inline int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx)
-{
- return UsefulOutBuf_IsBufferNULL(&(pCtx->OutBuf));
-}
-
-static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx)
-{
- if(UsefulOutBuf_GetError(&(pCtx->OutBuf))) {
- // Items didn't fit in the buffer.
- // This check catches this condition for all the appends and inserts
- // so checks aren't needed when the appends and inserts are performed.
- // And of course UsefulBuf will never overrun the input buffer given
- // to it. No complex analysis of the error handling in this file is
- // needed to know that is true. Just read the UsefulBuf code.
- pCtx->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
- // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
- // OK. Once the caller fixes this, they'll be unmasked.
- }
-
- return (QCBORError)pCtx->uError;
-}
-
-
-/* ===========================================================================
- END OF PRIVATE INLINE IMPLEMENTATION
-
- =========================================================================== */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* defined(__QCBOR__qcbor__) */
+#include "qcbor/qcbor_encode.h"
+#include "qcbor/qcbor_decode.h"
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
new file mode 100644
index 0000000..16a53d3
--- /dev/null
+++ b/inc/qcbor/UsefulBuf.h
@@ -0,0 +1,2134 @@
+/*============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+/*============================================================================
+ FILE: UsefulBuf.h
+
+ DESCRIPTION: General purpose input and output buffers
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when who what, where, why
+ -------- ---- --------------------------------------------------
+ 1/25/2020 llundblade Add some casts so static anlyzers don't complain.
+ 5/21/2019 llundblade #define configs for efficient endianness handling.
+ 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL().
+ 3/23/2019 llundblade Big documentation & style update. No interface
+ change.
+ 3/6/2019 llundblade Add UsefulBuf_IsValue()
+ 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
+ 12/13/2018 llundblade Documentation improvements
+ 09/18/2018 llundblade Cleaner distinction between UsefulBuf and
+ UsefulBufC.
+ 02/02/18 llundbla Full support for integers in and out; fix pointer
+ alignment bug. Incompatible change: integers
+ in/out are now in network byte order.
+ 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
+ 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected
+ comparison for < or > for unequal length buffers.
+ Added UsefulBuf_Set() function.
+ 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
+ 11/13/16 llundbla Initial Version.
+
+ =============================================================================*/
+
+#ifndef _UsefulBuf_h
+#define _UsefulBuf_h
+
+
+/*
+ Configuration Options
+
+ This code is designed so it will work correctly and completely by
+ default. No configuration is necessary to make it work. None of the
+ following #defines need to be enabled. The code works and is very
+ portable with them all turned off.
+
+ All configuration options (USEFULBUF_CONFIG_XXX)
+ 1) Reduce code size
+ 2) Improve efficiency
+ 3) Both of the above
+
+ The efficiency improvements are not large, so the main reason really
+ is to reduce code size.
+
+ */
+
+
+/*
+ Endianness Configuration
+
+ By default, UsefulBuf does not need to know what the endianness of
+ the device is. All the code will run correctly on either big or
+ little endian CPUs.
+
+ Here's the recipe for configuring the endianness-related #defines
+ to use more efficient CPU/OS/compiler dependent features to reduce
+ code size. Note these only affect the integer arrays (tagged
+ arrays) feature of QCBOR. All other endianness handling in
+ QCBOR is integrated with code that also handles alignment and
+ preferred encoding.
+
+ The first option is to not define anything. This will work fine on
+ with all CPU's, OS's and compilers. The code for encoding
+ integers will be a little larger and slower.
+
+ If your CPU is big-endian then define USEFULBUF_CONFIG_BIG_ENDIAN. This
+ will give the most efficient code for big-endian CPUs. It will be small
+ and efficient because there will be no byte swapping.
+
+ Try defining USEFULBUF_CONFIG_HTON. This will work on most CPU's,
+ OS's and compilers, but not all. On big-endian CPUs this should give
+ the most efficient code, the same as USEFULBUF_CONFIG_BIG_ENDIAN
+ does. On little-endian CPUs it should call the system-defined byte
+ swapping method which is presumably implemented efficiently. In some
+ cases, this will be a dedicated byte swap instruction like Intel's
+ bswap.
+
+ If USEFULBUF_CONFIG_HTON works and you know your CPU is
+ little-endian, it is also good to define
+ USEFULBUF_CONFIG_LITTLE_ENDIAN.
+
+ if USEFULBUF_CONFIG_HTON doesn't work and you know your system is
+ little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and
+ USEFULBUF_CONFIG_BSWAP. This should call the most efficient
+ system-defined byte swap method. However, note
+ https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps
+ this is fixed now. Often hton() and ntoh() will call the built-in
+ __builtin_bswapXX()() function, so this size issue could affect
+ USEFULBUF_CONFIG_HTON.
+
+ Last, run the tests. They must all pass.
+
+ These #define config options affect the inline implementation of
+ UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
+ also affect the 16-, 32-bit, float and double versions of these
+ instructions. Since they are inline, the size effect is not in the
+ UsefulBuf object code, but in the calling code.
+
+ Summary:
+ USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian.
+ USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian.
+ USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to
+ handle big and little-endian with system option.
+ USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
+ use __builtin_bswapXX().
+ */
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
+#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN"
+#endif
+
+
+#include <stdint.h> // for uint8_t, uint16_t....
+#include <string.h> // for strlen, memcpy, memmove, memset
+#include <stddef.h> // for size_t
+
+
+#ifdef USEFULBUF_CONFIG_HTON
+#include <arpa/inet.h> // for htons, htonl, htonll, ntohs...
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ @file UsefulBuf.h
+
+ The goal of this code is to make buffer and pointer manipulation
+ easier and safer when working with binary data.
+
+ The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf
+ structures are used to represent buffers rather than ad hoc pointers and
+ lengths.
+
+ With these it will often be possible to write code that does little
+ or no direct pointer manipulation for copying and formatting
+ data. For example, the QCBOR encoder was written using these and
+ has no less pointer manipulation.
+
+ While it is true that object code using these functions will be a
+ little larger and slower than a white-knuckle clever use of pointers
+ might be, but not by that much or enough to have an effect for most
+ use cases. For security-oriented code this is highly
+ worthwhile. Clarity, simplicity, reviewability and are more
+ important.
+
+ There are some extra sanity and double checks in this code to help
+ catch coding errors and simple memory corruption. They are helpful,
+ but not a substitute for proper code review, input validation and
+ such.
+
+ This code consists of a lot of inline functions and a few that are
+ not. It should not generate very much object code, especially with
+ the optimizer turned up to @c -Os or @c -O3.
+ */
+
+
+/**
+ @ref UsefulBufC and @ref UsefulBuf are simple data structures to hold
+ a pointer and length for binary data. In C99 this data structure can
+ be passed on the stack making a lot of code cleaner than carrying
+ around a pointer and length as two parameters.
+
+ This is also conducive to secure coding practice as the length is
+ always carried with the pointer and the convention for handling a
+ pointer and a length is clear.
+
+ While it might be possible to write buffer and pointer code more
+ efficiently in some use cases, the thought is that unless there is an
+ extreme need for performance (e.g., you are building a
+ gigabit-per-second IP router), it is probably better to have cleaner
+ code you can be most certain about the security of.
+
+ The non-const @ref UsefulBuf is usually used to refer a buffer to be
+ filled in. The length is the size of the buffer.
+
+ The const @ref UsefulBufC is usually used to refer to some data that
+ has been filled in. The length is amount of valid data pointed to.
+
+ A common use is to pass a @ref UsefulBuf to a function, the function
+ fills it in, the function returns a @ref UsefulBufC. The pointer is
+ the same in both.
+
+ A @ref UsefulBuf is null, it has no value, when @c ptr in it is @c NULL.
+
+ There are utility functions for the following:
+ - Initializing
+ - Create initialized const @ref UsefulBufC from compiler literals
+ - Create initialized const @ref UsefulBufC from NULL-terminated string
+ - Make an empty @ref UsefulBuf on the stack
+ - Checking whether a @ref UsefulBuf is null, empty or both
+ - Copying, copying with offset, copying head or tail
+ - Comparing and finding substrings
+
+ See also @ref UsefulOutBuf. It is a richer structure that has both
+ the size of the valid data and the size of the buffer.
+
+ @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it
+ can go on the stack and be a function parameter or return value.
+
+ Another way to look at it is this. C has the NULL-terminated string
+ as a means for handling text strings, but no means or convention for
+ binary strings. Other languages do have such means, Rust, an
+ efficient compiled language, for example.
+
+ @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his
+ birthday. Eeyore's balloon fits beautifully, "it goes in and out
+ like anything".
+*/
+typedef struct q_useful_buf_c {
+ const void *ptr;
+ size_t len;
+} UsefulBufC;
+
+
+/**
+ This non-const @ref UsefulBuf is typically used for some allocated
+ memory that is to be filled in. The @c len is the amount of memory,
+ not the length of the valid data in the buffer.
+ */
+typedef struct q_useful_buf {
+ void *ptr;
+ size_t len;
+} UsefulBuf;
+
+
+/**
+ A null @ref UsefulBufC is one that has no value in the same way a @c
+ NULL pointer has no value. A @ref UsefulBufC is @c NULL when the @c
+ ptr field is @c NULL. It doesn't matter what @c len is. See
+ UsefulBuf_IsEmpty() for the distinction between null and empty.
+ */
+#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
+
+
+/**
+ A null @ref UsefulBuf is one that has no memory associated the same
+ way @c NULL points to nothing. It does not matter what @c len is.
+ */
+#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
+
+
+/**
+ @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not.
+
+ @param[in] UB The UsefulBuf to check.
+
+ @return 1 if it is @ref NULLUsefulBuf, 0 if not.
+ */
+static inline int UsefulBuf_IsNULL(UsefulBuf UB);
+
+
+/**
+ @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not.
+
+ @param[in] UB The @ref UsefulBufC to check.
+
+ @return 1 if it is @c NULLUsefulBufC, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLC(UsefulBufC UB);
+
+
+/**
+ @brief Check if a @ref UsefulBuf is empty or not.
+
+ @param[in] UB The @ref UsefulBuf to check.
+
+ @return 1 if it is empty, 0 if not.
+
+ An "empty" @ref UsefulBuf is one that has a value and can be
+ considered to be set, but that value is of zero length. It is empty
+ when @c len is zero. It doesn't matter what the @c ptr is.
+
+ A lot of uses will not need to clearly distinguish a @c NULL @ref
+ UsefulBuf from an empty one and can have the @c ptr @c NULL and the
+ @c len 0. However if a use of @ref UsefulBuf needs to make a
+ distinction then @c ptr should not be @c NULL when the @ref UsefulBuf
+ is considered empty, but not @c NULL.
+ */
+static inline int UsefulBuf_IsEmpty(UsefulBuf UB);
+
+
+/**
+ @brief Check if a @ref UsefulBufC is empty or not.
+
+ @param[in] UB The @ref UsefulBufC to check.
+
+ @return 1 if it is empty, 0 if not.
+ */
+static inline int UsefulBuf_IsEmptyC(UsefulBufC UB);
+
+
+/**
+ @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty.
+
+ @param[in] UB The @ref UsefulBuf to check.
+
+ @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB);
+
+
+/**
+ @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty.
+
+ @param[in] UB The @ref UsefulBufC to check.
+
+ @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB);
+
+
+/**
+ @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC.
+
+ @param[in] UB The @ref UsefulBuf to convert.
+
+ @return A @ref UsefulBufC struct.
+ */
+static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB);
+
+
+/**
+ @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf.
+
+ @param[in] UBC The @ref UsefulBuf to convert.
+
+ @return A non-const @ref UsefulBuf struct.
+ */
+static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
+
+
+/**
+ Convert a literal string to a @ref UsefulBufC.
+
+ @c szString must be a literal string that @c sizeof() works on. This
+ is better for literal strings than UsefulBuf_FromSZ() because it
+ generates less code. It will not work on non-literal strings.
+
+ The terminating \0 (NULL) is NOT included in the length!
+ */
+#define UsefulBuf_FROM_SZ_LITERAL(szString) \
+ ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+
+/**
+ Convert a literal byte array to a @ref UsefulBufC.
+
+ @c pBytes must be a literal string that @c sizeof() works on. It
+ will not work on non-literal arrays.
+ */
+#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
+ ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+
+/**
+ Make an automatic variable named @c name of type @ref UsefulBuf and
+ point it to a stack variable of the given @c size.
+ */
+#define UsefulBuf_MAKE_STACK_UB(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
+
+
+/**
+ Make a byte array in to a @ref UsefulBuf. This is usually used on
+ stack variables or static variables. Also see @ref
+ UsefulBuf_MAKE_STACK_UB.
+ */
+#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
+ ((UsefulBuf) {(pBytes), sizeof(pBytes)})
+
+
+/**
+ @brief Convert a NULL-terminated string to a @ref UsefulBufC.
+
+ @param[in] szString The string to convert.
+
+ @return A @ref UsefulBufC struct.
+
+ @c UsefulBufC.ptr points to the string so its lifetime must be
+ maintained.
+
+ The terminating \0 (NULL) is NOT included in the length.
+ */
+static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
+
+
+/**
+ @brief Copy one @ref UsefulBuf into another at an offset.
+
+ @param[in] Dest Destination buffer to copy into.
+ @param[in] uOffset The byte offset in @c Dest at which to copy to.
+ @param[in] Src The bytes to copy.
+
+ @return Pointer and length of the copy or @ref NULLUsefulBufC.
+
+ This fails and returns @ref NULLUsefulBufC if @c offset is beyond the
+ size of @c Dest.
+
+ This fails and returns @ref NULLUsefulBufC if the @c Src length plus
+ @c uOffset is greater than the length of @c Dest.
+
+ The results are undefined if @c Dest and @c Src overlap.
+
+ This assumes that there is valid data in @c Dest up to @c
+ uOffset. The @ref UsefulBufC returned starts at the beginning of @c
+ Dest and goes to @c Src.len @c + @c uOffset.
+ */
+UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
+
+
+/**
+ @brief Copy one @ref UsefulBuf into another.
+
+ @param[in] Dest The destination buffer to copy into.
+ @param[out] Src The source to copy from.
+
+ @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
+ on failure.
+
+ This fails if @c Src.len is greater than @c Dest.len.
+
+ Note that like @c memcpy(), the pointers are not checked and this
+ will crash rather than return @ref NULLUsefulBufC if they are @c
+ NULL or invalid.
+
+ The results are undefined if @c Dest and @c Src overlap.
+ */
+static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
+
+
+/**
+ @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0.
+
+ @param[in] pDest The destination buffer to copy into.
+ @param[in] value The value to set the bytes to.
+
+ Note that like @c memset(), the pointer in @c pDest is not checked
+ and this will crash if @c NULL or invalid.
+ */
+static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value);
+
+
+/**
+ @brief Copy a pointer into a @ref UsefulBuf.
+
+ @param[in,out] Dest The destination buffer to copy into.
+ @param[in] ptr The source to copy from.
+ @param[in] uLen Length of the source; amount to copy.
+
+ @return 0 on success, 1 on failure.
+
+ This fails and returns @ref NULLUsefulBufC if @c uLen is greater than
+ @c pDest->len.
+
+ Note that like @c memcpy(), the pointers are not checked and this
+ will crash, rather than return 1 if they are @c NULL or invalid.
+ */
+static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest,
+ const void *ptr,
+ size_t uLen);
+
+
+/**
+ @brief Returns a truncation of a @ref UsefulBufC.
+
+ @param[in] UB The buffer to get the head of.
+ @param[in] uAmount The number of bytes in the head.
+
+ @return A @ref UsefulBufC that is the head of UB.
+ */
+static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount);
+
+
+/**
+ @brief Returns bytes from the end of a @ref UsefulBufC.
+
+ @param[in] UB The buffer to get the tail of.
+ @param[in] uAmount The offset from the start where the tail is to begin.
+
+ @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC
+ if @c uAmount is greater than the length of the @ref UsefulBufC.
+
+ If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will
+ be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length
+ of the tail.
+ */
+static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount);
+
+
+/**
+ @brief Compare one @ref UsefulBufC to another.
+
+ @param[in] UB1 The first buffer to compare.
+ @param[in] UB2 The second buffer to compare.
+
+ @return 0, positive or negative value.
+
+ Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is
+ less than @c UB2 if it is shorter or the first byte that is not the
+ same is less.
+
+ Returns 0 if the inputs are the same.
+
+ Returns a positive value if @c UB2 is less than @c UB1.
+
+ All that is of significance is that the result is positive, negative
+ or 0. (This doesn't return the difference between the first
+ non-matching byte like @c memcmp() ).
+ */
+int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
+
+
+/**
+ @brief Find first byte that is not a particular byte value.
+
+ @param[in] UB The destination buffer for byte comparison.
+ @param[in] uValue The byte value to compare to.
+
+ @return Offset of first byte that isn't @c uValue or
+ @c SIZE_MAX if all bytes are @c uValue.
+
+ Note that unlike most comparison functions, 0
+ does not indicate a successful comparison, so the
+ test for match is:
+
+ UsefulBuf_IsValue(...) == SIZE_MAX
+
+ If @c UB is null or empty, there is no match
+ and 0 is returned.
+ */
+size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
+
+
+/**
+ @brief Find one @ref UsefulBufC in another.
+
+ @param[in] BytesToSearch Buffer to search through.
+ @param[in] BytesToFind Buffer with bytes to be found.
+
+ @return Position of found bytes or @c SIZE_MAX if not found.
+ */
+size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
+
+
+#if 1 // NOT_DEPRECATED
+/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
+#define SZLiteralToUsefulBufC(szString) \
+ ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
+#define MakeUsefulBufOnStack(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
+
+/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
+#define ByteArrayLiteralToUsefulBufC(pBytes) \
+ ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+/** Deprecated function; use UsefulBuf_Unconst() instead */
+static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
+{
+ return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+#endif
+
+
+
+
+/**
+ @brief Copy a @c float to a @c uint32_t.
+
+ @param[in] f Float value to copy.
+
+ @return A @c uint32_t with the float bits.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f);
+
+
+/**
+ @brief Copy a @c double to a @c uint64_t.
+
+ @param[in] d Double value to copy.
+
+ @return A @c uint64_t with the double bits.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d);
+
+
+/**
+ @brief Copy a @c uint32_t to a @c float.
+
+ @param[in] u32 Integer value to copy.
+
+ @return The value as a @c float.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32);
+
+
+/**
+ @brief Copy a @c uint64_t to a @c double.
+
+ @param[in] u64 Integer value to copy.
+
+ @return The value as a @c double.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
+
+
+
+
+/**
+ UsefulOutBuf is a structure and functions (an object) for serializing
+ data into a buffer when encoding a network protocol or writing data
+ to file.
+
+ The main idea is that all the pointer manipulation is performed by
+ @ref UsefulOutBuf functions so the caller doesn't have to do any
+ pointer manipulation. The pointer manipulation is centralized. This
+ code will have been reviewed and written carefully so it spares the
+ caller of much of this work and results in safer code with less work.
+
+ The @ref UsefulOutBuf methods that add data to the output buffer
+ always check the length and will never write off the end of the
+ output buffer. If an attempt to add data that will not fit is made,
+ an internal error flag will be set and further attempts to add data
+ will not do anything.
+
+ There is no way to ever write off the end of that buffer when calling
+ the @c UsefulOutBuf_AddXxx() and @c UsefulOutBuf_InsertXxx()
+ functions.
+
+ The functions to add data do not return an error. The working model
+ is that all calls to add data are made without an error check. Errors
+ are just checked for once after all the data has been added before the
+ and before serialized data is to be used. This makes the calling code
+ cleaner.
+
+ There is a utility function to get the error status anytime along the
+ way for a special circumstance. There are functions to see how much
+ room is left and see if some data will fit too, but their use is
+ generally not necessary.
+
+ The general call flow is:
+
+ - Initialize by calling @ref UsefulOutBuf_Init(). The output
+ buffer given to it can be from the heap, stack or
+ otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience macro
+ that makes a buffer on the stack and initializes it.
+
+ - Call methods like UsefulOutBuf_InsertString(),
+ UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf()
+ to output data. The append calls add data to the end of the
+ valid data. The insert calls take a position argument.
+
+ - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see
+ there were no errors and to get the serialized output bytes.
+
+ @ref UsefulOutBuf can be used in a size calculation mode to calculate
+ the size of output that would be generated. This is useful to
+ calculate the size of a buffer that is to be allocated to hold the
+ output. To use @ref UsefulOutBuf in this mode, call
+ UsefulOutBuf_Init() with the @c Storage @ref UsefulBuf as
+ @c (UsefulBuf){NULL,MAX_UINT32}. Then call all the Insert and Add
+ functions. No attempt will made to actually copy data, so only the
+ lengths have to be valid for these calls.
+
+ Methods like UsefulOutBuf_InsertUint64() always output in network
+ bytes order (big endian).
+
+ The possible errors are:
+ - The @ref UsefulOutBuf was not initialized or was corrupted.
+
+ - An attempt was made to add data that will not fit.
+
+ - An attempt was made to insert data at a position beyond the end of
+ the buffer.
+
+ - An attempt was made to insert data at a position beyond the valid
+ data in the buffer.
+
+ Some inexpensive simple sanity checks are performed before every data
+ addition to guard against use of an uninitialized or corrupted
+ UsefulOutBuf.
+
+ This has been used to create a CBOR encoder. The CBOR encoder has
+ almost no pointer manipulation in it, is easier to read, and easier
+ to review.
+
+ A @ref UsefulOutBuf is small and can go on the stack:
+ - 32 bytes (27 bytes plus alignment padding) on a 64-bit machine
+ - 16 bytes (15 bytes plus alignment padding) on a 32-bit machines
+ */
+typedef struct useful_out_buf {
+ // PRIVATE DATA STRUCTURE
+ UsefulBuf UB; // Memory that is being output to
+ size_t data_len; // length of the data
+ uint16_t magic; // Used to detect corruption and lack of initialization
+ uint8_t err;
+} UsefulOutBuf;
+
+
+/**
+ @brief Initialize and supply the actual output buffer.
+
+ @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
+ @param[in] Storage Buffer to output into.
+
+ Initializes the @ref UsefulOutBuf with storage. Sets the current
+ position to the beginning of the buffer clears the error.
+
+ This must be called before the @ref UsefulOutBuf is used.
+ */
+void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage);
+
+
+/**
+ Convenience macro to make a @ref UsefulOutBuf on the stack and
+ initialize it with a stack buffer of the given size. The variable
+ will be named @c name.
+ */
+#define UsefulOutBuf_MakeOnStack(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulOutBuf name;\
+ UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)});
+
+
+/**
+ @brief Reset a @ref UsefulOutBuf for re use
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
+
+ This sets the amount of data in the output buffer to none and clears
+ the error state.
+
+ The output buffer is still the same one and size as from the
+ UsefulOutBuf_Init() call.
+
+ This doesn't zero the data, just resets to 0 bytes of valid data.
+ */
+static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns position of end of data in the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return position of end of data.
+
+ On a freshly initialized @ref UsefulOutBuf with no data added, this
+ will return 0. After 10 bytes have been added, it will return 10 and
+ so on.
+
+ Generally callers will not need this function for most uses of @ref
+ UsefulOutBuf.
+ */
+static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns whether any data has been added to the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return 1 if output position is at start.
+ */
+static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Inserts bytes into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] NewData The bytes to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ @c NewData is the pointer and length for the bytes to be added to the
+ output buffer. There must be room in the output buffer for all of @c
+ NewData or an error will occur.
+
+ The insertion point must be between 0 and the current valid data. If
+ not, an error will occur. Appending data to the output buffer is
+ achieved by inserting at the end of the valid data. This can be
+ retrieved by calling UsefulOutBuf_GetEndPosition().
+
+ When insertion is performed, the bytes between the insertion point
+ and the end of data previously added to the output buffer are slid to
+ the right to make room for the new data.
+
+ Overlapping buffers are OK. @c NewData can point to data in the
+ output buffer.
+
+ If an error occurs an error state is set in the @ref UsefulOutBuf. No
+ error is returned. All subsequent attempts to add data will do
+ nothing.
+
+ The intended use is that all additions are made without checking for
+ an error. The error will be taken into account when
+ UsefulOutBuf_OutUBuf() returns @c NullUsefulBufC.
+ UsefulOutBuf_GetError() can also be called to check for an error.
+ */
+void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf,
+ UsefulBufC NewData,
+ size_t uPos);
+
+
+/**
+ @brief Insert a data buffer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] pBytes Pointer to the bytes to insert
+ @param[in] uLen Length of the bytes to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a pointer and length is passed in rather than an
+ @ref UsefulBufC.
+ */
+static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf,
+ const void *pBytes,
+ size_t uLen,
+ size_t uPos);
+
+
+/**
+ @brief Insert a NULL-terminated string into the UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] szString NULL-terminated string to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+ */
+static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf,
+ const char *szString,
+ size_t uPos);
+
+
+/**
+ @brief Insert a byte into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the UsefulOutBuf.
+ @param[in] byte Bytes to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+ */
+static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf,
+ uint8_t byte,
+ size_t uPos);
+
+
+/**
+ @brief Insert a 16-bit integer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger16 Integer to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a two-byte integer is to be inserted.
+
+ The integer will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf,
+ uint16_t uInteger16,
+ size_t uPos);
+
+
+/**
+ @brief Insert a 32-bit integer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger32 Integer to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a four-byte integer is to be inserted.
+
+ The integer will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf,
+ uint32_t uInteger32,
+ size_t uPos);
+
+
+/**
+ @brief Insert a 64-bit integer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger64 Integer to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being an eight-byte integer is to be inserted.
+
+ The integer will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf,
+ uint64_t uInteger64,
+ size_t uPos);
+
+
+/**
+ @brief Insert a @c float into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] f @c float to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a @c float is to be inserted.
+
+ The @c float will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf,
+ float f,
+ size_t uPos);
+
+
+/**
+ @brief Insert a @c double into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] d @c double to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a @c double is to be inserted.
+
+ The @c double will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
+ double d,
+ size_t uPos);
+
+
+/**
+ @brief Append a @ref UsefulBuf into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] NewData The @ref UsefulBuf with the bytes to append.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+*/
+static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf,
+ UsefulBufC NewData);
+
+
+/**
+ @brief Append bytes to the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] pBytes Pointer to bytes to append.
+ @param[in] uLen Length of @c pBytes to append.
+
+ See UsefulOutBuf_InsertData() for details. This does the same
+ with the insertion point at the end of the valid data.
+ */
+static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf,
+ const void *pBytes,
+ size_t uLen);
+
+
+/**
+ @brief Append a NULL-terminated string to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] szString NULL-terminated string to append.
+ */
+static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf,
+ const char *szString);
+
+
+/**
+ @brief Append a byte to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] byte Bytes to append.
+
+ See UsefulOutBuf_InsertByte() for details. This does the same
+ with the insertion point at the end of the valid data.
+ */
+static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf,
+ uint8_t byte);
+
+
+/**
+ @brief Append an integer to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger16 Integer to append.
+
+ See UsefulOutBuf_InsertUint16() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf,
+ uint16_t uInteger16);
+
+
+/**
+ @brief Append an integer to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger32 Integer to append.
+
+ See UsefulOutBuf_InsertUint32() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf,
+ uint32_t uInteger32);
+
+
+/**
+ @brief Append an integer to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger64 Integer to append.
+
+ See UsefulOutBuf_InsertUint64() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf,
+ uint64_t uInteger64);
+
+
+/**
+ @brief Append a @c float to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] f @c float to append.
+
+ See UsefulOutBuf_InsertFloat() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The float will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf,
+ float f);
+
+
+/**
+ @brief Append a @c double to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] d @c double to append.
+
+ See UsefulOutBuf_InsertDouble() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The double will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
+ double d);
+
+
+/**
+ @brief Returns the current error status.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return 0 if all OK, 1 on error.
+
+ This is the error status since the call to either
+ UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error
+ state it will stay until one of those functions is called.
+
+ Possible error conditions are:
+ - bytes to be inserted will not fit
+ - insertion point is out of buffer or past valid data
+ - current position is off end of buffer (probably corrupted or uninitialized)
+ - detect corruption / uninitialized by bad magic number
+ */
+static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns number of bytes unused used in the output buffer.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return Number of unused bytes or zero.
+
+ Because of the error handling strategy and checks in
+ UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
+ this.
+ */
+static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
+ @param[in] uLen Number of bytes for which to check
+
+ @return 1 if @c uLen bytes will fit, 0 if not.
+
+ Because of the error handling strategy and checks in
+ UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
+ this.
+ */
+static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen);
+
+
+ /**
+ @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
+
+ @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
+
+ Giving a @c NULL output buffer to UsefulOutBuf_Init() is used
+ when just calculating the length of the encoded data.
+ */
+static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns the resulting valid data in a UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return The valid data in @ref UsefulOutBuf or
+ @ref NULLUsefulBufC if there was an error adding data.
+
+ The storage for the returned data is the @c Storage parameter passed
+ to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
+
+ This can be called anytime and many times to get intermediate
+ results. It doesn't change the data or reset the current position
+ so you can keep adding data.
+ */
+UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Copies the valid data into a supplied buffer
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[out] Dest The destination buffer to copy into.
+
+ @return Pointer and length of copied data or @c NULLUsefulBufC
+ if it will not fit in the @c Dest buffer.
+
+ This is the same as UsefulOutBuf_OutUBuf() except it copies the data
+ to @c Dest.
+*/
+UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
+
+
+
+
+/**
+ @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf and is
+ for parsing data read or received. Initialize it with the data from
+ the network. Then use the functions here to get data chunks of
+ various types. A position cursor is maintained internally.
+
+ As long as the functions here are used, there will never be a
+ reference off the end of the given buffer. This is true even if they
+ care called incorrectly, an attempt is made to seek of the end of the
+ buffer, etc. This makes it easier to write safe and correct code.
+ For example, the QCBOR decoder implementation is safer and easier to
+ review through its use of @ref UsefulInputBuf.
+
+ @ref UsefulInputBuf maintains an internal error state. The
+ intended use is that data chunks can be fetched without error
+ checking until the end. Once data has been requested off the end of
+ the buffer, the error state is entered. In the error state the
+ @c UsefulInputBuf_GetXxxx() functions return 0, or @c NULL or
+ @ref NULLUsefulBufC. As long as null are not dereferenced, the
+ error check can be put off until the end, simplifying the calling
+ code.
+
+ The integer and float parsing expects network byte order (big
+ endian). Network byte order is what is used by TCP/IP, CBOR and most
+ internet protocols.
+
+ Lots of inline functions are used to keep code size down. The code
+ optimizer, particularly with the @c -Os or @c -O3, also reduces code
+ size a lot. The only non-inline code is UsefulInputBuf_GetBytes()
+ which is less than 100 bytes so use of @ref UsefulInputBuf doesn't
+ add much code for all the messy hard-to-get right issues with parsing
+ in C that is solves.
+
+ The parse context size is:
+ - 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
+ - 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
+ */
+typedef struct useful_input_buf {
+ // PRIVATE DATA STRUCTURE
+ UsefulBufC UB; // Data being parsed
+ size_t cursor; // Current offset in data being parse
+ uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf
+ uint8_t err; // Set request goes off end or magic number is bad
+} UsefulInputBuf;
+
+#define UIB_MAGIC (0xB00F)
+
+
+/**
+ @brief Initialize the UsefulInputBuf structure before use.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf instance.
+ @param[in] UB The data to parse.
+ */
+static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB);
+
+
+/**
+ @brief Returns current position in input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return Integer position of the cursor.
+
+ The position that the next bytes will be returned from.
+ */
+static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Sets the current position in input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uPos Position to set to.
+
+ If the position is off the end of the input buffer, the error state
+ is entered, and all functions will do nothing.
+
+ Seeking to a valid position in the buffer will not reset the error
+ state. Only re initialization will do that.
+ */
+static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos);
+
+
+/**
+ @brief Returns the number of bytes from the cursor to the end of the buffer,
+ the unconsumed bytes.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return Number of bytes unconsumed or 0 on error.
+
+ This is a critical function for input length validation.
+
+ Returns 0 if the cursor it invalid or corruption of the structure is
+ detected.
+ */
+static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Check if there are any unconsumed bytes.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uLen Number of bytes to check availability for.
+
+ @return 1 if @c uLen bytes are available after the cursor, and 0 if not.
+ */
+static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
+
+
+/**
+ @brief Get pointer to bytes out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uNum Number of bytes to get.
+
+ @return Pointer to bytes.
+
+ This consumes @c uNum bytes from the input buffer. It returns a
+ pointer to the start of the @c uNum bytes.
+
+ If there are not @c uNum bytes in the input buffer, @c NULL will be
+ returned and an error will be set.
+
+ It advances the current position by @c uNum bytes.
+ */
+const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum);
+
+
+/**
+ @brief Get @ref UsefulBuf out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uNum Number of bytes to get.
+
+ @return A @ref UsefulBufC with ptr and length of bytes consumed.
+
+ This consumes @c uNum bytes from the input buffer and returns the
+ pointer and length for them as a @ref UsefulBufC. The length returned
+ will always be @c uNum.
+
+ If there are not @c uNum bytes in the input buffer, @ref NULLUsefulBufC
+ will be returned and the error state is set.
+
+ It advances the current position by @c uNum bytes.
+ */
+static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum);
+
+
+/**
+ @brief Get a byte out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
+
+ @return The byte.
+
+ This consumes 1 byte from the input buffer. It returns the byte.
+
+ If there is not 1 byte in the buffer, 0 will be returned for the byte
+ and an error set internally. You must check the error at some point
+ to know whether the 0 was the real value or just returned in error,
+ but you may not have to do that right away. Check the error state
+ with UsefulInputBuf_GetError(). You can also know you are in the
+ error state if UsefulInputBuf_GetBytes() returns @c NULL or the @c
+ ptr from UsefulInputBuf_GetUsefulBuf() is @c NULL.
+
+ It advances the current position by 1 byte.
+ */
+static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a @c uint16_t out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The @c uint16_t.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a @c uint16_t and two bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a uint32_t out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The @c uint32_t.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a @c uint32_t and four bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a uint64_t out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The uint64_t.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a @c uint64_t and eight bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a float out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The float.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a float and four bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a double out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The double.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a double and eight bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get the error status.
+
+ @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
+
+ @return 0 if there is no error, 1 if there is.
+
+ The error state is entered for one of these reasons:
+ - Attempt to fetch data past the end of the buffer
+ - Attempt to seek to a position past the end of the buffer
+ - Attempt to get data from an uninitialized or corrupt instance
+ of @ref UsefulInputBuf
+
+ Once in the error state, it can only be cleared by calling
+ UsefulInputBuf_Init().
+
+ You may be able to only check the error state at the end after all
+ the UsefulInputBuf_GetXxxx() calls have been made, but if what you
+ get later depends on what you get sooner you cannot. For example,
+ if you get a length or count of following items you will have to
+ check the error.
+ */
+static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf);
+
+
+
+
+/*----------------------------------------------------------
+ Inline implementations.
+ */
+static inline int UsefulBuf_IsNULL(UsefulBuf UB)
+{
+ return !UB.ptr;
+}
+
+
+static inline int UsefulBuf_IsNULLC(UsefulBufC UB)
+{
+ return !UB.ptr;
+}
+
+
+static inline int UsefulBuf_IsEmpty(UsefulBuf UB)
+{
+ return !UB.len;
+}
+
+
+static inline int UsefulBuf_IsEmptyC(UsefulBufC UB)
+{
+ return !UB.len;
+}
+
+
+static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB)
+{
+ return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
+}
+
+
+static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB)
+{
+ return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
+}
+
+
+static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
+{
+ return (UsefulBufC){UB.ptr, UB.len};
+}
+
+
+static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
+{
+ return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+
+
+static inline UsefulBufC UsefulBuf_FromSZ(const char *szString)
+{
+ return ((UsefulBufC) {szString, strlen(szString)});
+}
+
+
+static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src)
+{
+ return UsefulBuf_CopyOffset(Dest, 0, Src);
+}
+
+
+static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
+{
+ memset(pDest.ptr, value, pDest.len);
+ return (UsefulBufC){pDest.ptr, pDest.len};
+}
+
+
+static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
+{
+ return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
+}
+
+
+static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
+{
+ if(uAmount > UB.len) {
+ return NULLUsefulBufC;
+ }
+ return (UsefulBufC){UB.ptr, uAmount};
+}
+
+
+static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
+{
+ UsefulBufC ReturnValue;
+
+ if(uAmount > UB.len) {
+ ReturnValue = NULLUsefulBufC;
+ } else if(UB.ptr == NULL) {
+ ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
+ } else {
+ ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
+ }
+
+ return ReturnValue;
+}
+
+
+
+static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
+{
+ uint32_t u32;
+ memcpy(&u32, &f, sizeof(uint32_t));
+ return u32;
+}
+
+static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
+{
+ uint64_t u64;
+ memcpy(&u64, &d, sizeof(uint64_t));
+ return u64;
+}
+
+static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
+{
+ double d;
+ memcpy(&d, &u64, sizeof(uint64_t));
+ return d;
+}
+
+static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
+{
+ float f;
+ memcpy(&f, &u32, sizeof(uint32_t));
+ return f;
+}
+
+
+
+
+static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe)
+{
+ pMe->data_len = 0;
+ pMe->err = 0;
+}
+
+
+static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe)
+{
+ return pMe->data_len;
+}
+
+
+static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe)
+{
+ return 0 == pMe->data_len;
+}
+
+
+static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe,
+ const void *pBytes,
+ size_t uLen,
+ size_t uPos)
+{
+ UsefulBufC Data = {pBytes, uLen};
+ UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe,
+ const char *szString,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertUsefulBuf(pMe,
+ (UsefulBufC){szString, strlen(szString)},
+ uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me,
+ uint8_t byte,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertData(me, &byte, 1, uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
+ uint16_t uInteger16,
+ size_t uPos)
+{
+ // See UsefulOutBuf_InsertUint64() for comments on this code
+
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ pBytes = &uInteger16;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ uint16_t uTmp = htons(uInteger16);
+ pBytes = &uTmp;
+
+#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ uint16_t uTmp = __builtin_bswap16(uInteger16);
+ pBytes = &uTmp;
+
+#else
+ uint8_t aTmp[2];
+
+ aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
+ aTmp[1] = (uint8_t)(uInteger16 & 0xff);
+
+ pBytes = aTmp;
+#endif
+
+ UsefulOutBuf_InsertData(me, pBytes, 2, uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
+ uint32_t uInteger32,
+ size_t uPos)
+{
+ // See UsefulOutBuf_InsertUint64() for comments on this code
+
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ pBytes = &uInteger32;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ uint32_t uTmp = htonl(uInteger32);
+ pBytes = &uTmp;
+
+#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ uint32_t uTmp = __builtin_bswap32(uInteger32);
+
+ pBytes = &uTmp;
+
+#else
+ uint8_t aTmp[4];
+
+ aTmp[0] = (uint8_t)((uInteger32 & 0xff000000) >> 24);
+ aTmp[1] = (uint8_t)((uInteger32 & 0xff0000) >> 16);
+ aTmp[2] = (uint8_t)((uInteger32 & 0xff00) >> 8);
+ aTmp[3] = (uint8_t)(uInteger32 & 0xff);
+
+ pBytes = aTmp;
+#endif
+
+ UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
+}
+
+static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
+ uint64_t uInteger64,
+ size_t uPos)
+{
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ // We have been told explicitly we are running on a big-endian
+ // machine. Network byte order is big endian, so just copy. There
+ // is no issue with alignment here because uInter64 is always
+ // aligned (and it doesn't matter if pBytes is aligned).
+ pBytes = &uInteger64;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ // Use system function to handle big- and little-endian. This works
+ // on both big- and little-endian machines, but hton() is not
+ // always available or in a standard place so it is not used by
+ // default. With some compilers and CPUs the code for this is very
+ // compact through use of a special swap instruction and on
+ // big-endian machines hton() will reduce to nothing.
+ uint64_t uTmp = htonll(uInteger64);
+
+ pBytes = &uTmp;
+
+#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ // Use built-in function for byte swapping. This usually compiles
+ // to an efficient special byte swap instruction. Unlike hton() it
+ // does not do this conditionally on the CPU endianness, so this
+ // code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN
+ uint64_t uTmp = __builtin_bswap64(uInteger64);
+
+ pBytes = &uTmp;
+
+#else
+ // Default which works on every CPU with no dependency on anything
+ // from the CPU, compiler, libraries or OS. This always works, but
+ // it is usually a little larger and slower than hton().
+ uint8_t aTmp[8];
+
+ aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56);
+ aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48);
+ aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40);
+ aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32);
+ aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24);
+ aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16);
+ aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8);
+ aTmp[7] = (uint8_t)(uInteger64 & 0xff);
+
+ pBytes = aTmp;
+#endif
+
+ // Do the insert
+ UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
+ float f,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe,
+ double d,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
+}
+
+
+static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
+ UsefulBufC NewData)
+{
+ // An append is just a insert at the end
+ UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe,
+ const void *pBytes,
+ size_t uLen)
+{
+ UsefulBufC Data = {pBytes, uLen};
+ UsefulOutBuf_AppendUsefulBuf(pMe, Data);
+}
+
+
+static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe,
+ const char *szString)
+{
+ UsefulOutBuf_AppendUsefulBuf(pMe, (UsefulBufC){szString, strlen(szString)});
+}
+
+
+static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe,
+ uint8_t byte)
+{
+ UsefulOutBuf_AppendData(pMe, &byte, 1);
+}
+
+
+static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe,
+ uint16_t uInteger16)
+{
+ UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe,
+ uint32_t uInteger32)
+{
+ UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe,
+ uint64_t uInteger64)
+{
+ UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
+ float f)
+{
+ UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe,
+ double d)
+{
+ UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
+{
+ return pMe->err;
+}
+
+
+static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe)
+{
+ return pMe->UB.len - pMe->data_len;
+}
+
+
+static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen)
+{
+ return uLen <= UsefulOutBuf_RoomLeft(pMe);
+}
+
+
+static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe)
+{
+ return pMe->UB.ptr == NULL;
+}
+
+
+
+static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
+{
+ pMe->cursor = 0;
+ pMe->err = 0;
+ pMe->magic = UIB_MAGIC;
+ pMe->UB = UB;
+}
+
+static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe)
+{
+ return pMe->cursor;
+}
+
+
+static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos)
+{
+ if(uPos > pMe->UB.len) {
+ pMe->err = 1;
+ } else {
+ pMe->cursor = uPos;
+ }
+}
+
+
+static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe)
+{
+ // Code Reviewers: THIS FUNCTION DOES POINTER MATH
+
+ // Magic number is messed up. Either the structure got overwritten
+ // or was never initialized.
+ if(pMe->magic != UIB_MAGIC) {
+ return 0;
+ }
+
+ // The cursor is off the end of the input buffer given.
+ // Presuming there are no bugs in this code, this should never happen.
+ // If it so, the struct was corrupted. The check is retained as
+ // as a defense in case there is a bug in this code or the struct is
+ // corrupted.
+ if(pMe->cursor > pMe->UB.len) {
+ return 0;
+ }
+
+ // subtraction can't go neative because of check above
+ return pMe->UB.len - pMe->cursor;
+}
+
+
+static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen)
+{
+ return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0;
+}
+
+
+static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
+{
+ const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
+ if(!pResult) {
+ return NULLUsefulBufC;
+ } else {
+ return (UsefulBufC){pResult, uNum};
+ }
+}
+
+
+static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
+{
+ const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
+
+ // The ternery operator is subject to integer promotion, because the
+ // operands are smaller than int, so cast back to uint8_t is needed
+ // to be completely explicit about types (for static analyzers)
+ return (uint8_t)(pResult ? *(uint8_t *)pResult : 0);
+}
+
+static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
+{
+ const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t));
+
+ if(!pResult) {
+ return 0;
+ }
+
+ // See UsefulInputBuf_GetUint64() for comments on this code
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
+ uint16_t uTmp;
+ memcpy(&uTmp, pResult, sizeof(uint16_t));
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ return uTmp;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ return ntohs(uTmp);
+
+#else
+ return __builtin_bswap16(uTmp);
+
+#endif
+
+#else
+
+ // The operations here are subject to integer promotion because the
+ // operands are smaller than int. They will be promoted to unsigned
+ // int for the shift and addition. The cast back to uint16_t is is needed
+ // to be completely explicit about types (for static analyzers)
+ return (uint16_t)((pResult[0] << 8) + pResult[1]);
+
+#endif
+}
+
+
+static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe)
+{
+ const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t));
+
+ if(!pResult) {
+ return 0;
+ }
+
+ // See UsefulInputBuf_GetUint64() for comments on this code
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
+ uint32_t uTmp;
+ memcpy(&uTmp, pResult, sizeof(uint32_t));
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ return uTmp;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ return ntohl(uTmp);
+
+#else
+ return __builtin_bswap32(uTmp);
+
+#endif
+
+#else
+ return ((uint32_t)pResult[0]<<24) +
+ ((uint32_t)pResult[1]<<16) +
+ ((uint32_t)pResult[2]<<8) +
+ (uint32_t)pResult[3];
+#endif
+}
+
+
+static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe)
+{
+ const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t));
+
+ if(!pResult) {
+ return 0;
+ }
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
+ // pResult will probably not be aligned. This memcpy() moves the
+ // bytes into a temp variable safely for CPUs that can or can't do
+ // unaligned memory access. Many compilers will optimize the
+ // memcpy() into a simple move instruction.
+ uint64_t uTmp;
+ memcpy(&uTmp, pResult, sizeof(uint64_t));
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ // We have been told expliclity this is a big-endian CPU. Since
+ // network byte order is big-endian, there is nothing to do.
+
+ return uTmp;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ // We have been told to use ntoh(), the system function to handle
+ // big- and little-endian. This works on both big- and
+ // little-endian machines, but ntoh() is not always available or in
+ // a standard place so it is not used by default. On some CPUs the
+ // code for this is very compact through use of a special swap
+ // instruction.
+
+ return ntohll(uTmp);
+
+#else
+ // Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and
+ // USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON).
+ // __builtin_bswap64() and friends are not conditional on CPU
+ // endianness so this must only be used on little-endian machines.
+
+ return __builtin_bswap64(uTmp);
+
+
+#endif
+
+#else
+ // This is the default code that works on every CPU and every
+ // endianness with no dependency on ntoh(). This works on CPUs
+ // that either allow or do not allow unaligned access. It will
+ // always work, but usually is a little less efficient than ntoh().
+
+ return ((uint64_t)pResult[0]<<56) +
+ ((uint64_t)pResult[1]<<48) +
+ ((uint64_t)pResult[2]<<40) +
+ ((uint64_t)pResult[3]<<32) +
+ ((uint64_t)pResult[4]<<24) +
+ ((uint64_t)pResult[5]<<16) +
+ ((uint64_t)pResult[6]<<8) +
+ (uint64_t)pResult[7];
+#endif
+}
+
+
+static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
+{
+ uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
+
+ return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
+}
+
+
+static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe)
+{
+ uint64_t uResult = UsefulInputBuf_GetUint64(pMe);
+
+ return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
+}
+
+
+static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
+{
+ return pMe->err;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _UsefulBuf_h
+
+
diff --git a/inc/qcbor/qcbor.h b/inc/qcbor/qcbor.h
new file mode 100644
index 0000000..7b8096b
--- /dev/null
+++ b/inc/qcbor/qcbor.h
@@ -0,0 +1,41 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+/**
+ * @file qcbor.h
+ *
+ * Backwards compatibility for includers of qcbor.h (which has been split
+ * into four include files).
+ */
+
+#include "qcbor_encode.h"
+#include "qcbor_decode.h"
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
new file mode 100644
index 0000000..aaea610
--- /dev/null
+++ b/inc/qcbor/qcbor_common.h
@@ -0,0 +1,356 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+
+#ifndef qcbor_common_h
+#define qcbor_common_h
+
+/* Standard CBOR Major type for positive integers of various lengths */
+#define CBOR_MAJOR_TYPE_POSITIVE_INT 0
+
+/* Standard CBOR Major type for negative integer of various lengths */
+#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1
+
+/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */
+#define CBOR_MAJOR_TYPE_BYTE_STRING 2
+
+/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8
+ with no encoding and no NULL termination */
+#define CBOR_MAJOR_TYPE_TEXT_STRING 3
+
+/* Standard CBOR Major type for an ordered array of other CBOR data items */
+#define CBOR_MAJOR_TYPE_ARRAY 4
+
+/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The
+ first item in the pair is the "label" (key, name or identfier) and the second
+ item is the value. */
+#define CBOR_MAJOR_TYPE_MAP 5
+
+/* Standard CBOR optional tagging. This tags things like dates and URLs */
+#define CBOR_MAJOR_TYPE_OPTIONAL 6
+
+/* Standard CBOR extra simple types like floats and the values true and false */
+#define CBOR_MAJOR_TYPE_SIMPLE 7
+
+
+/*
+ These are special values for the AdditionalInfo bits that are part of
+ the first byte. Mostly they encode the length of the data item.
+ */
+#define LEN_IS_ONE_BYTE 24
+#define LEN_IS_TWO_BYTES 25
+#define LEN_IS_FOUR_BYTES 26
+#define LEN_IS_EIGHT_BYTES 27
+#define ADDINFO_RESERVED1 28
+#define ADDINFO_RESERVED2 29
+#define ADDINFO_RESERVED3 30
+#define LEN_IS_INDEFINITE 31
+
+
+/*
+ 24 is a special number for CBOR. Integers and lengths
+ less than it are encoded in the same byte as the major type.
+ */
+#define CBOR_TWENTY_FOUR 24
+
+
+/*
+ Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These
+ are types defined in RFC 7049 and some additional ones
+ in the IANA CBOR tags registry.
+ */
+/** See QCBOREncode_AddDateString(). */
+#define CBOR_TAG_DATE_STRING 0
+/** See QCBOREncode_AddDateEpoch(). */
+#define CBOR_TAG_DATE_EPOCH 1
+/** See QCBOREncode_AddPositiveBignum(). */
+#define CBOR_TAG_POS_BIGNUM 2
+/** See QCBOREncode_AddNegativeBignum(). */
+#define CBOR_TAG_NEG_BIGNUM 3
+/** CBOR tag for a two-element array representing a fraction with a
+ mantissa and base-10 scaling factor. See QCBOREncode_AddDecimalFraction()
+ and @ref expAndMantissa.
+ */
+#define CBOR_TAG_DECIMAL_FRACTION 4
+/** CBOR tag for a two-element array representing a fraction with a
+ mantissa and base-2 scaling factor. See QCBOREncode_AddBigFloat()
+ and @ref expAndMantissa. */
+#define CBOR_TAG_BIGFLOAT 5
+/** Tag for COSE format encryption with no recipient
+ identification. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_COSE_ENCRYPTO 16
+/** Tag for COSE format MAC'd data with no recipient
+ identification. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag.*/
+#define CBOR_TAG_COSE_MAC0 17
+/** Tag for COSE format single signature signing. No API is provided
+ for this tag. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). */
+#define CBOR_TAG_COSE_SIGN1 18
+/** 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_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_AddBytes(). */
+#define CBOR_TAG_ENC_AS_B64 22
+/** A hint that the following byte string should be encoded in base-16
+ format per [RFC 4648] (https://tools.ietf.org/html/rfc4648) 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) before
+ the call to QCBOREncode_AddBytes(). */
+#define CBOR_TAG_ENC_AS_B16 23
+/** Tag to indicate a byte string contains encoded CBOR. No API is
+ provided for this tag. */
+#define CBOR_TAG_CBOR 24
+/** See QCBOREncode_AddURI(). */
+#define CBOR_TAG_URI 32
+/** See QCBOREncode_AddB64URLText(). */
+#define CBOR_TAG_B64URL 33
+/** See QCBOREncode_AddB64Text(). */
+#define CBOR_TAG_B64 34
+/** See QCBOREncode_AddRegex(). */
+#define CBOR_TAG_REGEX 35
+/** See QCBOREncode_AddMIMEData(). */
+#define CBOR_TAG_MIME 36
+/** See QCBOREncode_AddBinaryUUID(). */
+#define CBOR_TAG_BIN_UUID 37
+/** The data is a CBOR Web Token per [RFC 8392]
+ (https://tools.ietf.org/html/rfc8932). No API is provided for this
+ tag. */
+#define CBOR_TAG_CWT 61
+/** Tag for COSE format encryption. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_ENCRYPT 96
+/** Tag for COSE format MAC. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_MAC 97
+/** Tag for COSE format signed data. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_SIGN 98
+/** World geographic coordinates. See ISO 6709, [RFC 5870]
+ (https://tools.ietf.org/html/rfc5870) and WGS-84. No API is
+ provided for this tag. */
+#define CBOR_TAG_GEO_COORD 103
+/** The magic number, self-described CBOR. No API is provided for this
+ tag. */
+#define CBOR_TAG_CBOR_MAGIC 55799
+
+#define CBOR_TAG_NONE UINT64_MAX
+
+
+/*
+ Values for the 5 bits for items of major type 7
+ */
+#define CBOR_SIMPLEV_FALSE 20
+#define CBOR_SIMPLEV_TRUE 21
+#define CBOR_SIMPLEV_NULL 22
+#define CBOR_SIMPLEV_UNDEF 23
+#define CBOR_SIMPLEV_ONEBYTE 24
+#define HALF_PREC_FLOAT 25
+#define SINGLE_PREC_FLOAT 26
+#define DOUBLE_PREC_FLOAT 27
+#define CBOR_SIMPLE_BREAK 31
+#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE
+#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK
+
+
+
+
+/**
+ Error codes returned by QCBOR Encoder and Decoder.
+ */
+typedef enum {
+ /** The encode or decode completely correctly. */
+ QCBOR_SUCCESS = 0,
+
+ /** The buffer provided for the encoded output when doing encoding
+ was too small and the encoded output will not fit. Also, when
+ the buffer given to QCBORDecode_SetMemPool() is too small. */
+ QCBOR_ERR_BUFFER_TOO_SMALL = 1,
+
+ /** During encoding or decoding, the array or map nesting was
+ deeper than this implementation can handle. Note that in the
+ interest of code size and memory use, this implementation has a
+ hard limit on array nesting. The limit is defined as the
+ constant @ref QCBOR_MAX_ARRAY_NESTING. */
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 2,
+
+ /** During decoding or encoding, the array or map had too many
+ items in it. This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY,
+ typically 65,535. */
+ QCBOR_ERR_ARRAY_TOO_LONG = 3,
+
+ /** During encoding, more arrays or maps were closed than
+ opened. This is a coding error on the part of the caller of the
+ encoder. */
+ QCBOR_ERR_TOO_MANY_CLOSES = 4,
+
+ /** During decoding, some CBOR construct was encountered that this
+ decoder doesn't support, primarily this is the reserved
+ additional info values, 28 through 30. During encoding,
+ an attempt to create simple value between 24 and 31. */
+ QCBOR_ERR_UNSUPPORTED = 5,
+
+ /** During decoding, hit the end of the given data to decode. For
+ example, a byte string of 100 bytes was expected, but the end
+ of the input was hit before finding those 100 bytes. Corrupted
+ CBOR input will often result in this error. See also @ref
+ QCBOR_ERR_NO_MORE_ITEMS.
+ */
+ QCBOR_ERR_HIT_END = 6,
+
+ /** During encoding, the length of the encoded CBOR exceeded @c
+ UINT32_MAX. */
+ QCBOR_ERR_BUFFER_TOO_LARGE = 7,
+
+ /** During decoding, an integer smaller than INT64_MIN was received
+ (CBOR can represent integers smaller than INT64_MIN, but C
+ cannot). */
+ QCBOR_ERR_INT_OVERFLOW = 8,
+
+ /** During decoding, the label for a map entry is bad. What causes
+ this error depends on the decoding mode. */
+ QCBOR_ERR_MAP_LABEL_TYPE = 9,
+
+ /** During encoding or decoding, the number of array or map opens
+ was not matched by the number of closes. */
+ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 10,
+
+ /** During decoding, a date greater than +- 292 billion years from
+ Jan 1 1970 encountered during parsing. */
+ QCBOR_ERR_DATE_OVERFLOW = 11,
+
+ /** During decoding, the CBOR is not valid, primarily a simple type
+ is encoded in a prohibited way. */
+ QCBOR_ERR_BAD_TYPE_7 = 12,
+
+ /** Optional tagging that doesn't make sense (an integer is tagged
+ as a date string) or can't be handled. */
+ QCBOR_ERR_BAD_OPT_TAG = 13,
+
+ /** Returned by QCBORDecode_Finish() if all the inputs bytes have
+ not been consumed. */
+ QCBOR_ERR_EXTRA_BYTES = 14,
+
+ /** During encoding, @c QCBOREncode_CloseXxx() called with a
+ different type than is currently open. */
+ QCBOR_ERR_CLOSE_MISMATCH = 15,
+
+ /** Unable to decode an indefinite-length string because no string
+ allocator was configured. See QCBORDecode_SetMemPool() or
+ QCBORDecode_SetUpAllocator(). */
+ QCBOR_ERR_NO_STRING_ALLOCATOR = 16,
+
+ /** One of the chunks in an indefinite-length string is not of the
+ type of the start of the string. */
+ QCBOR_ERR_INDEFINITE_STRING_CHUNK = 17,
+
+ /** Error allocating space for a string, usually for an
+ indefinite-length string. */
+ QCBOR_ERR_STRING_ALLOCATE = 18,
+
+ /** During decoding, a break occurred outside an indefinite-length
+ item. */
+ QCBOR_ERR_BAD_BREAK = 19,
+
+ /** During decoding, too many tags in the caller-configured tag
+ list, or not enough space in @ref QCBORTagListOut. */
+ QCBOR_ERR_TOO_MANY_TAGS = 20,
+
+ /** An integer type is encoded with a bad length (an indefinite length) */
+ QCBOR_ERR_BAD_INT = 21,
+
+ /** All well-formed data items have been consumed and there are no
+ more. If parsing a CBOR stream this indicates the non-error
+ end of the stream. If parsing a CBOR stream / sequence, this
+ probably indicates that some data items expected are not present.
+ See also @ref QCBOR_ERR_HIT_END. */
+ QCBOR_ERR_NO_MORE_ITEMS = 22,
+
+ /** Something is wrong with a decimal fraction or bigfloat such as
+ it not consisting of an array with two integers */
+ QCBOR_ERR_BAD_EXP_AND_MANTISSA = 23,
+
+ /** When decoding, a string's size is greater than size_t. In all but some
+ very strange situations this is because of corrupt input CBOR and
+ should be treated as such. The strange situation is a CPU with a very
+ small size_t (e.g., a 16-bit CPU) and a large string (e.g., > 65KB).
+ */
+ QCBOR_ERR_STRING_TOO_LONG = 24
+
+ /* This is stored in uint8_t in places; never add values > 255 */
+} QCBORError;
+
+
+/* Function for getting an error string from an error code */
+const char *qcbor_err_to_str(QCBORError err);
+
+
+
+/**
+ The maximum nesting of arrays and maps when encoding or decoding. The
+ error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on
+ encoding of decoding if it is exceeded.
+ */
+#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1
+
+
+/**
+ The maximum number of items in a single array or map when encoding of
+ decoding.
+ */
+// -1 is because the value UINT16_MAX is used to track indefinite-length arrays
+#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1)
+
+
+/**
+ The maximum number of tags that can be in @ref QCBORTagListIn and passed to
+ QCBORDecode_SetCallerConfiguredTagList()
+ */
+#define QCBOR_MAX_CUSTOM_TAGS 16
+
+
+#endif /* qcbor_common_h */
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
new file mode 100644
index 0000000..be03b01
--- /dev/null
+++ b/inc/qcbor/qcbor_decode.h
@@ -0,0 +1,973 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+
+#ifndef qcbor_decode_h
+#define qcbor_decode_h
+
+
+#include "qcbor/qcbor_common.h"
+#include "qcbor/qcbor_private.h"
+#include <stdbool.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} // Keep editor indention formatting happy
+#endif
+#endif
+
+
+/**
+ @file qcbor_decode.h
+
+ This describes CBOR decoding.
+*/
+
+/**
+ The decode mode options.
+ */
+typedef enum {
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_NORMAL = 0,
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
+ /* This is stored in uint8_t in places; never add values > 255 */
+} QCBORDecodeMode;
+
+
+
+
+
+/* Do not renumber these. Code depends on some of these values. */
+/** The data type is unknown, unset or invalid. */
+#define QCBOR_TYPE_NONE 0
+/** Type for an integer that decoded either between @c INT64_MIN and
+ @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member
+ @c val.int64. */
+#define QCBOR_TYPE_INT64 2
+/** Type for an integer that decoded to a more than @c INT64_MAX and
+ @c UINT64_MAX. Data is in member @c val.uint64. */
+#define QCBOR_TYPE_UINT64 3
+/** Type for an array. The number of items in the array is in @c
+ val.uCount. */
+#define QCBOR_TYPE_ARRAY 4
+/** Type for a map; number of items in map is in @c val.uCount. */
+#define QCBOR_TYPE_MAP 5
+/** Type for a buffer full of bytes. Data is in @c val.string. */
+#define QCBOR_TYPE_BYTE_STRING 6
+/** Type for a UTF-8 string. It is not NULL-terminated. Data is in @c
+ val.string. */
+#define QCBOR_TYPE_TEXT_STRING 7
+/** Type for a positive big number. Data is in @c val.bignum, a
+ pointer and a length. */
+#define QCBOR_TYPE_POSBIGNUM 9
+/** Type for a negative big number. Data is in @c val.bignum, a
+ pointer and a length. */
+#define QCBOR_TYPE_NEGBIGNUM 10
+/** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date
+ string, possibly with time zone. Data is in @c val.dateString */
+#define QCBOR_TYPE_DATE_STRING 11
+/** Type for integer seconds since Jan 1970 + floating-point
+ fraction. Data is in @c val.epochDate */
+#define QCBOR_TYPE_DATE_EPOCH 12
+/** A simple type that this CBOR implementation doesn't know about;
+ Type is in @c val.uSimple. */
+#define QCBOR_TYPE_UKNOWN_SIMPLE 13
+
+/** A decimal fraction made of decimal exponent and integer mantissa.
+ See @ref expAndMantissa and QCBOREncode_AddDecimalFraction(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION 14
+
+/** A decimal fraction made of decimal exponent and positive big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddDecimalFractionBigNum(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15
+
+/** A decimal fraction made of decimal exponent and negative big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddDecimalFractionBigNum(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16
+
+/** A floating-point number made of base-2 exponent and integer
+ mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddBigFloat(). */
+#define QCBOR_TYPE_BIGFLOAT 17
+
+/** A floating-point number made of base-2 exponent and positive big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddBigFloatBigNum(). */
+#define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18
+
+/** A floating-point number made of base-2 exponent and negative big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddBigFloatBigNum(). */
+#define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19
+
+/** Type for the value false. */
+#define QCBOR_TYPE_FALSE 20
+/** Type for the value true. */
+#define QCBOR_TYPE_TRUE 21
+/** Type for the value null. */
+#define QCBOR_TYPE_NULL 22
+/** Type for the value undef. */
+#define QCBOR_TYPE_UNDEF 23
+/** Type for a floating-point number. Data is in @c val.float. */
+#define QCBOR_TYPE_FLOAT 26
+/** Type for a double floating-point number. Data is in @c val.double. */
+#define QCBOR_TYPE_DOUBLE 27
+/** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is
+ being traversed as an array. See QCBORDecode_Init() */
+#define QCBOR_TYPE_MAP_AS_ARRAY 32
+
+#define QCBOR_TYPE_BREAK 31 // Used internally; never returned
+
+#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned
+
+
+
+/*
+ Approx Size of this:
+ 8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding) = 24 for first part
+ (20 on a 32-bit machine)
+ 16 bytes for the val union
+ 16 bytes for label union
+ total = 56 bytes (52 bytes on 32-bit machine)
+ */
+
+/**
+ The main data structure that holds the type, value and other info for
+ a decoded item returned by QCBORDecode_GetNext() and
+ QCBORDecode_GetNextWithTags().
+ */
+typedef struct _QCBORItem {
+ /** Tells what element of the @c val union to use. One of @c
+ QCBOR_TYPE_XXXX */
+ uint8_t uDataType;
+ /** How deep the nesting from arrays and maps are. 0 is the top
+ level with no arrays or maps entered. */
+ uint8_t uNestingLevel;
+ /** Tells what element of the label union to use. */
+ uint8_t uLabelType;
+ /** 1 if allocated with string allocator, 0 if not. See
+ QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() */
+ uint8_t uDataAlloc;
+ /** Like @c uDataAlloc, but for label. */
+ uint8_t uLabelAlloc;
+ /** If not equal to @c uNestingLevel, this item closed out at least
+ one map/array */
+ uint8_t uNextNestLevel;
+
+ /** The union holding the item's value. Select union member based
+ on @c uDataType */
+ union {
+ /** The value for @c uDataType @ref QCBOR_TYPE_INT64. */
+ int64_t int64;
+ /** The value for uDataType @ref QCBOR_TYPE_UINT64. */
+ uint64_t uint64;
+ /** The value for @c uDataType @ref QCBOR_TYPE_BYTE_STRING and
+ @ref QCBOR_TYPE_TEXT_STRING. */
+ UsefulBufC string;
+ /** The "value" for @c uDataType @ref QCBOR_TYPE_ARRAY or @ref
+ QCBOR_TYPE_MAP -- the number of items in the array or map.
+ It is @c UINT16_MAX when decoding indefinite-lengths maps
+ and arrays. */
+ uint16_t uCount;
+ /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
+ double dfnum;
+ /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
+ struct {
+ int64_t nSeconds;
+ double fSecondsFraction;
+ } epochDate;
+ /** The value for @c uDataType @ref QCBOR_TYPE_DATE_STRING. */
+ UsefulBufC dateString;
+ /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and
+ @ref QCBOR_TYPE_NEGBIGNUM. */
+ UsefulBufC bigNum;
+ /** The integer value for unknown simple types. */
+ uint8_t uSimple;
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+ /** @anchor expAndMantissa
+
+ The value for bigfloats and decimal fractions. The use of the
+ fields in this structure depend on @c uDataType.
+
+ When @c uDataType is a @c DECIMAL_FRACTION, the exponent is
+ base-10. When it is a @c BIG_FLOAT it is base-2.
+
+ When @c uDataType is a @c POS_BIGNUM or a @c NEG_BIGNUM then the
+ @c bigNum part of @c Mantissa is valid. Otherwise the
+ @c nInt part of @c Mantissa is valid.
+
+ See @ref QCBOR_TYPE_DECIMAL_FRACTION,
+ @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
+ @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
+ @ref QCBOR_TYPE_BIGFLOAT, @ref QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
+ and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
+
+ Also see QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
+ QCBOREncode_AddDecimalFractionBigNum() and
+ QCBOREncode_AddBigFloatBigNum().
+ */
+ struct {
+ int64_t nExponent;
+ union {
+ int64_t nInt;
+ UsefulBufC bigNum;
+ } Mantissa;
+ } expAndMantissa;
+#endif
+ uint64_t uTagV; // Used internally during decoding
+ } val;
+
+ /** Union holding the different label types selected based on @c
+ uLabelType */
+ union {
+ /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and
+ @ref QCBOR_TYPE_TEXT_STRING */
+ UsefulBufC string;
+ /** The label for @c uLabelType for @ref QCBOR_TYPE_INT64 */
+ int64_t int64;
+ /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */
+ uint64_t uint64;
+ } label;
+
+ /** Bit indicating which tags (major type 6) on this item. See
+ QCBORDecode_IsTagged(). */
+ uint64_t uTagBits;
+
+} QCBORItem;
+
+
+
+/**
+ @brief The type defining what a string allocator function must do.
+
+ @param[in] pAllocateCxt Pointer to context for the particular
+ allocator implementation What is in the
+ context is dependent on how a particular
+ string allocator works. Typically, it
+ will contain a pointer to the memory pool
+ and some booking keeping data.
+ @param[in] pOldMem Points to some memory allocated by the
+ allocator that is either to be freed or
+ to be reallocated to be larger. It is
+ @c NULL for new allocations and when called as
+ a destructor to clean up the whole
+ allocation.
+ @param[in] uNewSize Size of memory to be allocated or new
+ size of chunk to be reallocated. Zero for
+ a new allocation or when called as a
+ destructor.
+
+ @return Either the allocated buffer is returned, or @ref
+ NULLUsefulBufC. @ref NULLUsefulBufC is returned on a failed
+ allocation and in the two cases where there is nothing to
+ return.
+
+ This is called in one of four modes:
+
+ Allocate -- @c uNewSize is the amount to allocate. @c pOldMem is @c
+ NULL.
+
+ Free -- @c uNewSize is 0. @c pOldMem points to the memory to be
+ freed. When the decoder calls this, it will always be the most
+ recent block that was either allocated or reallocated.
+
+ Reallocate -- @c pOldMem is the block to reallocate. @c uNewSize is
+ its new size. When the decoder calls this, it will always be the
+ most recent block that was either allocated or reallocated.
+
+ Destruct -- @c pOldMem is @c NULL and @c uNewSize is 0. This is called
+ when the decoding is complete by QCBORDecode_Finish(). Usually the
+ strings allocated by a string allocator are in use after the decoding
+ is completed so this usually will not free those strings. Many string
+ allocators will not need to do anything in this mode.
+
+ The strings allocated by this will have @c uDataAlloc set to true in
+ the @ref QCBORItem when they are returned. The user of the strings
+ will have to free them. How they free them, depends on the string
+ allocator.
+
+ If QCBORDecode_SetMemPool() is called, the internal MemPool will be
+ used. It has its own internal implementation of this function, so
+ one does not need to be implemented.
+ */
+typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
+
+
+/**
+ This only matters if you use the built-in string allocator by setting
+ it up with QCBORDecode_SetMemPool(). This is the size of the overhead
+ needed by QCBORDecode_SetMemPool(). The amount of memory available
+ for decoded strings will be the size of the buffer given to
+ QCBORDecode_SetMemPool() less this amount.
+
+ If you write your own string allocator or use the separately
+ available malloc based string allocator, this size will not apply.
+ */
+#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 8
+
+
+/**
+ This is used by QCBORDecode_SetCallerConfiguredTagList() to set a
+ list of tags beyond the built-in ones.
+
+ See also QCBORDecode_GetNext() for general description of tag
+ decoding.
+ */
+typedef struct {
+ /** The number of tags in the @c puTags. The maximum size is @ref
+ QCBOR_MAX_CUSTOM_TAGS. */
+ uint8_t uNumTags;
+ /** An array of tags to add to recognize in addition to the
+ built-in ones. */
+ const uint64_t *puTags;
+} QCBORTagListIn;
+
+
+/**
+ This is for QCBORDecode_GetNextWithTags() to be able to return the
+ full list of tags on an item. It is not needed for most CBOR protocol
+ implementations. Its primary use is for pretty-printing CBOR or
+ protocol conversion to another format.
+
+ 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.
+
+ 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;
+
+
+/**
+ QCBORDecodeContext is the data type that holds context decoding the
+ data items for some received CBOR. It is about 100 bytes, so it can
+ go on the stack. The contents are opaque, and the caller should not
+ access any internal items. A context may be re used serially as long
+ as it is re initialized.
+ */
+typedef struct _QCBORDecodeContext QCBORDecodeContext;
+
+
+/**
+ Initialize the CBOR decoder context.
+
+ @param[in] pCtx The context to initialize.
+ @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded.
+ @param[in] nMode See below and @ref QCBORDecodeMode.
+
+ Initialize context for a pre-order traversal of the encoded CBOR
+ tree.
+
+ Most CBOR decoding can be completed by calling this function to start
+ and QCBORDecode_GetNext() in a loop.
+
+ If indefinite-length strings are to be decoded, then
+ QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
+ called to set up a string allocator.
+
+ If tags other than built-in tags are to be recognized and recorded in
+ @c uTagBits, then QCBORDecode_SetCallerConfiguredTagList() must be
+ called. The built-in tags are those for which a macro of the form @c
+ CBOR_TAG_XXX is defined.
+
+ Three decoding modes are supported. In normal mode, @ref
+ QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers
+ are accepted as map labels. If a label is other than these, the error
+ @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
+
+ 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
+ returned by QCBORDecode_GetNext() if anything but a text string label
+ is encountered.
+
+ In @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special
+ arrays. They will be return with special @c uDataType @ref
+ QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the number of items, will be
+ double what it would be for a normal map because the labels are also
+ counted. This mode is useful for decoding CBOR that has labels that
+ are not integers or text strings, but the caller must manage much of
+ the map decoding.
+ */
+void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
+
+
+/**
+ @brief Set up the MemPool string allocator for indefinite-length strings.
+
+ @param[in] pCtx The decode context.
+ @param[in] MemPool The pointer and length of the memory pool.
+ @param[in] bAllStrings If true, all strings, even of definite
+ length, will be allocated with the string
+ allocator.
+
+ @return Error if the MemPool was less than @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE.
+
+ indefinite-length strings (text and byte) cannot be decoded unless
+ there is a string allocator configured. MemPool is a simple built-in
+ string allocator that allocates bytes from a memory pool handed to it
+ by calling this function. The memory pool is just a pointer and
+ length for some block of memory that is to be used for string
+ allocation. It can come from the stack, heap or other.
+
+ The memory pool must be @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE plus
+ space for all the strings allocated. There is no overhead per string
+ allocated. A conservative way to size this buffer is to make it the
+ same size as the CBOR being decoded plus @ref
+ QCBOR_DECODE_MIN_MEM_POOL_SIZE.
+
+ This memory pool is used for all indefinite-length strings that are
+ text strings or byte strings, including strings used as labels.
+
+ The pointers to strings in @ref QCBORItem will point into the memory
+ pool set here. They do not need to be individually freed. Just
+ discard the buffer when they are no longer needed.
+
+ If @c bAllStrings is set, then the size will be the overhead plus the
+ space to hold **all** strings, definite and indefinite-length, value
+ or label. The advantage of this is that after the decode is complete,
+ the original memory holding the encoded CBOR does not need to remain
+ valid.
+
+ If this function is never called because there is no need to support
+ indefinite-length strings, the internal MemPool implementation should
+ be dead-stripped by the loader and not add to code size.
+ */
+QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings);
+
+
+/**
+ @brief Sets up a custom string allocator for indefinite-length strings
+
+ @param[in] pCtx The decoder context to set up an
+ allocator for.
+ @param[in] pfAllocateFunction Pointer to function that will be
+ called by QCBOR for allocations and
+ frees.
+ @param[in] pAllocateContext Context passed to @c
+ pfAllocateFunction.
+ @param[in] bAllStrings If true, all strings, even of definite
+ length, will be allocated with the
+ string allocator.
+
+ indefinite-length strings (text and byte) cannot be decoded unless
+ there a string allocator is configured. QCBORDecode_SetUpAllocator()
+ allows the caller to configure an external string allocator
+ implementation if the internal string allocator is not suitable. See
+ QCBORDecode_SetMemPool() to configure the internal allocator. Note
+ that the internal allocator is not automatically set up.
+
+ The string allocator configured here can be a custom one designed and
+ implemented by the caller. See @ref QCBORStringAllocate for the
+ requirements for a string allocator implementation.
+
+ A malloc-based string external allocator can be obtained by calling
+ @c QCBORDecode_MakeMallocStringAllocator(). It will return a function
+ and pointer that can be given here as @c pAllocatorFunction and @c
+ pAllocatorContext. It uses standard @c malloc() so @c free() must be
+ called on all strings marked by @c uDataAlloc @c == @c 1 or @c
+ uLabelAlloc @c == @c 1 in @ref QCBORItem.
+
+ Note that an older version of this function took an allocator
+ structure, rather than single function and pointer. The older
+ version @c QCBORDecode_MakeMallocStringAllocator() also implemented
+ the older interface.
+ */
+void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx,
+ QCBORStringAllocate pfAllocateFunction,
+ void *pAllocateContext,
+ bool bAllStrings);
+
+/**
+ @brief Configure list of caller-selected tags to be recognized.
+
+ @param[in] pCtx The decode context.
+ @param[out] pTagList Structure holding the list of tags to configure.
+
+ This is used to tell the decoder about tags beyond those that are
+ built-in that should be recognized. The built-in tags are those with
+ macros of the form @c CBOR_TAG_XXX.
+
+ The list pointed to by @c pTagList must persist during decoding. No
+ copy of it is made.
+
+ The maximum number of tags that can be added is @ref
+ QCBOR_MAX_CUSTOM_TAGS. If a list larger than this is given, the
+ error will be returned when QCBORDecode_GetNext() is called, not
+ here.
+
+ See description of @ref QCBORTagListIn.
+ */
+void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList);
+
+
+/**
+ @brief Gets the next item (integer, byte string, array...) in
+ preorder traversal of CBOR tree.
+
+ @param[in] pCtx The decoder context.
+ @param[out] pDecodedItem Holds the CBOR item just decoded.
+
+ @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Not well-formed, one of the
+ chunks in indefinite-length
+ string is wrong type.
+
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Not well-formed, array or map
+ not closed.
+
+ @retval QCBOR_ERR_UNSUPPORTED Not well-formed, input contains
+ unsupported CBOR.
+
+ @retval QCBOR_ERR_HIT_END Not well-formed, unexpectedly ran out
+ of bytes.
+
+ @retval QCBOR_ERR_BAD_TYPE_7 Not well-formed, bad simple type value.
+
+ @retval QCBOR_ERR_BAD_BREAK Not well-formed, break occurs where
+ not allowed.
+
+ @retval QCBOR_ERR_EXTRA_BYTES Not well-formed, unprocessed bytes at
+ the end.
+
+ @retval QCBOR_ERR_BAD_INT Not well-formed, length of integer is
+ bad.
+
+ @retval QCBOR_ERR_BAD_OPT_TAG Invalid CBOR, tag on wrong type.
+
+ @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit, array or map
+ too long.
+
+ @retval QCBOR_ERR_INT_OVERFLOW Implementation limit, negative
+ integer too large.
+
+ @retval QCBOR_ERR_DATE_OVERFLOW Implementation limit, date larger
+ than can be handled.
+
+ @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit, nesting
+ too deep.
+
+ @retval QCBOR_ERR_STRING_ALLOCATE Resource exhaustion, string allocator
+ failed.
+
+ @retval QCBOR_ERR_MAP_LABEL_TYPE Configuration error / Implementation
+ limit encountered a map label this is
+ not a string on an integer.
+
+ @retval QCBOR_ERR_NO_STRING_ALLOCATOR Configuration error, encountered
+ indefinite-length string with no
+ allocator configured.
+ @retval QCBOR_ERR_NO_MORE_ITEMS No more bytes to decode. The previous
+ item was successfully decoded. This
+ is usually how the non-error end of
+ a CBOR stream / sequence is detected.
+
+ @c pDecodedItem is filled in with the value parsed. Generally, the
+ following data is returned in the structure:
+
+ - @c uDataType which indicates which member of the @c val union the
+ data is in. This decoder figures out the type based on the CBOR
+ major type, the CBOR "additionalInfo", the CBOR optional tags and
+ the value of the integer.
+
+ - The value of the item, which might be an integer, a pointer and a
+ length, the count of items in an array, a floating-point number or
+ other.
+
+ - The nesting level for maps and arrays.
+
+ - The label for an item in a map, which may be a text or byte string
+ or an integer.
+
+ - The CBOR optional tag or tags.
+
+ See documentation on in the data type @ref _QCBORItem for all the
+ details on what is returned.
+
+ This function handles arrays and maps. When first encountered a @ref
+ QCBORItem will be returned with major type @ref QCBOR_TYPE_ARRAY or
+ @ref QCBOR_TYPE_MAP. @c QCBORItem.val.uCount will indicate the number
+ of Items in the array or map. Typically, an implementation will call
+ QCBORDecode_GetNext() in a for loop to fetch them all. When decoding
+ indefinite-length maps and arrays, @c QCBORItem.val.uCount is @c
+ UINT16_MAX and @c uNextNestLevel must be used to know when the end of
+ a map or array is reached.
+
+ Nesting level 0 is the outside top-most nesting level. For example,
+ in a CBOR structure with two items, an integer and a byte string
+ only, both would be at nesting level 0. A CBOR structure with an
+ array open, an integer and a byte string, would have the integer and
+ byte string as nesting level 1.
+
+ Here is an example of how the nesting level is reported with no arrays
+ or maps at all.
+
+ @verbatim
+ CBOR Structure Nesting Level
+ Integer 0
+ Byte String 0
+ @endverbatim
+
+ Here is an example of how the nesting level is reported with a simple
+ array and some top-level items.
+
+ @verbatim
+ Integer 0
+ Array (with 2 items) 0
+ Byte String 1
+ Byte string 1
+ Integer 0
+ @endverbatim
+
+
+ Here's a more complex example
+ @verbatim
+
+ Map with 2 items 0
+ Text string 1
+ Array with 3 integers 1
+ integer 2
+ integer 2
+ integer 2
+ text string 1
+ byte string 1
+ @endverbatim
+
+ In @ref _QCBORItem, @c uNextNestLevel is the nesting level for the
+ next call to QCBORDecode_GetNext(). It indicates if any maps or
+ arrays were closed out during the processing of the just-fetched @ref
+ QCBORItem. This processing includes a look-ahead for any breaks that
+ close out indefinite-length arrays or maps. This value is needed to
+ be able to understand the hierarchical structure. If @c
+ uNextNestLevel is not equal to @c uNestLevel the end of the current
+ map or array has been encountered. This works the same for both
+ definite and indefinite-length arrays.
+
+ This decoder support CBOR type 6 tagging. The decoding of particular
+ given tag value may be supported in one of three different ways.
+
+ First, some common tags are fully and transparently supported by
+ automatically decoding them and returning them in a @ref QCBORItem.
+ These tags have a @c QCBOR_TYPE_XXX associated with them and manifest
+ pretty much the same as a standard CBOR type. @ref
+ QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref QCBORItem
+ is an example.
+
+ Second are tags that are automatically recognized, but not decoded.
+ These are tags that have a @c \#define of the form @c CBOR_TAG_XXX.
+ These are recorded in the @c uTagBits member of @ref QCBORItem. There
+ is an internal table that maps each bit to a particular tag value
+ allowing up to 64 tags on an individual item to be reported (it is
+ rare to have more than one or two). To find out if a particular tag
+ value is set call QCBORDecode_IsTagged() on the @ref QCBORItem. See
+ also QCBORDecode_GetNextWithTags().
+
+ Third are tags that are not automatically recognized, because they
+ are proprietary, custom or more recently registered with [IANA]
+ (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). The
+ internal mapping table has to be configured to recognize these. Call
+ QCBORDecode_SetCallerConfiguredTagList() to do that. Then
+ QCBORDecode_IsTagged() will work with them.
+
+ The actual decoding of tags supported in the second and third way
+ must be handled by the caller. Often this is simply verifying that
+ the expected tag is present on a map, byte string or such. In other
+ cases, there might a complicated map structure to decode.
+
+ 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.
+
+ If any error occurs, \c uDataType and \c uLabelType will be set
+ to \ref QCBOR_TYPE_NONE. If there is no need to know the specific
+ error, \ref QCBOR_TYPE_NONE can be checked for and the return value
+ ignored.
+
+ Errors fall in several categories as noted in list above:
+
+ - Not well-formed errors are those where there is something
+ syntactically and fundamentally wrong with the CBOR being
+ decoded. Encoding should stop completely.
+
+ - Invalid CBOR is well-formed, but still not correct. It is probably
+ best to stop decoding, but not necessary.
+
+ - This implementation has some size limits. They should rarely be
+ encountered. If they are it may because something is wrong with the
+ CBOR, for example an array size is incorrect.
+
+ - Resource exhaustion. This only occurs when a string allocator is
+ configured to handle indefinite-length strings as other than that,
+ this implementation does no dynamic memory allocation.
+
+ - There are a few CBOR constructs that are not handled without some
+ extra configuration. These are indefinite length strings and maps
+ with labels that are not strings or integers. See QCBORDecode_Init().
+
+ */
+QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
+
+/**
+ @brief Gets the next item including full list of tags for item.
+
+ @param[in] pCtx The decoder context.
+ @param[out] pDecodedItem Holds the CBOR item just decoded.
+ @param[in,out] pTagList On input array to put tags in; on output
+ the tags on this item. See
+ @ref QCBORTagListOut.
+
+ @return See return values for QCBORDecode_GetNext().
+
+ @retval QCBOR_ERR_TOO_MANY_TAGS The size of @c pTagList is too small.
+
+ This works the same as QCBORDecode_GetNext() except that it also
+ returns the full list of tags for the data item. This function should
+ only be needed when parsing CBOR to print it out or convert it to
+ some other format. It should not be needed to implement a CBOR-based
+ protocol. See QCBORDecode_GetNext() for the main description of tag
+ decoding.
+
+ Tags will be returned here whether or not they are in the built-in or
+ caller-configured tag lists.
+
+ CBOR has no upper bound of limit on the number of tags that can be
+ associated with a data item though in practice the number of tags on
+ an item will usually be small, perhaps less than five. 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 function is separate from QCBORDecode_GetNext() so as to not
+ have to make @ref QCBORItem large enough to be able to hold a full
+ list of tags. Even a list of five tags would nearly double its size
+ because tags can be a @c uint64_t ).
+ */
+QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList);
+
+
+/**
+ @brief Determine if a CBOR item was tagged with a particular tag
+
+ @param[in] pCtx The decoder context.
+ @param[in] pItem The CBOR item to check.
+ @param[in] uTag The tag to check, one of @c CBOR_TAG_XXX.
+
+ @return 1 if it was tagged, 0 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.
+ */
+int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag);
+
+
+/**
+ Check whether all the bytes have been decoded and maps and arrays closed.
+
+ @param[in] pCtx The context to check.
+
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN The CBOR is not well-formed
+ as some map or array was not closed off. This should always be treated as an
+ unrecoverable error.
+
+ @retval QCBOR_ERR_EXTRA_BYTES The CBOR was decoded correctly and
+ all maps and arrays are closed, but some of the bytes in the input were not consumed.
+ This may or may not be considered an error.
+
+ @retval QCBOR_SUCCES There were no errors and all bytes were
+ consumed.
+
+ This should always be called to determine if all maps and arrays
+ where correctly closed and that the CBOR was well-formed.
+
+ This calls the destructor for the string allocator, if one is in use.
+
+ Some CBOR protocols use a CBOR sequence [RFC 8742]
+ (https://tools.ietf.org/html/rfc8742) . A CBOR sequence typically
+ doesn't start out with a map or an array. The end of the CBOR is
+ determined in some other way, perhaps by external framing, or by the
+ occurrence of some particular CBOR data item or such. The buffer given
+ to decode must start out with valid CBOR, but it can have extra bytes
+ at the end that are not CBOR or CBOR that is to be ignored.
+
+ QCBORDecode_Finish() should still be called when decoding CBOR
+ Sequences to check that the input decoded was well-formed. If the
+ input was well-formed and there are extra bytes at the end @ref
+ QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a
+ successful decode.
+ */
+QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
+
+
+
+
+/**
+ @brief Convert int64_t to smaller integers safely.
+
+ @param [in] src An @c int64_t.
+ @param [out] dest A smaller sized integer to convert to.
+
+ @return 0 on success -1 if not
+
+ When decoding an integer, the CBOR decoder will return the value as
+ an int64_t unless the integer is in the range of @c INT64_MAX and @c
+ UINT64_MAX. That is, unless the value is so large that it can only be
+ represented as a @c uint64_t, it will be an @c int64_t.
+
+ CBOR itself doesn't size the individual integers it carries at
+ all. The only limits it puts on the major integer types is that they
+ are 8 bytes or less in length. Then encoders like this one use the
+ smallest number of 1, 2, 4 or 8 bytes to represent the integer based
+ on its value. There is thus no notion that one data item in CBOR is
+ a 1-byte integer and another is a 4-byte integer.
+
+ The interface to this CBOR encoder only uses 64-bit integers. Some
+ CBOR protocols or implementations of CBOR protocols may not want to
+ work with something smaller than a 64-bit integer. Perhaps an array
+ of 1000 integers needs to be sent and none has a value larger than
+ 50,000 and are represented as @c uint16_t.
+
+ The sending / encoding side is easy. Integers are temporarily widened
+ to 64-bits as a parameter passing through QCBOREncode_AddInt64() and
+ encoded in the smallest way possible for their value, possibly in
+ less than an @c uint16_t.
+
+ On the decoding side the integers will be returned at @c int64_t even if
+ they are small and were represented by only 1 or 2 bytes in the
+ encoded CBOR. The functions here will convert integers to a small
+ representation with an overflow check.
+
+ (The decoder could have support 8 different integer types and
+ represented the integer with the smallest type automatically, but
+ this would have made the decoder more complex and code calling the
+ decoder more complex in most use cases. In most use cases on 64-bit
+ machines it is no burden to carry around even small integers as
+ 64-bit values).
+ */
+static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest)
+{
+ if(src > INT32_MAX || src < INT32_MIN) {
+ return -1;
+ } else {
+ *dest = (int32_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest)
+{
+ if(src > INT16_MAX || src < INT16_MIN) {
+ return -1;
+ } else {
+ *dest = (int16_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest)
+{
+ if(src > INT8_MAX || src < INT8_MIN) {
+ return -1;
+ } else {
+ *dest = (int8_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest)
+{
+ if(src > UINT32_MAX || src < 0) {
+ return -1;
+ } else {
+ *dest = (uint32_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest)
+{
+ if(src > UINT16_MAX || src < 0) {
+ return -1;
+ } else {
+ *dest = (uint16_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest)
+{
+ if(src > UINT8_MAX || src < 0) {
+ return -1;
+ } else {
+ *dest = (uint8_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest)
+{
+ if(src < 0) {
+ return -1;
+ } else {
+ *dest = (uint64_t) src;
+ }
+ return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* qcbor_decode_h */
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
new file mode 100644
index 0000000..46fa578
--- /dev/null
+++ b/inc/qcbor/qcbor_encode.h
@@ -0,0 +1,2189 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+
+#ifndef qcbor_encode_h
+#define qcbor_encode_h
+
+
+#include "qcbor/qcbor_common.h"
+#include "qcbor/qcbor_private.h"
+#include <stdbool.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} // Keep editor indention formatting happy
+#endif
+#endif
+
+
+/**
+ @file qcbor_encode.h
+
+ Q C B O R E n c o d e / D e c o d e
+
+ This implements CBOR -- Concise Binary Object Representation as
+ defined in [RFC 7049] (https://tools.ietf.org/html/rfc7049). More
+ info is at http://cbor.io. This is a near-complete implementation of
+ the specification. Limitations are listed further down.
+
+ CBOR is intentionally designed to be translatable to JSON, but not
+ all CBOR can convert to JSON. See RFC 7049 for more info on how to
+ construct CBOR that is the most JSON friendly.
+
+ The memory model for encoding and decoding is that encoded CBOR must
+ be in a contiguous buffer in memory. During encoding the caller must
+ supply an output buffer and if the encoding would go off the end of
+ the buffer an error is returned. During decoding the caller supplies
+ the encoded CBOR in a contiguous buffer and the decoder returns
+ pointers and lengths into that buffer for strings.
+
+ This implementation does not require malloc. All data structures
+ passed in/out of the APIs can fit on the stack.
+
+ Decoding of indefinite-length strings is a special case that requires
+ a "string allocator" to allocate memory into which the segments of
+ the string are coalesced. Without this, decoding will error out if an
+ indefinite-length string is encountered (indefinite-length maps and
+ arrays do not require the string allocator). A simple string
+ allocator called MemPool is built-in and will work if supplied with a
+ block of memory to allocate. The string allocator can optionally use
+ malloc() or some other custom scheme.
+
+ Here are some terms and definitions:
+
+ - "Item", "Data Item": An integer or string or such. The basic "thing" that
+ CBOR is about. An array is an item itself that contains some items.
+
+ - "Array": An ordered sequence of items, the same as JSON.
+
+ - "Map": A collection of label/value pairs. Each pair is a data
+ item. A JSON "object" is the same as a CBOR "map".
+
+ - "Label": The data item in a pair in a map that names or identifies
+ the pair, not the value. This implementation refers to it as a
+ "label". JSON refers to it as the "name". The CBOR RFC refers to it
+ this as a "key". This implementation chooses label instead because
+ key is too easily confused with a cryptographic key. The COSE
+ standard, which uses CBOR, has also chosen to use the term "label"
+ rather than "key" for this same reason.
+
+ - "Key": See "Label" above.
+
+ - "Tag": Optional integer that can be added before each data item
+ usually to indicate it is new or more specific data type. For
+ example, a tag can indicate an integer is a date, or that a map is to
+ be considered a type (analogous to a typedef in C).
+
+ - "Initial Byte": The first byte of an encoded item. Encoding and
+ decoding of this byte is taken care of by the implementation.
+
+ - "Additional Info": In addition to the major type, all data items
+ have some other info. This is usually the length of the data but can
+ be several other things. Encoding and decoding of this is taken care
+ of by the implementation.
+
+ CBOR has two mechanisms for tagging and labeling the data values like
+ integers and strings. For example, an integer that represents
+ someone's birthday in epoch seconds since Jan 1, 1970 could be
+ encoded like this:
+
+ - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64),
+ the primitive positive integer.
+
+ - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer
+ represents a date in the form of the number of seconds since Jan 1,
+ 1970.
+
+ - Last it has a string "label" like "BirthDate" indicating the
+ meaning of the data.
+
+ The encoded binary looks like this:
+
+ a1 # Map of 1 item
+ 69 # Indicates text string of 9 bytes
+ 426972746844617465 # The text "BirthDate"
+ c1 # Tags next integer as epoch date
+ 1a # Indicates a 4-byte integer
+ 580d4172 # unsigned integer date 1477263730
+
+ Implementors using this API will primarily work with
+ labels. Generally, tags are only needed for making up new data
+ types. This implementation covers most of the data types defined in
+ the RFC using tags. It also, allows for the use of custom tags if
+ necessary.
+
+ This implementation explicitly supports labels that are text strings
+ and integers. Text strings translate nicely into JSON objects and are
+ very readable. Integer labels are much less readable but can be very
+ compact. If they are in the range of 0 to 23, they take up only one
+ byte.
+
+ CBOR allows a label to be any type of data including an array or a
+ map. It is possible to use this API to construct and parse such
+ labels, but it is not explicitly supported.
+
+ A common encoding usage mode is to invoke the encoding twice. First
+ with no output buffer to compute the length of the needed output
+ buffer. Then the correct sized output buffer is allocated. Last the
+ encoder is invoked again, this time with the output buffer.
+
+ The double invocation is not required if the maximum output buffer
+ size can be predicted. This is usually possible for simple CBOR
+ structures. If the double invocation is implemented, it can be in a
+ loop or function as in the example code so that the code doesn't have
+ to actually be written twice, saving code size.
+
+ If a buffer too small to hold the encoded output is given, the error
+ @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be
+ written off the end of the output buffer no matter which functions
+ here are called or what parameters are passed to them.
+
+ The encoding error handling is simple. The only possible errors are
+ trying to encode structures that are too large or too complex. There
+ are no internal malloc calls so there will be no failures for out of
+ memory. The error state is tracked internally, so there is no need
+ to check for errors when encoding. Only the return code from
+ QCBOREncode_Finish() need be checked as once an error happens, the
+ encoder goes into an error state and calls to it to add more data
+ will do nothing. An error check is not needed after every data item
+ is added.
+
+ Encoding generally proceeds by calling QCBOREncode_Init(), calling
+ lots of @c QCBOREncode_AddXxx() functions and calling
+ QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx()
+ functions for various data types. The input buffers need only to be
+ valid during the @c QCBOREncode_AddXxx() calls as the data is copied
+ into the output buffer.
+
+ There are three `Add` functions for each data type. The first / main
+ one for the type is for adding the data item to an array. The second
+ one's name ends in `ToMap`, is used for adding data items to maps and
+ takes a string argument that is its label in the map. The third one
+ ends in `ToMapN`, is also used for adding data items to maps, and
+ takes an integer argument that is its label in the map.
+
+ The simplest aggregate type is an array, which is a simple ordered
+ set of items without labels the same as JSON arrays. Call
+ QCBOREncode_OpenArray() to open a new array, then various @c
+ QCBOREncode_AddXxx() functions to put items in the array and then
+ QCBOREncode_CloseArray(). Nesting to the limit @ref
+ QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by
+ closes or an encoding error will be returned.
+
+ The other aggregate type is a map which does use labels. The `Add`
+ functions that end in `ToMap` and `ToMapN` are convenient ways to add
+ labeled data items to a map. You can also call any type of `Add`
+ function once to add a label of any time and then call any type of
+ `Add` again to add its value.
+
+ Note that when you nest arrays or maps in a map, the nested array or
+ map has a label.
+
+ Many CBOR-based protocols start with an array or map. This makes them
+ self-delimiting. No external length or end marker is needed to know
+ the end. It is also possible not start this way, in which case this
+ it is usually called a CBOR sequence which is described in [RFC 8742] (https://tools.ietf.org/html/rfc8742 ).
+ This encoder supports either just by whether the first item added is an
+ array, map or other.
+
+ @anchor Tags-Overview
+ Any CBOR data item can be tagged to add semantics, define a new data
+ type or such. Some tags are fully standardized and some are just
+ registered. Others are not registered and used in a proprietary way.
+
+ Encoding and decoding of many of the registered tags is fully
+ implemented by QCBOR. It is also possible to encode and decode tags
+ that are not directly supported. For many use cases the built-in tag
+ support should be adequate.
+
+ For example, the registered epoch date tag is supported in encoding
+ by QCBOREncode_AddDateEpoch() and in decoding by @ref
+ QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref
+ QCBORItem. This is typical of the built-in tag support. There is an
+ API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded.
+
+ Tags are registered in the [IANA CBOR Tags Registry]
+ (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There
+ are roughly three options to create a new tag. First, a public
+ specification can be created and the new tag registered with IANA.
+ This is the most formal. Second, the new tag can be registered with
+ IANA with just a short description rather than a full specification.
+ These tags must be greater than 256. Third, a tag can be used without
+ any IANA registration, though the registry should be checked to see
+ that the new value doesn't collide with one that is registered. The
+ value of these tags must be 256 or larger.
+
+ The encoding side of tags not built-in is handled by
+ QCBOREncode_AddTag() 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.
+
+ Summary Limits of this implementation:
+ - The entire encoded CBOR must fit into contiguous memory.
+ - Max size of encoded / decoded CBOR data is @c UINT32_MAX (4GB).
+ - Max array / map nesting level when encoding / decoding is
+ @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
+ - Max items in an array or map when encoding / decoding is
+ @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
+ - Does not directly support labels in maps other than text strings & integers.
+ - Does not directly support integer labels greater than @c INT64_MAX.
+ - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
+ - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX.
+ - Tags on labels are ignored during decoding.
+ - There is no duplicate detection of map labels (but duplicates are passed on).
+ - Works only on 32- and 64-bit CPUs (modifications could make it work
+ on 16-bit CPUs).
+
+ The public interface uses @c size_t for all lengths. Internally the
+ implementation uses 32-bit lengths by design to use less memory and
+ fit structures on the stack. This limits the encoded CBOR it can work
+ with to size @c UINT32_MAX (4GB) which should be enough.
+
+ This implementation assumes two's compliment integer machines. @c
+ <stdint.h> also requires this. It is possible to modify this
+ implementation for another integer representation, but all modern
+ machines seem to be two's compliment.
+
+ */
+
+
+/*
+ The size of the buffer to be passed to QCBOREncode_EncodeHead(). It is one
+ byte larger than sizeof(uint64_t) + 1, the actual maximum size of the
+ head of a CBOR data item. because QCBOREncode_EncodeHead() needs
+ one extra byte to work.
+ */
+#define QCBOR_HEAD_BUFFER_SIZE (sizeof(uint64_t) + 2)
+
+
+
+/**
+ QCBOREncodeContext is the data type that holds context for all the
+ encoding functions. It is less than 200 bytes, so it can go on the
+ stack. The contents are opaque, and the caller should not access
+ internal members. A context may be re used serially as long as it is
+ re initialized.
+ */
+typedef struct _QCBOREncodeContext QCBOREncodeContext;
+
+
+/**
+ Initialize the encoder to prepare to encode some CBOR.
+
+ @param[in,out] pCtx The encoder context to initialize.
+ @param[in] Storage The buffer into which this encoded result
+ will be placed.
+
+ Call this once at the start of an encoding of a CBOR structure. Then
+ call the various @c QCBOREncode_AddXxx() functions to add the data
+ items. Then call QCBOREncode_Finish().
+
+ The maximum output buffer is @c UINT32_MAX (4GB). This is not a
+ practical limit in any way and reduces the memory needed by the
+ implementation. The error @ref QCBOR_ERR_BUFFER_TOO_LARGE will be
+ returned by QCBOREncode_Finish() if a larger buffer length is passed
+ in.
+
+ If this is called with @c Storage.ptr as @c NULL and @c Storage.len a
+ large value like @c UINT32_MAX, all the QCBOREncode_AddXxx()
+ functions and QCBOREncode_Finish() can still be called. No data will
+ be encoded, but the length of what would be encoded will be
+ calculated. The length of the encoded structure will be handed back
+ in the call to QCBOREncode_Finish(). You can then allocate a buffer
+ of that size and call all the encoding again, this time to fill in
+ the buffer.
+
+ A @ref QCBOREncodeContext can be reused over and over as long as
+ QCBOREncode_Init() is called.
+ */
+void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage);
+
+
+/**
+ @brief Add a signed 64-bit integer to the encoded output.
+
+ @param[in] pCtx The encoding context to add the integer to.
+ @param[in] nNum The integer to add.
+
+ The integer will be encoded and added to the CBOR output.
+
+ This function figures out the size and the sign and encodes in the
+ correct minimal CBOR. Specifically, it will select CBOR major type 0
+ or 1 based on sign and will encode to 1, 2, 4 or 8 bytes depending on
+ the value of the integer. Values less than 24 effectively encode to
+ one byte because they are encoded in with the CBOR major type. This
+ is a neat and efficient characteristic of CBOR that can be taken
+ advantage of when designing CBOR-based protocols. If integers like
+ tags can be kept between -23 and 23 they will be encoded in one byte
+ including the major type.
+
+ If you pass a smaller int, say an @c int16_t or a small value, say
+ 100, the encoding will still be CBOR's most compact that can
+ represent the value. For example, CBOR always encodes the value 0 as
+ one byte, 0x00. The representation as 0x00 includes identification of
+ the type as an integer too as the major type for an integer is 0. See
+ [RFC 7049] (https://tools.ietf.org/html/rfc7049) Appendix A for more
+ examples of CBOR encoding. This compact encoding is also canonical
+ CBOR as per section 3.9 in RFC 7049.
+
+ There are no functions to add @c int16_t or @c int32_t because they
+ are not necessary because this always encodes to the smallest number
+ of bytes based on the value (If this code is running on a 32-bit
+ machine having a way to add 32-bit integers would reduce code size
+ some).
+
+ If the encoding context is in an error state, this will do
+ nothing. If an error occurs when adding this integer, the internal
+ error flag will be set, and the error will be returned when
+ QCBOREncode_Finish() is called.
+
+ See also QCBOREncode_AddUInt64().
+ */
+void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum);
+
+static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum);
+
+static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum);
+
+
+/**
+ @brief Add an unsigned 64-bit integer to the encoded output.
+
+ @param[in] pCtx The encoding context to add the integer to.
+ @param[in] uNum The integer to add.
+
+ The integer will be encoded and added to the CBOR output.
+
+ The only reason so use this function is for integers larger than @c
+ INT64_MAX and smaller than @c UINT64_MAX. Otherwise
+ QCBOREncode_AddInt64() will work fine.
+
+ Error handling is the same as for QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
+
+static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
+
+static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum);
+
+
+/**
+ @brief Add a UTF-8 text string to the encoded output.
+
+ @param[in] pCtx The encoding context to add the text to.
+ @param[in] Text Pointer and length of text to add.
+
+ The text passed in must be unencoded UTF-8 according to [RFC 3629]
+ (https://tools.ietf.org/html/rfc3629). There is no NULL
+ termination. The text is added as CBOR major type 3.
+
+ If called with @c nBytesLen equal to 0, an empty string will be
+ added. When @c nBytesLen is 0, @c pBytes may be @c NULL.
+
+ Note that the restriction of the buffer length to a @c uint32_t is
+ entirely intentional as this encoder is not capable of encoding
+ lengths greater. This limit to 4GB for a text string should not be a
+ problem.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text);
+
+static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text);
+
+static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text);
+
+
+/**
+ @brief Add a UTF-8 text string to the encoded output.
+
+ @param[in] pCtx The encoding context to add the text to.
+ @param[in] szString Null-terminated text to add.
+
+ This works the same as QCBOREncode_AddText().
+ */
+static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString);
+
+static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString);
+
+static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString);
+
+
+/**
+ @brief Add a floating-point number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the double to.
+ @param[in] dNum The double-precision number to add.
+
+ This outputs a floating-point number with CBOR major type 7.
+
+ This will selectively encode the double-precision floating-point
+ number as either double-precision, single-precision or
+ half-precision. It will always encode infinity, NaN and 0 has half
+ precision. If no precision will be lost in the conversion to
+ half-precision, then it will be converted and encoded. If not and no
+ precision will be lost in conversion to single-precision, then it
+ will be converted and encoded. If not, then no conversion is
+ performed, and it encoded as a double.
+
+ Half-precision floating-point numbers take up 2 bytes, half that of
+ single-precision, one quarter of double-precision
+
+ This automatically reduces the size of encoded messages a lot, maybe
+ even by four if most of values are 0, infinity or NaN.
+
+ On decode, these will always be returned as a double.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
+
+static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum);
+
+static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum);
+
+
+/**
+ @brief Add an optional tag.
+
+ @param[in] pCtx The encoding context to add the tag to.
+ @param[in] uTag The tag to add
+
+ This outputs a CBOR major type 6 item that tags the next data item
+ that is output usually to indicate it is some new data type.
+
+ For many of the common standard tags, a function to encode data using
+ it is provided and this is not needed. For example,
+ QCBOREncode_AddDateEpoch() already exists to output integers
+ representing dates with the right tag.
+
+ The tag is applied to the next data item added to the encoded
+ output. That data item that is to be tagged can be of any major CBOR
+ type. Any number of tags can be added to a data item by calling this
+ multiple times before the data item is added.
+
+ See @ref Tags-Overview for discussion of creating new non-standard
+ tags. See QCBORDecode_GetNext() for discussion of decoding custom
+ tags.
+*/
+void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag);
+
+
+/**
+ @brief Add an epoch-based date.
+
+ @param[in] pCtx The encoding context to add the date to.
+ @param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time.
+
+ As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is
+ the most compact way to specify a date and time in CBOR. Note that
+ this is always UTC and does not include the time zone. Use
+ QCBOREncode_AddDateString() if you want to include the time zone.
+
+ The integer encoding rules apply here so the date will be encoded in
+ a minimal number of bytes. Until about the year 2106 these dates will
+ encode in 6 bytes -- one byte for the tag, one byte for the type and
+ 4 bytes for the integer. After that it will encode to 10 bytes.
+
+ Negative values are supported for dates before 1970.
+
+ If you care about leap-seconds and that level of accuracy, make sure
+ the system you are running this code on does it correctly. This code
+ just takes the value passed in.
+
+ This implementation cannot encode fractional seconds using float or
+ double even though that is allowed by CBOR, but you can encode them
+ if you want to by calling QCBOREncode_AddDouble() and
+ QCBOREncode_AddTag().
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date);
+
+static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date);
+
+static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date);
+
+
+/**
+ @brief Add a byte string to the encoded output.
+
+ @param[in] pCtx The encoding context to add the bytes to.
+ @param[in] Bytes Pointer and length of the input data.
+
+ Simply adds the bytes to the encoded output as CBOR major type 2.
+
+ If called with @c Bytes.len equal to 0, an empty string will be
+ added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+
+/**
+ @brief Add a binary UUID to the encoded output.
+
+ @param[in] pCtx The encoding context to add the UUID to.
+ @param[in] Bytes Pointer and length of the binary UUID.
+
+ A binary UUID as defined in [RFC 4122]
+ (https://tools.ietf.org/html/rfc4122) is added to the output.
+
+ It is output as CBOR major type 2, a binary string, with tag @ref
+ CBOR_TAG_BIN_UUID indicating the binary string is a UUID.
+ */
+static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a positive big number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the big number to.
+ @param[in] Bytes Pointer and length of the big number.
+
+ Big numbers are integers larger than 64-bits. Their format is
+ described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
+
+ It is output as CBOR major type 2, a binary string, with tag @ref
+ CBOR_TAG_POS_BIGNUM indicating the binary string is a positive big
+ number.
+
+ Often big numbers are used to represent cryptographic keys, however,
+ COSE which defines representations for keys chose not to use this
+ particular type.
+ */
+static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a negative big number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the big number to.
+ @param[in] Bytes Pointer and length of the big number.
+
+ Big numbers are integers larger than 64-bits. Their format is
+ described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
+
+ It is output as CBOR major type 2, a binary string, with tag @ref
+ CBOR_TAG_NEG_BIGNUM indicating the binary string is a negative big
+ number.
+
+ Often big numbers are used to represent cryptographic keys, however,
+ COSE which defines representations for keys chose not to use this
+ particular type.
+ */
+static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/**
+ @brief Add a decimal fraction to the encoded output.
+
+ @param[in] pCtx The encoding context to add the decimal fraction to.
+ @param[in] nMantissa The mantissa.
+ @param[in] nBase10Exponent The exponent.
+
+ The value is nMantissa * 10 ^ nBase10Exponent.
+
+ A decimal fraction is good for exact representation of some values
+ that can't be represented exactly with standard C (IEEE 754)
+ floating-point numbers. Much larger and much smaller numbers can
+ also be represented than floating-point because of the larger number
+ of bits in the exponent.
+
+ The decimal fraction is conveyed as two integers, a mantissa and a
+ base-10 scaling factor.
+
+ For example, 273.15 is represented by the two integers 27315 and -2.
+
+ The exponent and mantissa have the range from @c INT64_MIN to
+ @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
+ to @c UINT64_MAX, but this implementation doesn't support this range to
+ reduce code size and interface complexity a little).
+
+ CBOR Preferred encoding of the integers is used, thus they will be encoded
+ in the smallest number of bytes possible.
+
+ See also QCBOREncode_AddDecimalFractionBigNum() for a decimal
+ fraction with arbitrarily large precision and QCBOREncode_AddBigFloat().
+
+ There is no representation of positive or negative infinity or NaN
+ (Not a Number). Use QCBOREncode_AddDouble() to encode them.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent);
+
+/**
+ @brief Add a decimal fraction with a big number mantissa to the encoded output.
+
+ @param[in] pCtx The encoding context to add the decimal fraction to.
+ @param[in] Mantissa The mantissa.
+ @param[in] bIsNegative false if mantissa is positive, true if negative.
+ @param[in] nBase10Exponent The exponent.
+
+ This is the same as QCBOREncode_AddDecimalFraction() except the
+ mantissa is a big number (See QCBOREncode_AddPositiveBignum())
+ allowing for arbitrarily large precision.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent);
+
+/**
+ @brief Add a big floating-point number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the bigfloat to.
+ @param[in] nMantissa The mantissa.
+ @param[in] nBase2Exponent The exponent.
+
+ The value is nMantissa * 2 ^ nBase2Exponent.
+
+ "Bigfloats", as CBOR terms them, are similar to IEEE floating-point
+ numbers in having a mantissa and base-2 exponent, but they are not
+ supported by hardware or encoded the same. They explicitly use two
+ CBOR-encoded integers to convey the mantissa and exponent, each of which
+ can be 8, 16, 32 or 64 bits. With both the mantissa and exponent
+ 64 bits they can express more precision and a larger range than an
+ IEEE double floating-point number. See
+ QCBOREncode_AddBigFloatBigNum() for even more precision.
+
+ For example, 1.5 would be represented by a mantissa of 3 and an
+ exponent of -1.
+
+ The exponent and mantissa have the range from @c INT64_MIN to
+ @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
+ to @c UINT64_MAX, but this implementation doesn't support this range to
+ reduce code size and interface complexity a little).
+
+ CBOR Preferred encoding of the integers is used, thus they will be encoded
+ in the smallest number of bytes possible.
+
+ This can also be used to represent floating-point numbers in
+ environments that don't support IEEE 754.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent);
+
+
+/**
+ @brief Add a big floating-point number with a big number mantissa to
+ the encoded output.
+
+ @param[in] pCtx The encoding context to add the bigfloat to.
+ @param[in] Mantissa The mantissa.
+ @param[in] bIsNegative false if mantissa is positive, true if negative.
+ @param[in] nBase2Exponent The exponent.
+
+ This is the same as QCBOREncode_AddBigFloat() except the mantissa is
+ a big number (See QCBOREncode_AddPositiveBignum()) allowing for
+ arbitrary precision.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent);
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+/**
+ @brief Add a text URI to the encoded output.
+
+ @param[in] pCtx The encoding context to add the URI to.
+ @param[in] URI Pointer and length of the URI.
+
+ The format of URI must be per [RFC 3986]
+ (https://tools.ietf.org/html/rfc3986).
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_URI indicating the text string is a URI.
+
+ A URI in a NULL-terminated string, @c szURI, can be easily added with
+ this code:
+
+ QCBOREncode_AddURI(pCtx, UsefulBuf_FromSZ(szURI));
+ */
+static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI);
+
+static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI);
+
+static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI);
+
+
+/**
+ @brief Add Base64-encoded text to encoded output.
+
+ @param[in] pCtx The encoding context to add the base-64 text to.
+ @param[in] B64Text Pointer and length of the base-64 encoded text.
+
+ The text content is Base64 encoded data per [RFC 4648]
+ (https://tools.ietf.org/html/rfc4648).
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_B64 indicating the text string is Base64 encoded.
+ */
+static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
+
+
+/**
+ @brief Add base64url encoded data to encoded output.
+
+ @param[in] pCtx The encoding context to add the base64url to.
+ @param[in] B64Text Pointer and length of the base64url encoded text.
+
+ The text content is base64URL encoded text as per [RFC 4648]
+ (https://tools.ietf.org/html/rfc4648).
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_B64URL indicating the text string is a Base64url encoded.
+ */
+static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
+
+
+/**
+ @brief Add Perl Compatible Regular Expression.
+
+ @param[in] pCtx The encoding context to add the regular expression to.
+ @param[in] Regex Pointer and length of the regular expression.
+
+ The text content is Perl Compatible Regular
+ Expressions (PCRE) / JavaScript syntax [ECMA262].
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_REGEX indicating the text string is a regular expression.
+ */
+static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex);
+
+static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex);
+
+static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex);
+
+
+/**
+ @brief MIME encoded text to the encoded output.
+
+ @param[in] pCtx The encoding context to add the MIME data to.
+ @param[in] MIMEData Pointer and length of the regular expression.
+
+ The text content is in MIME format per [RFC 2045]
+ (https://tools.ietf.org/html/rfc2045) including the headers. Note
+ that this only supports text-format MIME. Binary MIME is not
+ supported.
+
+ It is output as CBOR major type 3, a text string, with tag
+ @ref CBOR_TAG_MIME indicating the text string is MIME data.
+ */
+static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData);
+
+static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData);
+
+static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData);
+
+
+/**
+ @brief Add an RFC 3339 date string
+
+ @param[in] pCtx The encoding context to add the date to.
+ @param[in] szDate Null-terminated string with date to add.
+
+ The string szDate should be in the form of [RFC 3339]
+ (https://tools.ietf.org/html/rfc3339) as defined by section 3.3 in
+ [RFC 4287] (https://tools.ietf.org/html/rfc4287). This is as
+ described in section 2.4.1 in [RFC 7049]
+ (https://tools.ietf.org/html/rfc7049).
+
+ Note that this function doesn't validate the format of the date string
+ at all. If you add an incorrect format date string, the generated
+ CBOR will be incorrect and the receiver may not be able to handle it.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate);
+
+static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate);
+
+static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate);
+
+
+/**
+ @brief Add a standard Boolean.
+
+ @param[in] pCtx The encoding context to add the Boolean to.
+ @param[in] b true or false from @c <stdbool.h>.
+
+ Adds a Boolean value as CBOR major type 7.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b);
+
+static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b);
+
+static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b);
+
+
+
+/**
+ @brief Add a NULL to the encoded output.
+
+ @param[in] pCtx The encoding context to add the NULL to.
+
+ Adds the NULL value as CBOR major type 7.
+
+ This NULL doesn't have any special meaning in CBOR such as a
+ terminating value for a string or an empty value.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Add an "undef" to the encoded output.
+
+ @param[in] pCtx The encoding context to add the "undef" to.
+
+ Adds the undef value as CBOR major type 7.
+
+ Note that this value will not translate to JSON.
+
+ This Undef doesn't have any special meaning in CBOR such as a
+ terminating value for a string or an empty value.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Indicates that the next items added are in an array.
+
+ @param[in] pCtx The encoding context to open the array in.
+
+ Arrays are the basic CBOR aggregate or structure type. Call this
+ function to start or open an array. Then call the various @c
+ QCBOREncode_AddXxx() functions to add the items that go into the
+ array. Then call QCBOREncode_CloseArray() when all items have been
+ added. The data items in the array can be of any type and can be of
+ mixed types.
+
+ Nesting of arrays and maps is allowed and supported just by calling
+ QCBOREncode_OpenArray() again before calling
+ QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this
+ implementation does in order to keep it smaller and simpler. The
+ limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of
+ times this can be called without calling
+ QCBOREncode_CloseArray(). QCBOREncode_Finish() will return @ref
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function
+ just sets an error state and returns no value when this occurs.
+
+ If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to a
+ single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be returned
+ when QCBOREncode_Finish() is called.
+
+ An array itself must have a label if it is being added to a map.
+ Note that array elements do not have labels (but map elements do).
+
+ An array itself may be tagged by calling QCBOREncode_AddTag() before this call.
+ */
+static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Close an open array.
+
+ @param[in] pCtx The encoding context to close the array in.
+
+ The closes an array opened by QCBOREncode_OpenArray(). It reduces
+ nesting level by one. All arrays (and maps) must be closed before
+ calling QCBOREncode_Finish().
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_OpenArray(), then
+ @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish()
+ is called.
+
+ If this is called and it is not an array that is currently open, @ref
+ QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
+
+
+/**
+ @brief Indicates that the next items added are in a map.
+
+ @param[in] pCtx The encoding context to open the map in.
+
+ See QCBOREncode_OpenArray() for more information, particularly error
+ handling.
+
+ CBOR maps are an aggregate type where each item in the map consists
+ of a label and a value. They are similar to JSON objects.
+
+ The value can be any CBOR type including another map.
+
+ The label can also be any CBOR type, but in practice they are
+ typically, integers as this gives the most compact output. They might
+ also be text strings which gives readability and translation to JSON.
+
+ Every @c QCBOREncode_AddXxx() call has one version that ends with @c
+ InMap for adding items to maps with string labels and one that ends
+ with @c InMapN that is for adding with integer labels.
+
+ RFC 7049 uses the term "key" instead of "label".
+
+ If you wish to use map labels that are neither integer labels nor
+ text strings, then just call the QCBOREncode_AddXxx() function
+ explicitly to add the label. Then call it again to add the value.
+
+ See the [RFC 7049] (https://tools.ietf.org/html/rfc7049) for a lot
+ more information on creating maps.
+ */
+static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+
+/**
+ @brief Close an open map.
+
+ @param[in] pCtx The encoding context to close the map in .
+
+ This closes a map opened by QCBOREncode_OpenMap(). It reduces nesting
+ level by one.
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_OpenMap(),
+ then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this is called and it is not a map that is currently open, @ref
+ QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx);
+
+
+/**
+ @brief Indicate start of encoded CBOR to be wrapped in a bstr.
+
+ @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in.
+
+ All added encoded items between this call and a call to
+ QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will
+ appear in the final output as a byte string. That byte string will
+ contain encoded CBOR. This increases nesting level by one.
+
+ The typical use case is for encoded CBOR that is to be
+ cryptographically hashed, as part of a [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152) implementation.
+
+ Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() avoids
+ having to encode the items first in one buffer (e.g., the COSE
+ payload) and then add that buffer as a bstr to another encoding
+ (e.g. the COSE to-be-signed bytes, the @c Sig_structure) potentially
+ halving the memory needed.
+
+ RFC 7049 states the purpose of this wrapping is to prevent code
+ relaying the signed data but not verifying it from tampering with the
+ signed data thus making the signature unverifiable. It is also quite
+ beneficial for the signature verification code. Standard CBOR
+ decoders usually do not give access to partially decoded CBOR as
+ would be needed to check the signature of some CBOR. With this
+ wrapping, standard CBOR decoders can be used to get to all the data
+ needed for a signature verification.
+ */
+static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Close a wrapping bstr.
+
+ @param[in] pCtx The encoding context to close of bstr wrapping in.
+ @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr
+ as well as the bytes in @c pWrappedCBOR.
+ @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes.
+
+ The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces
+ nesting level by one.
+
+ A pointer and length of the enclosed encoded CBOR is returned in @c
+ *pWrappedCBOR if it is not @c NULL. The main purpose of this is so
+ this data can be hashed (e.g., with SHA-256) as part of a [RFC 8152,
+ COSE] (https://tools.ietf.org/html/rfc8152)
+ implementation. **WARNING**, this pointer and length should be used
+ right away before any other calls to @c QCBOREncode_CloseXxx() as
+ they will move data around and the pointer and length will no longer
+ be to the correct encoded CBOR.
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_BstrWrap(), then
+ @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this is called and it is not a wrapping bstr that is currently
+ open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when
+ QCBOREncode_Finish() is called.
+
+ QCBOREncode_CloseBstrWrap() is a deprecated version of this function
+ that is equivalent to the call with @c bIncludeCBORHead @c true.
+ */
+void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR);
+
+static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR);
+
+
+/**
+ @brief Add some already-encoded CBOR bytes.
+
+ @param[in] pCtx The encoding context to add the already-encode CBOR to.
+ @param[in] Encoded The already-encoded CBOR to add to the context.
+
+ The encoded CBOR being added must be fully conforming CBOR. It must
+ be complete with no arrays or maps that are incomplete. While this
+ encoder doesn't ever produce indefinite lengths, it is OK for the
+ raw CBOR added here to have indefinite lengths.
+
+ The raw CBOR added here is not checked in anyway. If it is not
+ conforming or has open arrays or such, the final encoded CBOR
+ will probably be wrong or not what was intended.
+
+ If the encoded CBOR being added here contains multiple items, they
+ must be enclosed in a map or array. At the top level the raw
+ CBOR must be a single data item.
+ */
+static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded);
+
+static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded);
+
+static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded);
+
+
+/**
+ @brief Get the encoded result.
+
+ @param[in] pCtx The context to finish encoding with.
+ @param[out] pEncodedCBOR Pointer and length of encoded CBOR.
+
+ @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error
+
+ @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error
+
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error
+
+ @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size
+
+ @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size
+
+ @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit
+
+ @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit
+
+ If this returns success @ref QCBOR_SUCCESS the encoding was a success
+ and the return length is correct and complete.
+
+ If no buffer was passed to QCBOREncode_Init(), then only the length
+ was computed. If a buffer was passed, then the encoded CBOR is in the
+ buffer.
+
+ Encoding errors primarily manifest here as most other encoding function
+ do no return an error. They just set the error state in the encode
+ context after which no encoding function does anything.
+
+ Three types of errors manifest here. The first type are nesting
+ errors where the number of @c QCBOREncode_OpenXxx() calls do not
+ match the number @c QCBOREncode_CloseXxx() calls. The solution is to
+ fix the calling code.
+
+ The second type of error is because the buffer given is either too
+ small or too large. The remedy is to give a correctly sized buffer.
+
+ The third type are due to limits in this implementation. @ref
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by encoding the
+ CBOR in two (or more) phases and adding the CBOR from the first phase
+ to the second with @c QCBOREncode_AddEncoded().
+
+ If an error is returned, the buffer may have partially encoded
+ incorrect CBOR in it and it should not be used. Likewise, the length
+ may be incorrect and should not be used.
+
+ Note that the error could have occurred in one of the many @c
+ QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was
+ called. This error handling reduces the CBOR implementation size but
+ makes debugging harder.
+
+ This may be called multiple times. It will always return the same. It
+ can also be interleaved with calls to QCBOREncode_FinishGetSize().
+
+ QCBOREncode_GetErrorState() can be called to get the current
+ error state and abort encoding early as an optimization, but is
+ is never required.
+ */
+QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
+
+
+/**
+ @brief Get the encoded CBOR and error status.
+
+ @param[in] pCtx The context to finish encoding with.
+ @param[out] uEncodedLen The length of the encoded or potentially
+ encoded CBOR in bytes.
+
+ @return The same errors as QCBOREncode_Finish().
+
+ This functions the same as QCBOREncode_Finish(), but only returns the
+ size of the encoded output.
+ */
+QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen);
+
+
+/**
+ @brief Indicate whether output buffer is NULL or not.
+
+ @param[in] pCtx The encoding context.
+
+ @return 1 if the output buffer is @c NULL.
+
+ Sometimes a @c NULL input buffer is given to QCBOREncode_Init() so
+ that the size of the generated CBOR can be calculated without
+ allocating a buffer for it. This returns 1 when the output buffer is
+ NULL and 0 when it is not.
+*/
+static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);
+
+ /**
+ @brief Get the encoding error state.
+
+ @param[in] pCtx The encoding context.
+
+ @return One of \ref QCBORError. See return values from
+ QCBOREncode_Finish()
+
+ Normally encoding errors need only be handled at the end of encoding
+ when QCBOREncode_Finish() is called. This can be called to get the
+ error result before finish should there be a need to halt encoding
+ before QCBOREncode_Finish() is called.
+*/
+static QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx);
+
+
+/**
+ Encode the "head" of a CBOR data item.
+
+ @param buffer Buffer to output the encoded head to; must be
+ @ref QCBOR_HEAD_BUFFER_SIZE bytes in size.
+ @param uMajorType One of CBOR_MAJOR_TYPE_XX.
+ @param uMinLen The minimum number of bytes to encode uNumber. Almost always
+ this is 0 to use preferred minimal encoding. If this is 4,
+ then even the values 0xffff and smaller will be encoded
+ as in 4 bytes. This is used primarily when encoding a
+ float or double put into uNumber as the leading zero bytes
+ for them must be encoded.
+ @param uNumber The numeric argument part of the CBOR head.
+ @return Pointer and length of the encoded head or
+ @NULLUsefulBufC if the output buffer is too small.
+
+ Callers to need to call this for normal CBOR encoding. Note that it doesn't even
+ take a @ref QCBOREncodeContext argument.
+
+ This encodes the major type and argument part of a data item. The
+ argument is an integer that is usually either the value or the length
+ of the data item.
+
+ This is exposed in the public interface to allow hashing of some CBOR
+ data types, bstr in particular, a chunk at a time so the full CBOR
+ doesn't have to be encoded in a contiguous buffer.
+
+ For example, if you have a 100,000 byte binary blob in a buffer that
+ needs to be a bstr encoded and then hashed. You could allocate a
+ 100,010 byte buffer and encode it normally. Alternatively, you can
+ encode the head in a 10 byte buffer with this function, hash that and
+ then hash the 100,000 bytes using the same hash context.
+
+ See also QCBOREncode_AddBytesLenOnly();
+ */
+UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
+ uint8_t uMajorType,
+ uint8_t uMinLen,
+ uint64_t uNumber);
+
+
+
+
+/* ===========================================================================
+ BEGINNING OF PRIVATE INLINE IMPLEMENTATION
+
+ =========================================================================== */
+
+/**
+ @brief Semi-private method to add a buffer full of bytes to encoded output
+
+ @param[in] pCtx The encoding context to add the integer to.
+ @param[in] uMajorType The CBOR major type of the bytes.
+ @param[in] Bytes The bytes to add.
+
+ Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
+ QCBOREncode_AddEncoded() instead. They are inline functions that call
+ this and supply the correct major type. This function is public to
+ make the inline functions work to keep the overall code size down and
+ because the C language has no way to make it private.
+
+ If this is called the major type should be @c
+ CBOR_MAJOR_TYPE_TEXT_STRING, @c CBOR_MAJOR_TYPE_BYTE_STRING or @c
+ CBOR_MAJOR_NONE_TYPE_RAW. The last one is special for adding
+ already-encoded CBOR.
+ */
+void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes);
+
+
+/**
+ @brief Semi-private method to open a map, array or bstr-wrapped CBOR
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
+ QCBOREncode_BstrWrap() instead of this.
+ */
+void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to open a map, array with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArrayIndefiniteLength() or
+ QCBOREncode_OpenMapIndefiniteLength() instead of this.
+ */
+void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to close a map, array or bstr wrapped CBOR
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close.
+
+ Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
+ */
+void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to close a map, array with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close.
+
+ Call QCBOREncode_CloseArrayIndefiniteLength() or
+ QCBOREncode_CloseMapIndefiniteLength() instead of this.
+ */
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx,
+ uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to add simple types.
+
+ @param[in] pCtx The encoding context to add the simple value to.
+ @param[in] uMinLen Minimum encoding size for uNum. Usually 0.
+ @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
+
+ This is used to add simple types like true and false.
+
+ Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
+ QCBOREncode_AddUndef() instead of this.
+
+ This function can add simple values that are not defined by CBOR
+ yet. This expansion point in CBOR should not be used unless they are
+ standardized.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, uint8_t uMinLen, uint64_t uNum);
+
+
+/**
+ @brief Semi-private method to add bigfloats and decimal fractions.
+
+ @param[in] pCtx The encoding context to add the value to.
+ @param[in] uTag The type 6 tag indicating what this is to be
+ @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
+ @c int64_t or the actual big number mantissa
+ if not.
+ @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
+ @param[in] nExponent The exponent.
+
+ This adds a tagged array with two members, the mantissa and exponent. The
+ mantissa can be either a big number or an @c int64_t.
+
+ Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
+ QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
+ is called instead of this.
+ */
+void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pCtx,
+ uint64_t uTag,
+ UsefulBufC BigNumMantissa,
+ bool bBigNumIsNegative,
+ int64_t nMantissa,
+ int64_t nExponent);
+
+/**
+ @brief Semi-private method to add only the type and length of a byte string.
+
+ @param[in] pCtx The context to initialize.
+ @param[in] Bytes Pointer and length of the input data.
+
+ This is the same as QCBOREncode_AddBytes() except it only adds the
+ CBOR encoding for the type and the length. It doesn't actually add
+ the bytes. You can't actually produce correct CBOR with this and the
+ rest of this API. It is only used for a special case where
+ the valid CBOR is created manually by putting this type and length in
+ and then adding the actual bytes. In particular, when only a hash of
+ the encoded CBOR is needed, where the type and header are hashed
+ separately and then the bytes is hashed. This makes it possible to
+ implement COSE Sign1 with only one copy of the payload in the output
+ buffer, rather than two, roughly cutting memory use in half.
+
+ This is only used for this odd case, but this is a supported
+ tested function.
+
+ See also QCBOREncode_EncodeHead().
+*/
+static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+
+
+
+static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
+{
+ // Use _AddBuffer() because _AddSZString() is defined below, not above
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddInt64(pCtx, uNum);
+}
+
+static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddInt64(pCtx, uNum);
+}
+
+
+static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum)
+{
+ // Use _AddBuffer() because _AddSZString() is defined below, not above
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddUInt64(pCtx, uNum);
+}
+
+static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddUInt64(pCtx, uNum);
+}
+
+
+static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
+}
+
+static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text)
+{
+ // Use _AddBuffer() because _AddSZString() is defined below, not above
+ QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddText(pCtx, Text);
+}
+
+static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddText(pCtx, Text);
+}
+
+
+inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString)
+{
+ QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString));
+}
+
+static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddSZString(pCtx, szString);
+}
+
+static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddSZString(pCtx, szString);
+}
+
+
+static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddDouble(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddDouble(pCtx, dNum);
+}
+
+
+static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+ QCBOREncode_AddInt64(pCtx, date);
+}
+
+static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+ QCBOREncode_AddInt64(pCtx, date);
+}
+
+static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+ QCBOREncode_AddInt64(pCtx, date);
+}
+
+
+static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+
+static inline void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx,
+ CBOR_TAG_DECIMAL_FRACTION,
+ NULLUsefulBufC,
+ false,
+ nMantissa,
+ nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx,
+ CBOR_TAG_DECIMAL_FRACTION,
+ Mantissa, bIsNegative,
+ 0,
+ nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, NULLUsefulBufC, false, nMantissa, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, Mantissa, bIsNegative, 0, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
+}
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+ QCBOREncode_AddText(pCtx, URI);
+}
+
+static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+ QCBOREncode_AddText(pCtx, URI);
+}
+
+static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+ QCBOREncode_AddText(pCtx, URI);
+}
+
+
+
+static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+
+static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+
+static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+ QCBOREncode_AddText(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+ QCBOREncode_AddText(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+ QCBOREncode_AddText(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+ QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+ QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+ QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+
+static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+ QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+ QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+ QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+
+static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum)
+{
+ QCBOREncode_AddType7(pCtx, 0, uNum);
+}
+
+static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+
+static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b)
+{
+ uint8_t uSimple = CBOR_SIMPLEV_FALSE;
+ if(b) {
+ uSimple = CBOR_SIMPLEV_TRUE;
+ }
+ QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBool(pCtx, b);
+}
+
+static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBool(pCtx, b);
+}
+
+
+static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL);
+}
+
+static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddNULL(pCtx);
+}
+
+static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddNULL(pCtx);
+}
+
+
+static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF);
+}
+
+static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddUndef(pCtx);
+}
+
+static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddUndef(pCtx);
+}
+
+
+static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
+}
+
+static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenArray(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenArray(pCtx);
+}
+
+static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
+}
+
+
+static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
+}
+
+static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenMap(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenMap(pCtx);
+}
+
+static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
+}
+
+
+static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+
+
+static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING);
+}
+
+static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_BstrWrap(pCtx);
+}
+
+static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_BstrWrap(pCtx);
+}
+
+static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR)
+{
+ QCBOREncode_CloseBstrWrap2(pCtx, true, pWrappedCBOR);
+}
+
+
+static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded);
+}
+
+static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddEncoded(pCtx, Encoded);
+}
+
+static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddEncoded(pCtx, Encoded);
+}
+
+
+static inline int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx)
+{
+ return UsefulOutBuf_IsBufferNULL(&(pCtx->OutBuf));
+}
+
+static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx)
+{
+ if(UsefulOutBuf_GetError(&(pCtx->OutBuf))) {
+ // Items didn't fit in the buffer.
+ // This check catches this condition for all the appends and inserts
+ // so checks aren't needed when the appends and inserts are performed.
+ // And of course UsefulBuf will never overrun the input buffer given
+ // to it. No complex analysis of the error handling in this file is
+ // needed to know that is true. Just read the UsefulBuf code.
+ pCtx->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
+ // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
+ // OK. Once the caller fixes this, they'll be unmasked.
+ }
+
+ return (QCBORError)pCtx->uError;
+}
+
+
+/* ===========================================================================
+ END OF PRIVATE INLINE IMPLEMENTATION
+
+ =========================================================================== */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* qcbor_encode_h */
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
new file mode 100644
index 0000000..a7cb440
--- /dev/null
+++ b/inc/qcbor/qcbor_private.h
@@ -0,0 +1,188 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+
+#ifndef qcbor_private_h
+#define qcbor_private_h
+
+
+#include <stdint.h>
+#include "UsefulBuf.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} // Keep editor indention formatting happy
+#endif
+#endif
+
+
+/*
+ The maxium nesting of arrays and maps when encoding or decoding.
+ (Further down in the file there is a definition that refers to this
+ that is public. This is done this way so there can be a nice
+ separation of public and private parts in this file.
+*/
+#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255
+
+
+/* The largest offset to the start of an array or map. It is slightly
+ less than UINT32_MAX so the error condition can be tests on 32-bit machines.
+ UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t.
+
+ This will cause trouble on a machine where size_t is less than 32-bits.
+ */
+#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100)
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Holds the data for tracking array and map nesting during encoding. Pairs up
+ with the Nesting_xxx functions to make an "object" to handle nesting encoding.
+
+ uStart is a uint32_t instead of a size_t to keep the size of this
+ struct down so it can be on the stack without any concern. It would be about
+ double if size_t was used instead.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
+ 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
+*/
+typedef struct __QCBORTrackNesting {
+ // PRIVATE DATA STRUCTURE
+ struct {
+ // See function QCBOREncode_OpenMapOrArray() for details on how this works
+ uint32_t uStart; // uStart is the byte position where the array starts
+ uint16_t uCount; // Number of items in the arrary or map; counts items
+ // in a map, not pairs of items
+ uint8_t uMajorType; // Indicates if item is a map or an array
+ } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
+ *pCurrentNesting; // the current nesting level
+} QCBORTrackNesting;
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Context / data object for encoding some CBOR. Used by all encode functions to
+ form a public "object" that does the job of encdoing.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
+ 32-bit machine: 15 + 1 + 132 = 148 bytes
+*/
+struct _QCBOREncodeContext {
+ // PRIVATE DATA STRUCTURE
+ UsefulOutBuf OutBuf; // Pointer to output buffer, its length and
+ // position in it
+ uint8_t uError; // Error state, always from QCBORError enum
+ QCBORTrackNesting nesting; // Keep track of array and map nesting
+};
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Holds the data for array and map nesting for decoding work. This structure
+ and the DecodeNesting_xxx functions form an "object" that does the work
+ for arrays and maps.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: 4 * 16 + 8 = 72
+ 32-bit machine: 4 * 16 + 4 = 68
+ */
+typedef struct __QCBORDecodeNesting {
+ // PRIVATE DATA STRUCTURE
+ struct {
+ uint16_t uCount;
+ uint8_t uMajorType;
+ } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1],
+ *pCurrent;
+} QCBORDecodeNesting;
+
+
+typedef struct {
+ // PRIVATE DATA STRUCTURE
+ void *pAllocateCxt;
+ UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
+} QCORInternalAllocator;
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ The decode context. This data structure plus the public QCBORDecode_xxx
+ functions form an "object" that does CBOR decoding.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes
+ 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes
+ */
+struct _QCBORDecodeContext {
+ // PRIVATE DATA STRUCTURE
+ UsefulInputBuf InBuf;
+
+ uint8_t uDecodeMode;
+ uint8_t bStringAllocateAll;
+
+ QCBORDecodeNesting nesting;
+
+ // If a string allocator is configured for indefinite-length
+ // strings, it is configured here.
+ QCORInternalAllocator StringAllocator;
+
+ // These are special for the internal MemPool allocator.
+ // They are not used otherwise. We tried packing these
+ // in the MemPool itself, but there are issues
+ // with memory alignment.
+ uint32_t uMemPoolSize;
+ uint32_t uMemPoolFreeOffset;
+
+ // This is NULL or points to QCBORTagList.
+ // It is type void for the same reason as above.
+ const void *pCallerConfiguredTagList;
+};
+
+// Used internally in the impementation here
+// Must not conflict with any of the official CBOR types
+#define CBOR_MAJOR_NONE_TYPE_RAW 9
+#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
+#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
+#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN 12
+#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN 13
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* qcbor_private_h */
diff --git a/min_use_main.c b/min_use_main.c
index 7d6f5d9..ba7ae67 100644
--- a/min_use_main.c
+++ b/min_use_main.c
@@ -31,7 +31,7 @@
// Created by Laurence Lundblade on 10/26/18.
#include <stdio.h>
-#include "qcbor.h"
+#include "qcbor/qcbor.h"
diff --git a/src/ieee754.c b/src/ieee754.c
index ac454b4..226282a 100644
--- a/src/ieee754.c
+++ b/src/ieee754.c
@@ -453,9 +453,8 @@
// Public function; see ieee754.h
-double IEEE754_FloatToDouble(float f)
+double IEEE754_FloatToDouble(uint32_t uFloat)
{
- const uint32_t uFloat = CopyFloatToUint32(f);
// Pull out the three parts of the single-precision float
// Do all the work in 64 bits because that is what the end result is.
// It may give smaller code size and will keep static analyzers happier.
diff --git a/src/ieee754.h b/src/ieee754.h
index 47bfea5..72444f1 100644
--- a/src/ieee754.h
+++ b/src/ieee754.h
@@ -103,7 +103,7 @@
floating-point HW or compiler-supplied SW.
This is a loss-less conversion.
*/
-double IEEE754_FloatToDouble(float f);
+double IEEE754_FloatToDouble(uint32_t ufloat);
// Both tags the value and gives the size
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index ab37435..99060f3 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -30,48 +30,8 @@
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
-/*==============================================================================
- FILE: qcbor_decode.c
- DESCRIPTION: This file contains the implementation of QCBOR.
-
- EDIT HISTORY FOR FILE:
-
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
-
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 01/28/2020 llundblade Refine integer signedness to quiet static analysis.
- 01/25/2020 llundblade Cleaner handling of too-long encoded string input.
- 01/25/2020 llundblade Refine use of integer types to quiet static analysis
- 01/08/2020 llundblade Documentation corrections & improved code formatting
- 12/30/19 llundblade Add support for decimal fractions and bigfloats.
- 11/07/19 llundblade Fix long long conversion to double compiler warning
- 09/07/19 llundblade Fix bug decoding empty arrays and maps
- 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR
- 07/31/19 llundblade New error code for better end of data handling
- 02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when
- bAllStrings set
- 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug
- 01/10/19 llundblade Clever type and argument decoder; 250 bytes smaller
- 11/9/18 llundblade Error codes are now enums.
- 11/2/18 llundblade Simplify float decoding and align with preferred
- float encoding
- 10/31/18 llundblade Switch to one license that is almost BSD-3.
- 10/28/18 llundblade Reworked tag decoding
- 10/15/18 llundblade Indefinite length maps and arrays supported
- 10/8/18 llundblade Indefinite length strings supported
- 02/04/17 llundbla Work on CPUs that don's require pointer alignment
- by making use of changes in UsefulBuf
- 03/01/17 llundbla More data types; decoding improvements and fixes
- 11/13/16 llundbla Integrate most TZ changes back into github version.
- 09/30/16 gkanike Porting to TZ.
- 03/15/16 llundbla Initial Version.
-
- =============================================================================*/
-
-#include "qcbor.h"
+#include "qcbor/qcbor_decode.h"
#include "ieee754.h"
@@ -86,7 +46,8 @@
/*===========================================================================
DecodeNesting -- Functions for tracking array/map nesting when decoding
- See qcbor.h for definition of the object used here: QCBORDecodeNesting
+ See qcbor/qcbor_decode.h for definition of the object
+ used here: QCBORDecodeNesting
===========================================================================*/
inline static int
@@ -390,7 +351,8 @@
/*===========================================================================
QCBORDecode -- The main implementation of CBOR decoding
- See qcbor.h for definition of the object used here: QCBORDecodeContext
+ See qcbor/qcbor_decode.h for definition of the object
+ used here: QCBORDecodeContext
===========================================================================*/
/*
Public function, see header file
@@ -620,7 +582,7 @@
case SINGLE_PREC_FLOAT:
#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
// The caast to uint32_t is safe because the encoded value
- // was 16 bits. It was widened to 64 bits to be passed in here.
+ // was 32 bits. It was widened to 64 bits to be passed in here.
pDecodedItem->val.dfnum = IEEE754_FloatToDouble((uint32_t)uNumber);
#else
pDecodedItem->val.fnum = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
@@ -845,12 +807,16 @@
GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
{
// Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
- QCBORError nReturn;
+
+ // Get pointer to string allocator. First use is to pass it to
+ // GetNext_Item() when option is set to allocate for *every* string.
+ // Second use here is to allocate space to coallese indefinite
+ // length string items into one.
const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
&(me->StringAllocator) :
NULL;
- UsefulBufC FullString = NULLUsefulBufC;
+ QCBORError nReturn;
nReturn = GetNext_Item(&(me->InBuf),
pDecodedItem,
me->bStringAllocateAll ? pAllocator: NULL);
@@ -863,8 +829,8 @@
// indefinite length string tests, to be sure all is OK if this is removed.
// Only do indefinite length processing on strings
- if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING &&
- pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
+ const uint8_t uStringType = pDecodedItem->uDataType;
+ if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
goto Done; // no need to do any work here on non-string types
}
@@ -879,15 +845,14 @@
goto Done;
}
- // There is an indefinite length string to work on...
- // Track which type of string it is
- const uint8_t uStringType = pDecodedItem->uDataType;
-
// Loop getting chunk of indefinite string
+ UsefulBufC FullString = NULLUsefulBufC;
+
for(;;) {
// Get item for next chunk
QCBORItem StringChunkItem;
- // NULL passed to never string alloc chunk of indefinite length strings
+ // NULL string allocator passed here. Do not need to allocate
+ // chunks even if bStringAllocateAll is set.
nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
if(nReturn) {
break; // Error getting the next chunk
@@ -927,12 +892,12 @@
FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
}
-Done:
if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
// Getting the item failed, clean up the allocated memory
StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
}
+Done:
return nReturn;
}
@@ -1062,9 +1027,15 @@
}
} else {
if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
+ if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
+ nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
+ goto Done;
+ }
// Decoding a map as an array
pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
- pDecodedItem->val.uCount *= 2;
+ // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
+ // Cast is needed because of integer promotion
+ pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
}
}
@@ -1074,7 +1045,7 @@
/*
- Public function, see header qcbor.h file
+ Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me,
QCBORItem *pDecodedItem,
@@ -1392,7 +1363,7 @@
/*
- Public function, see header qcbor.h file
+ Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError
QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
@@ -1460,7 +1431,7 @@
/*
- Public function, see header qcbor.h file
+ Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
{
@@ -1512,7 +1483,7 @@
/*
- Public function, see header qcbor.h file
+ Public function, see header qcbor/qcbor_decode.h file
*/
int QCBORDecode_IsTagged(QCBORDecodeContext *me,
const QCBORItem *pItem,
@@ -1533,7 +1504,7 @@
/*
- Public function, see header qcbor.h file
+ Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
{
@@ -1741,7 +1712,7 @@
/*
- Public function, see header qcbor.h file
+ Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
UsefulBuf Pool,
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 7e16595..95cb9fa 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -30,42 +30,8 @@
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
-/*=============================================================================
- FILE: qcbor_encode.c
- DESCRIPTION: This file contains the implementation of QCBOR.
-
- EDIT HISTORY FOR FILE:
-
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
-
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 02/07/2020 llundblade QCBOREncode_EncodeHead() and other for bstr hashing.
- 01/25/2020 llundblade Refine use of integer types to quiet static analysis.
- 01/08/2020 llundblade Documentation corrections & improved code formatting.
- 12/30/19 llundblade Add support for decimal fractions and bigfloats.
- 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
- 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
- 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr.
- 12/30/18 llundblade Small efficient clever encode of type & argument.
- 11/29/18 llundblade Rework to simpler handling of tags and labels.
- 11/9/18 llundblade Error codes are now enums.
- 11/1/18 llundblade Floating support.
- 10/31/18 llundblade Switch to one license that is almost BSD-3.
- 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
- 02/05/18 llundbla Works on CPUs which require integer alignment.
- Requires new version of UsefulBuf.
- 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
- 03/01/17 llundbla More data types
- 11/13/16 llundbla Integrate most TZ changes back into github version.
- 09/30/16 gkanike Porting to TZ.
- 03/15/16 llundbla Initial Version.
-
- =============================================================================*/
-
-#include "qcbor.h"
+#include "qcbor/qcbor_encode.h"
#include "ieee754.h"
@@ -133,7 +99,7 @@
return QCBOR_ERR_ARRAY_TOO_LONG;
}
- pNesting->pCurrentNesting->uCount += 1;
+ pNesting->pCurrentNesting->uCount++;
return QCBOR_SUCCESS;
}
@@ -242,7 +208,7 @@
/*
- Public function for initialization. See header qcbor.h
+ Public function for initialization. See qcbor/qcbor_encode.h
*/
void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
{
@@ -253,7 +219,7 @@
/*
- Public function for initialization. See header qcbor.h
+ Public function to encode a CBOR head. See qcbor/qcbor_encode.h
*/
UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
uint8_t uMajorType,
@@ -275,7 +241,7 @@
The top three bits of the initial byte are the major type for the
CBOR data item. The eight major types defined by the standard are
- defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
+ defined as CBOR_MAJOR_TYPE_xxxx in qcbor/qcbor_common.h.
The remaining five bits, known as "additional information", and
possibly more bytes encode the argument. If the argument is less than
@@ -502,7 +468,7 @@
/*
- Public functions for closing arrays and maps. See qcbor.h
+ Public functions for adding integers. See qcbor/qcbor_encode.h
*/
void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
{
@@ -514,7 +480,7 @@
/*
- Public functions for closing arrays and maps. See qcbor.h
+ Public functions for adding unsigned. See qcbor/qcbor_encode.h
*/
void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
{
@@ -541,7 +507,7 @@
Semi-private function. It is exposed to user of the interface, but
they will usually call one of the inline wrappers rather than this.
- See qcbor.h
+ See qcbor/qcbor_encode.h
Does the work of adding actual strings bytes to the CBOR output (as
opposed to numbers and opening / closing aggregate types).
@@ -581,7 +547,7 @@
/*
- Public functions for closing arrays and maps. See qcbor.h
+ Public functions for adding a tag. See qcbor/qcbor_encode.h
*/
void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
{
@@ -593,7 +559,7 @@
Semi-private function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
- See header qcbor.h
+ See header qcbor/qcbor_encode.h
*/
void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum)
{
@@ -610,7 +576,7 @@
/*
- Public functions for closing arrays and maps. See qcbor.h
+ Public functions for adding a double. See qcbor/qcbor_encode.h
*/
void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
{
@@ -645,7 +611,7 @@
Semi-public function. It is exposed to the user of the interface, but
one of the inline wrappers will usually be called rather than this.
- See qcbor.h
+ See qcbor/qcbor_encode.h
*/
void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
uint64_t uTag,
@@ -682,7 +648,7 @@
Semi-public function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
- See header qcbor.h
+ See qcbor/qcbor_encode.h
*/
void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
{
@@ -723,7 +689,7 @@
Semi-public function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
- See qcbor.h
+ See qcbor/qcbor_encode.h
*/
void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
{
@@ -737,7 +703,7 @@
/*
- Public functions for closing arrays and maps. See qcbor.h
+ Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
*/
void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
{
@@ -746,7 +712,7 @@
/*
- Public functions for closing bstr wrapping. See qcbor.h
+ Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
*/
void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR)
{
@@ -783,7 +749,7 @@
/*
- Public functions for closing arrays and maps. See qcbor.h
+ Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
*/
void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
{
@@ -803,7 +769,7 @@
/*
- Public functions to finish and get the encoded result. See qcbor.h
+ Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
*/
QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
{
@@ -826,7 +792,7 @@
/*
- Public functions to finish and get the encoded result. See qcbor.h
+ Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
*/
QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
{
diff --git a/src/qcbor_err_to_str.c b/src/qcbor_err_to_str.c
new file mode 100644
index 0000000..3f9db0a
--- /dev/null
+++ b/src/qcbor_err_to_str.c
@@ -0,0 +1,48 @@
+/*==============================================================================
+ err_to_str.c -- strings names for errors
+
+ Copyright (c) 2020, Patrick Uiterwijk. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 3/21/20
+ =============================================================================*/
+
+#include "qcbor.h"
+
+#define _ERR_TO_STR(errpart) case QCBOR_##errpart: return "QCBOR_" #errpart;
+
+const char *qcbor_err_to_str(QCBORError err) {
+ switch (err) {
+ _ERR_TO_STR(SUCCESS)
+ _ERR_TO_STR(ERR_BUFFER_TOO_SMALL)
+ _ERR_TO_STR(ERR_ARRAY_NESTING_TOO_DEEP)
+ _ERR_TO_STR(ERR_ARRAY_TOO_LONG)
+ _ERR_TO_STR(ERR_TOO_MANY_CLOSES)
+ _ERR_TO_STR(ERR_UNSUPPORTED)
+ _ERR_TO_STR(ERR_HIT_END)
+ _ERR_TO_STR(ERR_BUFFER_TOO_LARGE)
+ _ERR_TO_STR(ERR_INT_OVERFLOW)
+ _ERR_TO_STR(ERR_MAP_LABEL_TYPE)
+ _ERR_TO_STR(ERR_ARRAY_OR_MAP_STILL_OPEN)
+ _ERR_TO_STR(ERR_DATE_OVERFLOW)
+ _ERR_TO_STR(ERR_BAD_TYPE_7)
+ _ERR_TO_STR(ERR_BAD_OPT_TAG)
+ _ERR_TO_STR(ERR_EXTRA_BYTES)
+ _ERR_TO_STR(ERR_CLOSE_MISMATCH)
+ _ERR_TO_STR(ERR_NO_STRING_ALLOCATOR)
+ _ERR_TO_STR(ERR_INDEFINITE_STRING_CHUNK)
+ _ERR_TO_STR(ERR_STRING_ALLOCATE)
+ _ERR_TO_STR(ERR_BAD_BREAK)
+ _ERR_TO_STR(ERR_TOO_MANY_TAGS)
+ _ERR_TO_STR(ERR_BAD_INT)
+ _ERR_TO_STR(ERR_NO_MORE_ITEMS)
+ _ERR_TO_STR(ERR_BAD_EXP_AND_MANTISSA)
+ _ERR_TO_STR(ERR_STRING_TOO_LONG)
+
+ default:
+ return "Invalid error";
+ }
+}
diff --git a/test/float_tests.c b/test/float_tests.c
index 569e40c..c488b7a 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -13,7 +13,8 @@
#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
#include "float_tests.h"
-#include "qcbor.h"
+#include "qcbor/qcbor_encode.h"
+#include "qcbor/qcbor_decode.h"
#include "half_to_double_from_rfc7049.h"
#include <math.h> // For INFINITY and NAN and isnan()
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index e21971f..9cfbb2d 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -31,7 +31,8 @@
=============================================================================*/
#include "qcbor_decode_tests.h"
-#include "qcbor.h"
+#include "qcbor/qcbor_encode.h"
+#include "qcbor/qcbor_decode.h"
#include <string.h>
#include <math.h> // for fabs()
#include "not_well_formed_cbor.h"
@@ -89,7 +90,7 @@
static int32_t IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
{
- QCBORItem Item;
+ QCBORItem Item;
QCBORError nCBORError;
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
@@ -1205,6 +1206,22 @@
UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
return -17;
}
+
+
+ /*
+ Test with map that nearly QCBOR_MAX_ITEMS_IN_ARRAY items in a
+ map that when interpreted as an array will be too many. Test
+ data just has the start of the map, not all the items in the map.
+ */
+ static const uint8_t pTooLargeMap[] = {0xb9, 0xff, 0xfd};
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pTooLargeMap),
+ QCBOR_DECODE_MODE_MAP_AS_ARRAY);
+
+ if((QCBOR_ERR_ARRAY_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item))) {
+ return -50;
+ }
return 0;
}
@@ -1416,9 +1433,7 @@
-/*
- Public function for initialization. See header qcbor.h
- */
+
int32_t ParseMapTest()
{
// Parse a moderatly complex map structure very thoroughly
@@ -2003,9 +2018,6 @@
}
-/*
- Public function for initialization. See header qcbor.h
- */
int32_t ComprehensiveInputTest()
{
// Size 2 tests 64K inputs and runs quickly
@@ -2017,9 +2029,6 @@
}
-/*
- Public function for initialization. See header qcbor.h
- */
int32_t BigComprehensiveInputTest()
{
// size 3 tests 16 million inputs and runs OK
@@ -2044,7 +2053,7 @@
0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
// CBOR_TAG_B64
- 0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags TODO: fix this test
+ 0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags
0x1a, 0x53, 0x72, 0x4E, 0x01,
0xc1, // tag for epoch date
@@ -2099,7 +2108,7 @@
return -2;
}
- // Epoch date
+ // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -3;
if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
@@ -3783,3 +3792,325 @@
}
#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+int32_t CBORSequenceDecodeTests(void)
+{
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+ QCBORError uCBORError;
+
+ // --- Test a sequence with extra bytes ---
+
+ // The input for the date test happens to be a sequence so it
+ // is reused. It is a sequence because it doesn't start as
+ // an array or map.
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ // Get the first item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 1;
+ }
+ if(Item.uDataType != QCBOR_TYPE_DATE_STRING) {
+ return 2;
+ }
+
+ // Get a second item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 2;
+ }
+ if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH) {
+ return 3;
+ }
+
+ // A sequence can have stuff at the end that may
+ // or may not be valid CBOR. The protocol decoder knows
+ // when to stop by definition of the protocol, not
+ // when the top-level map or array is ended.
+ // Finish still has to be called to know that
+ // maps and arrays (if there were any) were closed
+ // off correctly. When called like this it
+ // must return the error QCBOR_ERR_EXTRA_BYTES.
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_ERR_EXTRA_BYTES) {
+ return 4;
+ }
+
+
+ // --- Test an empty input ----
+ uint8_t empty[1];
+ UsefulBufC Empty = {empty, 0};
+ QCBORDecode_Init(&DCtx,
+ Empty,
+ QCBOR_DECODE_MODE_NORMAL);
+
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 5;
+ }
+
+
+ // --- Sequence with unclosed indefinite length array ---
+ static const uint8_t xx[] = {0x01, 0x9f, 0x02};
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(xx),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ // Get the first item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 7;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return 8;
+ }
+
+ // Get a second item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 9;
+ }
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return 10;
+ }
+
+ // Try to finish before consuming all bytes to confirm
+ // that the still-open error is returned.
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+ return 11;
+ }
+
+
+ // --- Sequence with a closed indefinite length array ---
+ static const uint8_t yy[] = {0x01, 0x9f, 0xff};
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(yy),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ // Get the first item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 12;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return 13;
+ }
+
+ // Get a second item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 14;
+ }
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return 15;
+ }
+
+ // Try to finish before consuming all bytes to confirm
+ // that the still-open error is returned.
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 16;
+ }
+
+
+ return 0;
+}
+
+
+int32_t IntToTests()
+{
+ int nErrCode;
+ int32_t n32;
+ int16_t n16;
+ int8_t n8;
+ uint32_t u32;
+ uint16_t u16;
+ uint8_t u8;
+ uint64_t u64;
+
+ nErrCode = QCBOR_Int64ToInt32(1, &n32);
+ if(nErrCode == -1 || n32 != 1) {
+ return 1;
+ }
+
+ nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MAX, &n32);
+ if(nErrCode == -1 || n32 != INT32_MAX) {
+ return 2;
+ }
+
+ nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MIN, &n32);
+ if(nErrCode == -1 || n32 != INT32_MIN) {
+ return 3;
+ }
+
+ nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MAX)+1, &n32);
+ if(nErrCode != -1) {
+ return 4;
+ }
+
+ nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MIN)-1, &n32);
+ if(nErrCode != -1) {
+ return 5;
+ }
+
+
+ nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MAX, &n16);
+ if(nErrCode == -1 || n16 != INT16_MAX) {
+ return 6;
+ }
+
+ nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MIN, &n16);
+ if(nErrCode == -1 || n16 != INT16_MIN) {
+ return 7;
+ }
+
+ nErrCode = QCBOR_Int64ToInt16(1, &n16);
+ if(nErrCode == -1 || n16 != 1) {
+ return 8;
+ }
+
+ nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MAX)+1, &n16);
+ if(nErrCode != -1) {
+ return 9;
+ }
+
+ nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MIN)-1, &n16);
+ if(nErrCode != -1) {
+ return 10;
+ }
+
+
+ nErrCode = QCBOR_Int64ToInt8(1, &n8);
+ if(nErrCode == -1 || n8 != 1) {
+ return 11;
+ }
+
+ nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MAX, &n8);
+ if(nErrCode == -1 || n8 != INT8_MAX) {
+ return 12;
+ }
+
+ nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MIN, &n8);
+ if(nErrCode == -1 || n8 != INT8_MIN) {
+ return 13;
+ }
+
+ nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MAX)+1, &n8);
+ if(nErrCode != -1) {
+ return 14;
+ }
+
+ nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MIN)-1, &n8);
+ if(nErrCode != -1) {
+ return 15;
+ }
+
+
+ nErrCode = QCBOR_Int64ToUInt32(1, &u32);
+ if(nErrCode == -1 || u32 != 1) {
+ return 16;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt32((int64_t)UINT32_MAX, &u32);
+ if(nErrCode == -1 || u32 != UINT32_MAX) {
+ return 17;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt32((int64_t)0, &u32);
+ if(nErrCode == -1 || u32 != 0) {
+ return 18;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt32(((int64_t)UINT32_MAX)+1, &u32);
+ if(nErrCode != -1) {
+ return 19;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt32((int64_t)-1, &u32);
+ if(nErrCode != -1) {
+ return 20;
+ }
+
+
+ nErrCode = QCBOR_Int64UToInt16((int64_t)UINT16_MAX, &u16);
+ if(nErrCode == -1 || u16 != UINT16_MAX) {
+ return 21;
+ }
+
+ nErrCode = QCBOR_Int64UToInt16((int64_t)0, &u16);
+ if(nErrCode == -1 || u16 != 0) {
+ return 22;
+ }
+
+ nErrCode = QCBOR_Int64UToInt16(1, &u16);
+ if(nErrCode == -1 || u16 != 1) {
+ return 23;
+ }
+
+ nErrCode = QCBOR_Int64UToInt16(((int64_t)UINT16_MAX)+1, &u16);
+ if(nErrCode != -1) {
+ return 24;
+ }
+
+ nErrCode = QCBOR_Int64UToInt16((int64_t)-1, &u16);
+ if(nErrCode != -1) {
+ return 25;
+ }
+
+
+ nErrCode = QCBOR_Int64ToUInt8((int64_t)UINT8_MAX, &u8);
+ if(nErrCode == -1 || u8 != UINT8_MAX) {
+ return 26;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt8((int64_t)0, &u8);
+ if(nErrCode == -1 || u8 != 0) {
+ return 27;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt8(1, &u8);
+ if(nErrCode == -1 || u8 != 1) {
+ return 28;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt8(((int64_t)UINT16_MAX)+1, &u8);
+ if(nErrCode != -1) {
+ return 29;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt8((int64_t)-1, &u8);
+ if(nErrCode != -1) {
+ return 30;
+ }
+
+
+ nErrCode = QCBOR_Int64ToUInt64(1, &u64);
+ if(nErrCode == -1 || u64 != 1) {
+ return 31;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt64(INT64_MAX, &u64);
+ if(nErrCode == -1 || u64 != INT64_MAX) {
+ return 32;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt64((int64_t)0, &u64);
+ if(nErrCode == -1 || u64 != 0) {
+ return 33;
+ }
+
+ nErrCode = QCBOR_Int64ToUInt64((int64_t)-1, &u64);
+ if(nErrCode != -1) {
+ return 34;
+ }
+
+ return 0;
+}
+
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index e87490e..26752e0 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -38,7 +38,8 @@
/*
Notes:
- - All the functions in qcbor.h are called once in the aggregation of all the tests below.
+ - All the functions in qcbor_decode.h are called once in the aggregation
+ of all the tests below.
- All the types that are supported are given as input and parsed by these tests
@@ -251,4 +252,15 @@
#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+/*
+ Tests decoding of CBOR Sequences defined in RFC 8742
+ */
+int32_t CBORSequenceDecodeTests(void);
+
+
+/*
+Tests for functions to safely convert integer types.
+*/
+int32_t IntToTests(void);
+
#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 638a9b9..1e91378 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -30,7 +30,8 @@
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
-#include "qcbor.h"
+#include "qcbor/qcbor_encode.h"
+#include "qcbor/qcbor_decode.h"
#include "qcbor_encode_tests.h"
diff --git a/test/qcbor_encode_tests.h b/test/qcbor_encode_tests.h
index 204bdee..e54168a 100644
--- a/test/qcbor_encode_tests.h
+++ b/test/qcbor_encode_tests.h
@@ -38,7 +38,7 @@
/*
Notes:
- - All the functions in qcbor.h are called once in the aggregation of all
+ - All the functions in qcbor_encode.h are called once in the aggregation of all
the tests below.
- All the types that are supported are given as input and parsed by these tests
@@ -136,7 +136,7 @@
/*
- Calls all public encode methods in qcbor.h once.
+ Calls all public encode methods in qcbor_encode.h once.
*/
int32_t AllAddMethodsTest(void);
diff --git a/test/run_tests.c b/test/run_tests.c
index 78450eb..ef95f7b 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -106,6 +106,8 @@
TEST_ENTRY(SetUpAllocatorTest),
TEST_ENTRY(SimpleValuesIndefiniteLengthTest1),
TEST_ENTRY(EncodeLengthThirtyoneTest),
+ TEST_ENTRY(CBORSequenceDecodeTests),
+ TEST_ENTRY(IntToTests),
#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
TEST_ENTRY(EncodeLengthThirtyoneTest),
TEST_ENTRY(ExponentAndMantissaDecodeTests),
@@ -277,7 +279,10 @@
}
-#include "qcbor.h" // For size printing
+// For size printing
+#include "qcbor/qcbor_encode.h"
+#include "qcbor/qcbor_decode.h"
+
/*
Public function. See run_test.h.