From 9598d29d8a9df26cd921e36dcf790538c4892918 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Wed, 8 Jan 2025 16:04:31 +0000 Subject: [PATCH] Upgrade QCBOR from 1.2 to 1.5 and t_cose from 1.1 to 1.1.3 --- 3rdparty/exported/QCBOR/CMakeLists.txt | 23 +- 3rdparty/exported/QCBOR/Makefile | 2 +- .../QCBOR/QCBOR.xcodeproj/project.pbxproj | 6 +- 3rdparty/exported/QCBOR/README.md | 78 +- 3rdparty/exported/QCBOR/cmd_line_main.c | 4 +- 3rdparty/exported/QCBOR/doc/Tagging.md | 2 + 3rdparty/exported/QCBOR/example.c | 18 +- 3rdparty/exported/QCBOR/example.h | 2 +- 3rdparty/exported/QCBOR/qcbor/UsefulBuf.h | 183 +- 3rdparty/exported/QCBOR/qcbor/qcbor_common.h | 612 +- 3rdparty/exported/QCBOR/qcbor/qcbor_decode.h | 684 +- 3rdparty/exported/QCBOR/qcbor/qcbor_encode.h | 5034 +++--- 3rdparty/exported/QCBOR/qcbor/qcbor_private.h | 450 +- .../QCBOR/qcbor/qcbor_spiffy_decode.h | 3876 +++-- 3rdparty/exported/QCBOR/src/UsefulBuf.c | 367 +- 3rdparty/exported/QCBOR/src/ieee754.c | 914 +- 3rdparty/exported/QCBOR/src/ieee754.h | 219 +- 3rdparty/exported/QCBOR/src/qcbor_decode.c | 4094 +++-- 3rdparty/exported/QCBOR/src/qcbor_encode.c | 759 +- .../exported/QCBOR/src/qcbor_err_to_str.c | 147 +- .../exported/QCBOR/test/UsefulBuf_Tests.c | 275 +- .../exported/QCBOR/test/UsefulBuf_Tests.h | 66 +- 3rdparty/exported/QCBOR/test/float_tests.c | 1170 +- 3rdparty/exported/QCBOR/test/float_tests.h | 33 +- .../QCBOR/test/half_to_double_from_rfc7049.c | 2 +- .../QCBOR/test/half_to_double_from_rfc7049.h | 4 +- .../QCBOR/test/not_well_formed_cbor.h | 9 +- .../exported/QCBOR/test/qcbor_decode_tests.c | 13733 +++++++++------- .../exported/QCBOR/test/qcbor_decode_tests.h | 15 +- .../exported/QCBOR/test/qcbor_encode_tests.c | 385 +- .../exported/QCBOR/test/qcbor_encode_tests.h | 9 +- 3rdparty/exported/QCBOR/test/run_tests.c | 37 +- 3rdparty/exported/QCBOR/test/run_tests.h | 4 +- 3rdparty/exported/QCBOR/ub-example.c | 2 +- 3rdparty/exported/QCBOR/ub-example.h | 2 +- 3rdparty/exported/t_cose/CMakeLists.txt | 2 +- 3rdparty/exported/t_cose/CONTRIBUTING.md | 107 +- 3rdparty/exported/t_cose/Makefile.ossl | 4 +- 3rdparty/exported/t_cose/Makefile.psa | 4 +- 3rdparty/exported/t_cose/Makefile.test | 10 +- 3rdparty/exported/t_cose/README.md | 22 +- .../t_cose/inc/t_cose/t_cose_common.h | 10 +- 3rdparty/exported/t_cose/mainpage.dox | 18 + .../exported/t_cose/src/t_cose_sign1_sign.c | 8 +- .../exported/t_cose/src/t_cose_sign1_verify.c | 7 +- .../t_cose/t_cose.xcodeproj/project.pbxproj | 4 +- cgmanifest.json | 4 +- 47 files changed, 19513 insertions(+), 13907 deletions(-) create mode 100644 3rdparty/exported/t_cose/mainpage.dox diff --git a/3rdparty/exported/QCBOR/CMakeLists.txt b/3rdparty/exported/QCBOR/CMakeLists.txt index 486946ce9e65..1c7e081f9937 100644 --- a/3rdparty/exported/QCBOR/CMakeLists.txt +++ b/3rdparty/exported/QCBOR/CMakeLists.txt @@ -11,7 +11,7 @@ cmake_minimum_required(VERSION 3.15) project(qcbor DESCRIPTION "QCBOR" LANGUAGES C - VERSION 1.1.0 + VERSION 1.5.0 ) set(BUILD_QCBOR_TEST "OFF" CACHE STRING "Build QCBOR test suite [OFF, LIB, APP]") @@ -72,6 +72,27 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU") ) endif() +set(HEADERS + inc/qcbor/qcbor.h + inc/qcbor/qcbor_common.h + inc/qcbor/qcbor_private.h + inc/qcbor/qcbor_encode.h + inc/qcbor/qcbor_decode.h + inc/qcbor/qcbor_spiffy_decode.h + inc/qcbor/UsefulBuf.h +) +set_target_properties( + qcbor PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + PUBLIC_HEADER "${HEADERS}" +) +include(GNUInstallDirs) +install( + TARGETS qcbor + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/qcbor" +) + if (NOT BUILD_QCBOR_TEST STREQUAL "OFF") add_subdirectory(test) endif() diff --git a/3rdparty/exported/QCBOR/Makefile b/3rdparty/exported/QCBOR/Makefile index d5d359b7121c..defcb720d08b 100644 --- a/3rdparty/exported/QCBOR/Makefile +++ b/3rdparty/exported/QCBOR/Makefile @@ -45,7 +45,7 @@ libqcbor.a: $(QCBOR_OBJ) # run "make warn" as a handy way to compile with the warning flags # used in the QCBOR release process. See CFLAGS above. warn: - make CMD_LINE="-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual" + make CMD_LINE="$(CMD_LINE) -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual" # The shared library is not made by default because of platform diff --git a/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj b/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj index c1e6cd710ed0..e43bf040f119 100644 --- a/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj +++ b/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj @@ -150,8 +150,8 @@ 0FA9BEB9216DC7AD00BA646B /* qcbor_encode_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_encode_tests.h; path = test/qcbor_encode_tests.h; sourceTree = ""; }; 0FA9BEBB216DE31700BA646B /* UsefulBuf_Tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf_Tests.h; path = test/UsefulBuf_Tests.h; sourceTree = ""; }; 0FA9BEBC216DE31700BA646B /* UsefulBuf_Tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = UsefulBuf_Tests.c; path = test/UsefulBuf_Tests.c; sourceTree = ""; tabWidth = 3; }; - E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = ""; }; - E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = ""; }; + E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = ""; tabWidth = 3; }; + E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = ""; tabWidth = 3; }; E73B575A2161CA7C0080D658 /* float_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = float_tests.c; path = test/float_tests.c; sourceTree = ""; tabWidth = 3; }; E73B575B2161CA7C0080D658 /* half_to_double_from_rfc7049.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = half_to_double_from_rfc7049.h; path = test/half_to_double_from_rfc7049.h; sourceTree = ""; }; E73B575C2161CA7C0080D658 /* float_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = float_tests.h; path = test/float_tests.h; sourceTree = ""; }; @@ -173,7 +173,7 @@ E776E094214AE09700E67947 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/UsefulBuf.h; sourceTree = ""; tabWidth = 3; }; E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = ""; tabWidth = 3; }; E776E161214EE19C00E67947 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - E7864765252CE63100A0C11B /* qcbor_err_to_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_err_to_str.c; path = src/qcbor_err_to_str.c; sourceTree = ""; }; + E7864765252CE63100A0C11B /* qcbor_err_to_str.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_err_to_str.c; path = src/qcbor_err_to_str.c; sourceTree = ""; tabWidth = 3; }; E78C91DE240C90C100F4CECE /* qcbor_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_decode.h; path = inc/qcbor/qcbor_decode.h; sourceTree = ""; tabWidth = 3; }; E78C91DF240C90C100F4CECE /* qcbor_common.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_common.h; path = inc/qcbor/qcbor_common.h; sourceTree = ""; tabWidth = 3; }; E78C91E0240C90C100F4CECE /* qcbor_private.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_private.h; path = inc/qcbor/qcbor_private.h; sourceTree = ""; tabWidth = 3; }; diff --git a/3rdparty/exported/QCBOR/README.md b/3rdparty/exported/QCBOR/README.md index 673e940e1469..46148806cc65 100644 --- a/3rdparty/exported/QCBOR/README.md +++ b/3rdparty/exported/QCBOR/README.md @@ -1,9 +1,9 @@ ![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true) -**QCBOR** is a powerful, commercial-quality CBOR encoder/decoder that +**QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that implements these RFCs: -* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Everything +* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything except sorting of encoded maps) * [RFC7049](https://tools.ietf.org/html/rfc7049) The previous CBOR standard. Replaced by RFC 8949. @@ -88,9 +88,9 @@ implementations as seen in the following example. /* Encode */ QCBOREncode_Init(&EncodeCtx, Buffer); QCBOREncode_OpenMap(&EncodeCtx); - QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pE->Manufacturer); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pE->uDisplacement); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pE->uHorsePower); + QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pE->Manufacturer); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pE->uDisplacement); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pE->uHorsePower); QCBOREncode_CloseMap(&EncodeCtx); uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedEngine); @@ -168,11 +168,14 @@ QCBOR. ## Code Status -The current version is v1.1, a small feature addition and bug fix -release over QCBOR 1.0. +The official current release is version 1.5 Changes over the last few +years have been only minor bug fixes, minor feature additions and +documentation improvements. QCBOR 1.x is highly stable. -Code has been stable for over a year. The last major change was in -fall of 2020. +Work on some larger feature additions is ongoing in "dev" branch. +This includes more explicit support for preferred serialization and +CDE (CBOR Deterministic Encoding). It will eventually be release as +QCBOR 2.x. QCBOR was originally developed by Qualcomm. It was [open sourced through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a @@ -375,17 +378,21 @@ available options and the associated #defines. ## Code Size These are approximate sizes on a 64-bit x86 CPU with the -Os optimization. +All QCBOR_DISABLE_XXX are set and compiler stack frame checking is disabled +for smallest but not for largest. Smallest is the library functions for a +protocol with strings, integers, arrays, maps and Booleans, but not floats +and standard tag types. | | smallest | largest | |---------------|----------|---------| - | encode only | 900 | 2100 | + | encode only | 850 | 2200 | | decode only | 1550 | 13300 | - | combined | 2450 | 15500 | + | combined | 2500 | 15500 | From the table above, one can see that the amount of code pulled in from the QCBOR library varies a lot, ranging from 1KB to 15KB. The - main factor is in this is the number of QCBOR functions called and - which ones they are. QCBOR is constructed with less internal + main factor is the number of QCBOR functions called and + which ones they are. QCBOR minimizes internal interdependency so only code necessary for the called functions is brought in. @@ -436,6 +443,7 @@ code. The amount saved is an approximation. | QCBOR_DISABLE_PREFERRED_FLOAT | 900 | | QCBOR_DISABLE_FLOAT_HW_USE | 50 | | QCBOR_DISABLE_TAGS | 400 | + | QCBOR_DISABLE_NON_INTEGER_LABELS | 140 | | USEFULBUF_DISABLE_ALL_FLOAT | 950 | QCBOR_DISABLE_ENCODE_USAGE_GUARDS affects encoding only. It doesn't @@ -475,6 +483,12 @@ a single tag, the error is unrecoverable so it is suitable only for protocols th have no tags. "Borrowed" tag content formats (e.g. an epoch-based date without the tag number), can still be processed. +QCBOR_DISABLE_NON_INTEGER_LABELS causes any label that doesn't +fit in an int64_t to result in a QCBOR_ERR_MAP_LABEL_TYPE error. +This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and +QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. It is fairly common for CBOR-based +protocols to use only small integers as labels. + See the discussion above on floating-point. ### Size of spiffy decode @@ -524,44 +538,8 @@ EAT and CWT. * Máté Tóth-Pál for float-point disabling and other * Dave Thaler for portability to Windows -## Copyright and License - -QCBOR is available under what is essentially the 3-Clause BSD License. - -Files created inside Qualcomm and open-sourced through CAF (The Code -Aurora Forum) have a slightly modified 3-Clause BSD License. The -modification additionally disclaims NON-INFRINGEMENT. - -Files created after release to CAF use the standard 3-Clause BSD -License with no modification. These files have the SPDX license -identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. - -### BSD-3-Clause license - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### Copyright for this README -Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. +Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. Copyright (c) 2021-2023, Arm Limited. All rights reserved. diff --git a/3rdparty/exported/QCBOR/cmd_line_main.c b/3rdparty/exported/QCBOR/cmd_line_main.c index 59ceb3a7c7c1..da5d0711cba4 100644 --- a/3rdparty/exported/QCBOR/cmd_line_main.c +++ b/3rdparty/exported/QCBOR/cmd_line_main.c @@ -1,11 +1,11 @@ /*============================================================================== - cmd_line_mainc.c -- Runs tests for QCBOR encoder / decoder + cmd_line_mainc.c -- Runs tests for QCBOR encoder-decoder Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/13/18 =============================================================================*/ diff --git a/3rdparty/exported/QCBOR/doc/Tagging.md b/3rdparty/exported/QCBOR/doc/Tagging.md index 7d6518518ddc..9d9538285596 100644 --- a/3rdparty/exported/QCBOR/doc/Tagging.md +++ b/3rdparty/exported/QCBOR/doc/Tagging.md @@ -1,3 +1,5 @@ +@file Tagging.md + @anchor CBORTags # Types and Tagging in CBOR diff --git a/3rdparty/exported/QCBOR/example.c b/3rdparty/exported/QCBOR/example.c index d580c78f0056..c489ad61e61e 100644 --- a/3rdparty/exported/QCBOR/example.c +++ b/3rdparty/exported/QCBOR/example.c @@ -6,7 +6,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 6/30/2020 ========================================================================== */ @@ -130,7 +130,7 @@ static bool EngineCompare(const CarEngine *pE1, const CarEngine *pE2) * @return The pointer and length of the encoded CBOR or * @ref NULLUsefulBufC on error. * - * This encodes the input structure \c pEngine as a CBOR map of + * This encodes the input structure @c pEngine as a CBOR map of * label-value pairs. An array of float is one of the items in the * map. * @@ -162,14 +162,14 @@ UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer) /* Proceed to output all the items, letting the internal error * tracking do its work */ QCBOREncode_OpenMap(&EncodeCtx); - QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower); + QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pEngine->Manufacturer); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pEngine->uDisplacement); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pEngine->uHorsePower); #ifndef USEFULBUF_DISABLE_ALL_FLOAT - QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion); + QCBOREncode_AddDoubleToMapSZ(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion); #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - QCBOREncode_OpenArrayInMap(&EncodeCtx, "Cylinders"); + QCBOREncode_OpenArrayInMapSZ(&EncodeCtx, "Cylinders"); #ifndef USEFULBUF_DISABLE_ALL_FLOAT for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) { QCBOREncode_AddDouble(&EncodeCtx, @@ -177,7 +177,7 @@ UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer) } #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ QCBOREncode_CloseArray(&EncodeCtx); - QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged); + QCBOREncode_AddBoolToMapSZ(&EncodeCtx, "Turbo", pEngine->bTurboCharged); QCBOREncode_CloseMap(&EncodeCtx); /* Get the pointer and length of the encoded output. If there was diff --git a/3rdparty/exported/QCBOR/example.h b/3rdparty/exported/QCBOR/example.h index b5bcf4bccf26..903b3f505b6c 100644 --- a/3rdparty/exported/QCBOR/example.h +++ b/3rdparty/exported/QCBOR/example.h @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 6/30/20 =============================================================================*/ diff --git a/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h b/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h index aa245070299a..0a6e823c19b7 100644 --- a/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h +++ b/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h @@ -1,34 +1,35 @@ -/*============================================================================ - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. 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. - =============================================================================*/ +/* ========================================================================= + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ /*============================================================================ FILE: UsefulBuf.h @@ -42,6 +43,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. when who what, where, why -------- ---- -------------------------------------------------- + 08/14/2024 llundblade Add UsefulOutBuf_RetrieveOutputStorage(). + 08/13/2024 llundblade Add UsefulInputBuf_RetrieveUndecodedInput(). + 08/08/2024 llundblade Add UsefulOutBuf_SubString(). + 10/05/2024 llundblade Add Xxx_OffsetToPointer. 19/12/2022 llundblade Document that adding empty data is allowed. 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf. 9/21/2021 llundbla Clarify UsefulOutBuf size calculation mode @@ -646,16 +651,27 @@ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind); /** - @brief Convert a pointer to an offset with bounds checking. - - @param[in] UB Pointer to the UsefulInputBuf. - @param[in] p Pointer to convert to offset. - - @return SIZE_MAX if @c p is out of range, the byte offset if not. + * @brief Convert a pointer to an offset with bounds checking. + * + * @param[in] UB A UsefulBuf. + * @param[in] p Pointer to convert to offset. + * + * @return SIZE_MAX if @c p is out of range, the byte offset if not. */ static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p); +/** + * @brief Convert an offset to a pointer with bounds checking. + * + * @param[in] UB A UsefulBuf. + * @param[in] uOffset Offset in @c pUInBuf. + * + * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not. + */ +static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset); + + #ifndef USEFULBUF_DISABLE_DEPRECATED /** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */ #define SZLiteralToUsefulBufC(szString) UsefulBuf_FROM_SZ_LITERAL(szString) @@ -674,7 +690,7 @@ static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC) { UsefulBuf UB; - // See UsefulBuf_Unconst() implementation for comment + /* See UsefulBuf_Unconst() implementation for comment */ UB.ptr = (void *)(uintptr_t)UBC.ptr; UB.len = UBC.len; @@ -1323,8 +1339,8 @@ UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf); * @param[in] uAmount The amount to advance. * * This advances the position in the output buffer - * by \c uAmount. This assumes that the - * caller has written \c uAmount to the pointer obtained + * by @c uAmount. This assumes that the + * caller has written @c uAmount to the pointer obtained * with UsefulOutBuf_GetOutPlace(). * * Warning: this bypasses the buffer safety provided by @@ -1368,6 +1384,35 @@ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf); UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest); +/** + * @beief Return a substring of the output data. + * + * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. + * @param[in] uStart Offset of start of substring. + * @param[in] uLen Length of substring. + * + * This is the same as UsefulOutBuf_OutUBuf(), but returns a + * substring. @c NULLUsefulBufC is returned if the requested substring + * is off the end of the output bytes or if in error state. + */ +UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pUOutBuf, + const size_t uStart, + const size_t uLen); + + +/** + * @brief Retrieve the storage buffer passed in to UsefulOutBuf_Init(). + * + * @param[in] pUOutBuf The encoding context. + * + * @return The output storage buffer passed to UsefulOutBuf_Init(). + * + * This doesn't give any information about how much has been encoded + * or the error state. It just returns the exact @ref UsefulOutBuf given + * to UsefulOutBuf_Init(). + */ +static UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pUOutBuf); + /** @@ -1490,7 +1535,18 @@ static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen); * * @return SIZE_MAX if @c p is out of range, the byte offset if not. */ -static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p); +static size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p); + + +/** + * @brief Convert an offset to a pointer with bounds checking. + * + * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. + * @param[in] uOffset Offset in @c pUInBuf. + * + * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not. + */ +static const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset); /** @@ -1700,6 +1756,16 @@ static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pUInBuf); static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen); +/** + * @brief Retrieve the undecoded input buffer. + * + * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. + * + * @return The input that was given to UsefulInputBuf_Init(). + * + * A simple convenience method, should it be useful to get the original input back. + */ +static UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pUInBuf); /*---------------------------------------------------------- @@ -1844,7 +1910,7 @@ static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p) return SIZE_MAX; } - // Cast to size_t (from ptrdiff_t) is OK because of check above + /* Cast to size_t (from ptrdiff_t) is OK because of check above */ const size_t uOffset = (size_t)((const uint8_t *)p - (const uint8_t *)UB.ptr); if(uOffset >= UB.len) { @@ -1856,6 +1922,18 @@ static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p) } +static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset) +{ + if(UsefulBuf_IsNULLC(UB) || uOffset >= UB.len) { + return NULL; + } + + return (const uint8_t *)UB.ptr + uOffset; +} + + + + #ifndef USEFULBUF_DISABLE_ALL_FLOAT static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f) { @@ -2192,6 +2270,12 @@ static inline UsefulBuf UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf) } +static inline UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pMe) +{ + return pMe->UB; +} + + static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB) @@ -2237,9 +2321,9 @@ static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe) /* 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 + * If it is 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. + * corrupted by an attacker or accidentally. */ if(pMe->cursor > pMe->UB.len) { return 0; @@ -2262,6 +2346,12 @@ static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, con } +static inline const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset) + { + return UsefulBuf_OffsetToPointer(pUInBuf->UB, uOffset); + } + + static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum) { const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum); @@ -2454,6 +2544,11 @@ static inline void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pMe, size_t uN pMe->UB.len = uNewLen; } +static inline UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pMe) +{ + return pMe->UB; +} + #ifdef __cplusplus } diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_common.h b/3rdparty/exported/QCBOR/qcbor/qcbor_common.h index 127537d85322..0027cf9554dc 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_common.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_common.h @@ -1,110 +1,99 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - =============================================================================*/ - - +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * 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 +#ifdef __cplusplus +extern "C" { +#if 0 +} // Keep editor indention formatting happy +#endif +#endif + /** - @file qcbor_common.h - - Types and defines common to QCBOR encoding and decoding. -*/ + * @file qcbor_common.h + * + * Constant values for types, error codes and such that are common to + * encoding and decoding. + */ /** - * This define indicates QCBOR v1.1. - * - * There are no backwards compatibiliy issues with QCBOR 1.0. + * Semantic versioning for QCBOR x.y.z from 1.3.0 on * - * The only new API is QCBOREncode_OpenBytes() and related. + * Note: + * - QCBOR 1.2 is indicated by the #define QCBOR_1_2 + * - QCBOR 1.1 is indicated by the #define QCBOR_1_1 + * - QCBOR 1.0 is indicated by the absence of all the above */ -#define QCBOR_1_1 +#define QCBOR_VERSION_MAJOR 1 +#define QCBOR_VERSION_MINOR 5 +#define QCBOR_VERSION_PATCH 0 /** - This define indicates a version of QCBOR that supports spiffy decode, - the decode functions found in qcbor_spiffy_decode.h. - - Versions of QCBOR that support spiffy decode are backwards compatible - with previous versions, but there are a few minor exceptions such as - some aspects of tag handling that are different. This define can be - used handle these variances. -*/ + * This define indicates a version of QCBOR that supports spiffy + * decode, the decode functions found in qcbor_spiffy_decode.h. + * + * Versions of QCBOR that support spiffy decode are backwards + * compatible with previous versions, but there are a few minor + * exceptions such as some aspects of tag handling that are + * different. This define can be used to handle these variances. + */ #define QCBOR_SPIFFY_DECODE -/* It was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, - * but this is incosistent with all the other QCBOR_DISABLE_ - * #defines, so the name was changed and this was added for backwards - * compatibility - */ -#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA -#define QCBOR_DISABLE_EXP_AND_MANTISSA -#endif -/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define - * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT - */ -#ifdef USEFULBUF_DISABLE_ALL_FLOAT -#ifndef QCBOR_DISABLE_FLOAT_HW_USE -#define QCBOR_DISABLE_FLOAT_HW_USE -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT -#define QCBOR_DISABLE_PREFERRED_FLOAT -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - -/* Standard CBOR Major type for positive integers of various lengths */ +/* 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 */ +/* 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 */ + * 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 */ +/* 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. */ + * 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 major type for a tag number. This creates a CBOR "tag" that @@ -117,142 +106,121 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CBOR_MAJOR_TYPE_TAG 6 #define CBOR_MAJOR_TYPE_OPTIONAL 6 -/* Standard CBOR extra simple types like floats and the values true and false */ +/* Standard CBOR simple types like float, the values true, false, null... */ #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. + * Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These + * are types defined in RFC 8949 and some additional ones + * in the IANA CBOR tags registry. */ -#define CBOR_TWENTY_FOUR 24 - - -/* - Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These - are types defined in RFC 8949 and some additional ones - in the IANA CBOR tags registry. - */ -/** See QCBOREncode_AddDateString(). */ +/** See QCBOREncode_AddTDateString(). */ #define CBOR_TAG_DATE_STRING 0 -/** See QCBOREncode_AddDateEpoch(). */ +/** See QCBOREncode_AddTDateEpoch(). */ #define CBOR_TAG_DATE_EPOCH 1 -/** See QCBOREncode_AddPositiveBignum(). */ +/** See QCBOREncode_AddTPositiveBignum(). */ #define CBOR_TAG_POS_BIGNUM 2 -/** See QCBOREncode_AddNegativeBignum(). */ +/** See QCBOREncode_AddTNegativeBignum(). */ #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. - */ + * mantissa and base-10 scaling factor. See + * QCBOREncode_AddTDecimalFraction() 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. */ + * mantissa and base-2 scaling factor. See QCBOREncode_AddTBigFloat() + * and @ref expAndMantissa. */ #define CBOR_TAG_BIGFLOAT 5 -/** Not Decoded by QCBOR. 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. */ +/** Not Decoded by QCBOR. Tag for COSE format encryption with no + * recipient identification. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided + * for this tag. */ #define CBOR_TAG_COSE_ENCRYPT0 16 #define CBOR_TAG_COSE_ENCRYPTO 16 -/** Not Decoded by QCBOR. 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.*/ +/** Not Decoded by QCBOR. Tag for COSE format MAC'd data with no + * recipient identification. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). 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). */ + * for this tag. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). */ #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(). */ + * 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(). */ + * 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(). */ + * format per [RFC 4648] + * (https://www.rfc-editor.org/rfc/rfc4648.html) when converting to + * JSON or similar text-based representations. Essentially, Base-16 + * encoding is the standard case- insensitive hex encoding and may be + * referred to as "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) + * before the call to QCBOREncode_AddBytes(). */ #define CBOR_TAG_ENC_AS_B16 23 /** See QCBORDecode_EnterBstrWrapped()). */ #define CBOR_TAG_CBOR 24 -/** See QCBOREncode_AddURI(). */ +/** See QCBOREncode_AddTURI(). */ #define CBOR_TAG_URI 32 -/** See QCBOREncode_AddB64URLText(). */ +/** See QCBOREncode_AddTB64URLText(). */ #define CBOR_TAG_B64URL 33 /** See QCBOREncode_AddB64Text(). */ #define CBOR_TAG_B64 34 -/** See QCBOREncode_AddRegex(). */ +/** See QCBOREncode_AddTRegex(). */ #define CBOR_TAG_REGEX 35 /** See QCBOREncode_AddMIMEData(). */ #define CBOR_TAG_MIME 36 -/** See QCBOREncode_AddBinaryUUID(). */ +/** See QCBOREncode_AddTBinaryUUID(). */ #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. */ + * (https://www.rfc-editor.org/rfc/rfc8392.html). 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. */ +/** Tag for COSE format encryption. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this + * tag. */ #define CBOR_TAG_CBOR_SEQUENCE 63 -/** Not Decoded by QCBOR. Tag for COSE format encryption with recipient - identification. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this - tag. */ +/** Not Decoded by QCBOR. Tag for COSE format encrypt. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this + * tag. */ #define CBOR_TAG_COSE_ENCRYPT 96 #define CBOR_TAG_ENCRYPT 96 -/** Not Decoded by QCBOR. Tag for COSE format MAC. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this +/** Not Decoded by QCBOR. Tag for COSE format MAC. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this tag. */ #define CBOR_TAG_COSE_MAC 97 #define CBOR_TAG_MAC 97 -/** Not Decoded by QCBOR. Tag for COSE format signed data. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this +/** Not Decoded by QCBOR. Tag for COSE format signed data. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this tag. */ #define CBOR_TAG_COSE_SIGN 98 #define CBOR_TAG_SIGN 98 /** Tag for date counted by days from Jan 1 1970 per [RFC 8943] - (https://tools.ietf.org/html/rfc8943). See - QCBOREncode_AddTDaysEpoch(). */ + * (https://www.rfc-editor.org/rfc/rfc8943.html). See + * QCBOREncode_AddTDaysEpoch(). */ #define CBOR_TAG_DAYS_EPOCH 100 /** Not Decoded by QCBOR. World geographic coordinates. See ISO 6709, [RFC 5870] - (https://tools.ietf.org/html/rfc5870) and WGS-84. No API is - provided for this tag. */ + * (https://www.rfc-editor.org/rfc/rfc5870.html) and WGS-84. No API is + * provided for this tag. */ #define CBOR_TAG_GEO_COORD 103 /** Binary MIME.*/ #define CBOR_TAG_BINARY_MIME 257 /** Tag for date string without time or time zone per [RFC 8943] - (https://tools.ietf.org/html/rfc8943). See - QCBOREncode_AddTDaysString(). */ + * (https://www.rfc-editor.org/rfc/rfc8943.html). See + * QCBOREncode_AddTDaysString(). */ #define CBOR_TAG_DAYS_STRING 1004 /** The magic number, self-described CBOR. No API is provided for this - tag. */ + * tag. */ #define CBOR_TAG_CBOR_MAGIC 55799 /** The 16-bit invalid tag from the CBOR tags registry */ @@ -264,28 +232,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -/* - 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. + * Error codes returned by QCBOR Encoder-Decoder. * - * The errors are grouped to keep the code size of + * They are grouped to keep the code size of * QCBORDecode_IsNotWellFormedError() and * QCBORDecode_IsUnrecoverableError() minimal. * @@ -299,307 +250,338 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * added for new QCBOR features. */ typedef enum { - /** The encode or decode completely correctly. */ + /** The encode or decode completed correctly. */ QCBOR_SUCCESS = 0, /** The buffer provided for the encoded output when doing encoding - was too small and the encoded output will not fit. */ + * was too small and the encoded output will not fit. */ QCBOR_ERR_BUFFER_TOO_SMALL = 1, /** During encoding, an attempt to create simple value between 24 - and 31. */ + * and 31. */ QCBOR_ERR_ENCODE_UNSUPPORTED = 2, /** During encoding, the length of the encoded CBOR exceeded - QCBOR_MAX_ARRAY_OFFSET, which is slightly less than - @c UINT32_MAX. */ + * @ref QCBOR_MAX_ARRAY_OFFSET, which is slightly less than + * @c UINT32_MAX. */ QCBOR_ERR_BUFFER_TOO_LARGE = 3, /** During encoding, 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. */ + * implementation can handle. Note that in the interest of code + * size and memory use, QCBOR 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 = 4, - /** During encoding, @c QCBOREncode_CloseXxx() called with a - different type than is currently open. */ + /** During encoding, @c QCBOREncode_CloseXxx() called for a + * different type than is currently open. */ QCBOR_ERR_CLOSE_MISMATCH = 5, - /** During encoding, the array or map had too many items in it. - This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,535. */ + /** During encoding, the array or map had too many items in it. The + * limits are @ref QCBOR_MAX_ITEMS_IN_ARRAY and + * @ref QCBOR_MAX_ITEMS_IN_MAP. */ QCBOR_ERR_ARRAY_TOO_LONG = 6, /** During encoding, more arrays or maps were closed than - opened. This is a coding error on the part of the caller of the - encoder. */ + * opened. This is a coding error on the part of the caller of the + * encoder. */ QCBOR_ERR_TOO_MANY_CLOSES = 7, - /** During encoding the number of array or map opens was not - matched by the number of closes. Also occurs with opened - byte strings that are not closed. */ + /** During encoding, the number of array or map opens was not + * matched by the number of closes. Also occurs with opened byte + * strings that are not closed. */ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 8, - /** During encode, opening a byte string while a byte string is open - is not allowed. . */ + /** During encoding, opening a byte string while a byte string is + * open is not allowed. */ QCBOR_ERR_OPEN_BYTE_STRING = 9, /** Trying to cancel a byte string wrapping after items have been - added to it. */ + * added to it. */ QCBOR_ERR_CANNOT_CANCEL = 10, #define QCBOR_START_OF_NOT_WELL_FORMED_ERRORS 20 /** During decoding, the CBOR is not well-formed because a simple - value between 0 and 31 is encoded in a two-byte integer rather - than one. */ + * value between 0 and 31 is encoded in a two-byte integer rather + * than one. */ QCBOR_ERR_BAD_TYPE_7 = 20, /** During decoding, returned by QCBORDecode_Finish() if all the - inputs bytes have not been consumed. This is considered not - well-formed. */ + * inputs bytes have not been consumed. This is considered not + * well-formed. */ QCBOR_ERR_EXTRA_BYTES = 21, /** During decoding, some CBOR construct was encountered that this - decoder doesn't support, primarily this is the reserved - additional info values, 28 through 30. The CBOR is not - well-formed.*/ + * decoder doesn't support, primarily this is the reserved + * additional info values, 28 through 30. The CBOR is not + * well-formed. + */ QCBOR_ERR_UNSUPPORTED = 22, /** During decoding, the an array or map was not fully consumed. - Returned by QCBORDecode_Finish(). The CBOR is not - well-formed. */ + * Returned by QCBORDecode_Finish(). The CBOR is not + * well-formed. */ QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED = 23, /** During decoding, an integer type is encoded with a bad length - (that of an indefinite length string). The CBOR is not-well - formed. */ + * (that of an indefinite length string). The CBOR is not-well + * formed. */ QCBOR_ERR_BAD_INT = 24, #define QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS 30 /** During decoding, one of the chunks in an indefinite-length - string is not of the type of the start of the string. The CBOR - is not well-formed. This error makes no further decoding - possible. */ + * string is not of the type of the start of the string. The CBOR + * is not well-formed. This error makes no further decoding + * possible. */ QCBOR_ERR_INDEFINITE_STRING_CHUNK = 30, /** 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. The CBOR is not well-formed. This - error makes no further decoding possible. */ + * 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. The CBOR is not well-formed. + * This error makes no further decoding possible. */ QCBOR_ERR_HIT_END = 31, /** During decoding, a break occurred outside an indefinite-length - item. The CBOR is not well-formed. This error makes no further - decoding possible. */ + * item. The CBOR is not well-formed. This error makes no further + * decoding possible. */ QCBOR_ERR_BAD_BREAK = 32, #define QCBOR_END_OF_NOT_WELL_FORMED_ERRORS 39 /** During decoding, the input is too large. It is greater than - QCBOR_MAX_DECODE_INPUT_SIZE. This is an implementation limit. - This error makes no further decoding possible. */ + * QCBOR_MAX_DECODE_INPUT_SIZE. This is an implementation limit. + * This error makes no further decoding possible. */ QCBOR_ERR_INPUT_TOO_LARGE = 40, /** During 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. This error makes no further decoding - possible. */ + * implementation can handle. Note that in the interest of code + * size and memory use, QCBOR has a hard limit on array + * nesting. The limit is defined as the constant + * @ref QCBOR_MAX_ARRAY_NESTING. This error makes no further + * decoding possible. */ QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP = 41, /** During decoding, the array or map had too many items in it. - This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,534, - UINT16_MAX - 1. This error makes no further decoding - possible. */ + * This limit is @ref QCBOR_MAX_ITEMS_IN_ARRAY (65,534) for + * arrays and @ref QCBOR_MAX_ITEMS_IN_MAP (32,767) for maps. This + * error makes no further decoding possible. */ QCBOR_ERR_ARRAY_DECODE_TOO_LONG = 42, /** When decoding, a string's size is greater than what a size_t - can hold less 4. 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). This - error makes no further decoding possible. */ + * can hold less 4. 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). This + * error makes no further decoding possible. */ QCBOR_ERR_STRING_TOO_LONG = 43, /** Something is wrong with a decimal fraction or bigfloat such as - it not consisting of an array with two integers. This error - makes no further decoding possible. */ + * it not consisting of an array with two integers. This error + * makes no further decoding possible. */ QCBOR_ERR_BAD_EXP_AND_MANTISSA = 44, /** Unable to decode an indefinite-length string because no string - allocator was configured. See QCBORDecode_SetMemPool() or - QCBORDecode_SetUpAllocator(). This error makes no further - decoding possible. */ + * allocator was configured. See QCBORDecode_SetMemPool() or + * QCBORDecode_SetUpAllocator(). This error makes no further + * decoding possible.*/ QCBOR_ERR_NO_STRING_ALLOCATOR = 45, - /** Error allocating space for a string, usually for an - indefinite-length string. This error makes no further decoding - possible. */ + /** Error allocating memory for a string, usually out of memory. + * This primarily occurs decoding indefinite-length strings. This + * error makes no further decoding possible. */ QCBOR_ERR_STRING_ALLOCATE = 46, /** During decoding, the type of the label for a map entry is not - one that can be handled in the current decoding mode. Typically - this is because a label is not an intger or a string. This is - an implemation limit. */ + * one that can be handled in the current decoding mode. Typically + * this is because a label is not an integer or a string. This is + * an implementation limit. */ QCBOR_ERR_MAP_LABEL_TYPE = 47, /** When the built-in tag decoding encounters an unexpected type, - this error is returned. This error is unrecoverable because the - built-in tag decoding doesn't try to consume the unexpected - type. In previous versions of QCBOR this was considered a - recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going back - further, RFC 7049 use the name "optional tags". That name is no - longer used because "optional" was causing confusion. See - also @ref QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT. */ + * this error is returned. This error is unrecoverable because the + * built-in tag decoding doesn't try to consume the unexpected + * type. In previous versions of QCBOR this was considered a + * recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going + * back further, RFC 7049 use the name "optional tags". That name + * is no longer used because "optional" was causing confusion. */ QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT = 48, QCBOR_ERR_BAD_TAG_CONTENT = 48, QCBOR_ERR_BAD_OPT_TAG = 48, /** Indefinite length string handling is disabled and there is an - indefinite length string in the input CBOR. */ + * indefinite length string in the input CBOR. */ QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED = 49, - /** Indefinite length arrays and maps handling are disabled and there is an - indefinite length map or array in the input CBOR. */ + /** Indefinite length arrays and maps handling are disabled and + * there is an indefinite length map or array in the input + * CBOR. */ QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED = 50, /** All decoding of tags (major type 6) has been disabled and a tag - occurred in the decode input. */ + * occurred in the decode input. */ QCBOR_ERR_TAGS_DISABLED = 51, #define QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS 59 /** More than @ref QCBOR_MAX_TAGS_PER_ITEM tags encountered for a - CBOR ITEM. @ref QCBOR_MAX_TAGS_PER_ITEM is a limit of this - implementation. During decoding, too many tags in the - caller-configured tag list, or not enough space in @ref - QCBORTagListOut. This error makes no further decoding - possible. */ + * CBOR ITEM. @ref QCBOR_MAX_TAGS_PER_ITEM is a limit of this + * implementation. During decoding, too many tags in the + * caller-configured tag list, or not enough space in + * @ref QCBORTagListOut. This error makes no further decoding + * possible. */ QCBOR_ERR_TOO_MANY_TAGS = 60, - /** When decoding for a specific type, the type was not was - expected. */ + /** When decoding for a specific type, the type was not expected. */ QCBOR_ERR_UNEXPECTED_TYPE = 61, - /** Duplicate label in map detected. */ + /** Duplicate label detected in a map. */ QCBOR_ERR_DUPLICATE_LABEL = 62, /** During decoding, the buffer given to QCBORDecode_SetMemPool() - is either too small, smaller than - QCBOR_DECODE_MIN_MEM_POOL_SIZE or too large, larger than - UINT32_MAX. */ + * is either too small, smaller than + * @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE or too large, larger than + * UINT32_MAX. */ QCBOR_ERR_MEM_POOL_SIZE = 63, /** During decoding, an integer smaller than INT64_MIN was received - (CBOR can represent integers smaller than INT64_MIN, but C - cannot). */ + * (CBOR can represent integers smaller than INT64_MIN, but C + * cannot). */ QCBOR_ERR_INT_OVERFLOW = 64, /** During decoding, a date greater than +- 292 billion years from - Jan 1 1970 encountered during parsing. This is an - implementation limit. */ + * Jan 1 1970 encountered during parsing. This is an + * implementation limit. */ QCBOR_ERR_DATE_OVERFLOW = 65, /** During decoding, @c QCBORDecode_ExitXxx() was called for a - different type than @c QCBORDecode_EnterXxx(). */ + * different type than @c QCBORDecode_EnterXxx(). */ QCBOR_ERR_EXIT_MISMATCH = 66, /** 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 not parsing a CBOR stream / sequence, this - probably indicates that some data items expected are not - present. See also @ref QCBOR_ERR_HIT_END. */ + * more. If parsing a CBOR stream this indicates the non-error end + * of the stream. If not 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 = 67, /** When finding an item by label, an item with the requested label - was not found. */ + * was not found. */ QCBOR_ERR_LABEL_NOT_FOUND = 68, /** Number conversion failed because of sign. For example a - negative int64_t can't be converted to a uint64_t */ + * negative int64_t can't be converted to a uint64_t */ QCBOR_ERR_NUMBER_SIGN_CONVERSION = 69, - /** When converting a decoded number, the value is too large or to - small for the conversion target */ + /** When converting a decoded number, the value is too large or too + * small for the conversion target. */ QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW = 70, /** Trying to get an item by label when a map has not been - entered. */ + * entered. */ QCBOR_ERR_MAP_NOT_ENTERED = 71, - /** A @ref QCBORItemCallback callback indicates processing should not - continue for some non-CBOR reason. */ + /** A callback indicates processing should not continue for some + * non-CBOR reason. */ QCBOR_ERR_CALLBACK_FAIL = 72, /** This error code is deprecated. Instead, - @ref QCBOR_ERR_HALF_PRECISION_DISABLED, - @ref QCBOR_ERR_HW_FLOAT_DISABLED or @ref QCBOR_ERR_ALL_FLOAT_DISABLED - is returned depending on the specific floating-point functionality - that is disabled and the type of floating-point input. */ + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED, + * @ref QCBOR_ERR_HW_FLOAT_DISABLED or @ref QCBOR_ERR_ALL_FLOAT_DISABLED + * is returned depending on the specific floating-point functionality + * that is disabled and the type of floating-point input. */ QCBOR_ERR_FLOAT_DATE_DISABLED = 73, /** Support for half-precision float decoding is disabled. */ QCBOR_ERR_HALF_PRECISION_DISABLED = 74, /** Use of floating-point HW is disabled. This affects all type - conversions to and from double and float types. */ + * conversions to and from double and float types. */ QCBOR_ERR_HW_FLOAT_DISABLED = 75, /** Unable to complete operation because a floating-point value - that is a NaN (not a number), that is too large, too small, - infinity or -infinity was encountered in encoded CBOR. Usually - this because conversion of the float-point value was being - attempted. */ + * that is a NaN (not a number), that is too large, too small, + * infinity or -infinity was encountered in encoded CBOR. Usually + * this because conversion of the float-point value was being + * attempted. */ QCBOR_ERR_FLOAT_EXCEPTION = 76, - /** Floating point support is completely turned off, encoding/decoding - floating point numbers is not possible. */ + /** Floating point support is completely turned off, + * encoding/decoding floating point numbers is not possible. */ QCBOR_ERR_ALL_FLOAT_DISABLED = 77, /** Like @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT, but recoverable. - If an implementation decodes a tag and can and does consume the - whole tag contents when it is not the correct tag content, this - error can be returned. None of the built-in tag decoders do - this (to save object code). */ - QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78 + * If an implementation decodes a tag and can and does consume the + * whole tag contents when it is not the correct tag content, this + * error can be returned. None of the built-in tag decoders do this + * (to save object code). */ + QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78, - /* This is stored in uint8_t; never add values > 255 */ -} QCBORError; + /** QCBORDecode_EnterBstrWrapped() cannot be used on + * indefinite-length strings because they exist in memory pool for + * a @ref QCBORStringAllocate. */ + QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 79, + /** A range of error codes that can be made use of by the + * caller. QCBOR internally does nothing with these except notice + * that they are not QCBOR_SUCCESS. See QCBORDecode_SetError(). */ + QCBOR_ERR_FIRST_USER_DEFINED = 128, -/* Function for getting an error string from an error code */ -const char *qcbor_err_to_str(QCBORError err); + /** See @ref QCBOR_ERR_FIRST_USER_DEFINED */ + QCBOR_ERR_LAST_USER_DEFINED = 255 + /* This is stored in uint8_t; never add values > 255 */ +} QCBORError; /** - 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 or QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP on decoding if it is exceeded. + * @brief Get string describing an error code. + * + * @param[in] uErr The error code. + * + * @return NULL-terminated string describing error or "Unidentified + * error" if the error is not known. + * + * This is not thread-safe because it uses a static buffer + * for formatting, but this is only a diagnostic and the only + * consequence is the wrong description. */ -#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1 +const char * +qcbor_err_to_str(QCBORError uErr); + + /** - * The maximum number of items in a single array or map when encoding of decoding. + * 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 or @ref QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP on + * decoding if it is exceeded. Do not increase this over 255. */ -/* -1 because the value UINT16_MAX is used to track indefinite-length arrays */ -#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) +#define QCBOR_MAX_ARRAY_NESTING 15 /** - This is deprecated. See QCBORDecode_GetNthTag() and QCBORDecode_GetNthTagOfLast() - for tag handling. - - The maximum number of tags that can be in @ref QCBORTagListIn and passed to - QCBORDecode_SetCallerConfiguredTagList() + * The maximum number of items in a single array when encoding or + * decoding. See also @ref QCBOR_MAX_ITEMS_IN_MAP. + */ +#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) /* -1 is because the + * value UINT16_MAX is + * used to indicate + * indefinite-length. + */ +/** + * The maximum number of items in a single map when encoding or + * decoding. See also @ref QCBOR_MAX_ITEMS_IN_ARRAY. */ -#define QCBOR_MAX_CUSTOM_TAGS 16 +#define QCBOR_MAX_ITEMS_IN_MAP (QCBOR_MAX_ITEMS_IN_ARRAY/2) +#ifdef __cplusplus +} +#endif + #endif /* qcbor_common_h */ diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h b/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h index bf30e6ded32d..8c7a44c2f4ac 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - =============================================================================*/ +/* =========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * 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 @@ -56,7 +56,7 @@ extern "C" { * # QCBOR Basic Decode * * This section discusses decoding assuming familiarity with the - * general description of this encoder / decoder in section @ref + * general description of this encoder-decoder in section @ref * Overview. * * Encoded CBOR has a tree structure where the leaf nodes are @@ -64,9 +64,9 @@ extern "C" { * nodes are either arrays or maps. Fundamentally, CBOR decoding is a * pre-order traversal of this tree with CBOR sequences a minor * exception. Calling QCBORDecode_GetNext() repeatedly will perform - * this. It is possible to decode any CBOR by only calling - * QCBORDecode_GetNext(), though this doesn't take advantage of many - * QCBOR features. + * this. QCBOR maintains an internal traversal cursor. It is possible + * to decode any CBOR by only calling QCBORDecode_GetNext(), though + * this doesn't take advantage of many QCBOR features. * * QCBORDecode_GetNext() returns a 56 byte structure called * @ref QCBORItem that describes the decoded item including: @@ -121,8 +121,11 @@ extern "C" { * call QCBORDecode_GetError() to know the earlier items were * successfully decoded before examining their value or type. * - * The internal decode error state is reset only by re initializing the - * decoder or calling QCBORDecode_GetErrorAndReset(). + * The internal decode error state can be reset by reinitializing the + * decoder or calling QCBORDecode_GetErrorAndReset(). Code calling + * QCBOR may take advantage of the internal error state to halt + * futher decoding and propagate errors it detects using + * QCBORDecode_SetError(). * * It is only useful to reset the error state by calling * QCBORDecode_GetErrorAndReset() on recoverable errors. Examples of @@ -175,7 +178,7 @@ extern "C" { * Decode functions like QCBORDecode_GetEpochDate() and * QCBORDecode_GetDecimalFraction() that can decode the tag content * even if the tag number is absent are still available. Typically - * they won't be linked in because of dead stripping. The + * they won't be linked in because of dead stripping. The * @c uTagRequirement parameter has no effect, but if it is * @ref QCBOR_TAG_REQUIREMENT_TAG, @ref QCBOR_ERR_TAGS_DISABLED * will be set. @@ -195,8 +198,8 @@ typedef enum { } QCBORDecodeMode; /** - * The maximum size of input to the decoder. Slightly less than UINT32_MAX - * to make room for some special indicator values. + * The maximum size of input to the decoder. Slightly less than + * @c UINT32_MAX to make room for some special indicator values. */ #define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2) @@ -211,134 +214,156 @@ typedef enum { /* Do not renumber these. Code depends on some of these values. */ /** The data type is unknown, unset or invalid. */ #define QCBOR_TYPE_NONE 0 + /** Never used in QCBORItem. Used by functions that match QCBOR types. */ #define QCBOR_TYPE_ANY 1 /** Type for an integer that decoded either between @c INT64_MIN and - @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member - @c val.int64. */ + * @c 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. */ + * @c UINT64_MAX. Data is in member @c val.uint64. */ #define QCBOR_TYPE_UINT64 3 + /** Type for an array. See comments on @c val.uCount. */ #define QCBOR_TYPE_ARRAY 4 + /** Type for a map. See comments on @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. See - QCBOREncode_AddText() for a discussion of line endings in CBOR. Data - is in @c val.string. */ + * QCBOREncode_AddText() for a discussion of line endings in CBOR. 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. */ + * 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. */ + * 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.string . Note this - was previously in @c val.dateString, however this is the same as - val.string being the same type in same union. */ + * string, possibly with time zone. Data is in @c val.string . Note this + * was previously in @c val.dateString, however this is the same as + * val.string being the same type in same union. val.dateString will + * be deprecated.. */ #define QCBOR_TYPE_DATE_STRING 11 + /** Type for integer seconds since Jan 1970 + floating-point - fraction. Data is in @c val.epochDate */ + * 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. */ + +/** The CBOR major type "simple" has a small integer value indicating + * what it is. The standard CBOR simples are true, false, null, undef + * (values 20-23) and float-point numbers (values 25-27). The values + * 0-19 and 32-255 are unassigned and may be used if registered with + * in the IANA Simple Values Registry. If these unassigned simple + * values occur in the input they will be decoded as this. The value + * 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(). */ + * See @ref expAndMantissa and QCBOREncode_AddTDecimalFraction(). */ #define QCBOR_TYPE_DECIMAL_FRACTION 14 /** A decimal fraction made of decimal exponent and positive big - number mantissa. See @ref expAndMantissa and - QCBOREncode_AddDecimalFractionBigNum(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTDecimalFractionBigNum(). */ #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(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTDecimalFractionBigNum(). */ #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(). */ + * mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTBigFloat(). */ #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(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTBigFloatBigNum(). */ #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(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTBigFloatBigNum(). */ #define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19 -/** Type for the value false. */ +/** Type for the simple value false. */ #define QCBOR_TYPE_FALSE 20 -/** Type for the value true. */ + +/** Type for the simple value true. */ #define QCBOR_TYPE_TRUE 21 -/** Type for the value null. */ + +/** Type for the simple value null. */ #define QCBOR_TYPE_NULL 22 -/** Type for the value undef. */ + +/** Type for the simple value undef. */ #define QCBOR_TYPE_UNDEF 23 -/** Type for a floating-point number. Data is in @c val.float. */ + +/** Type for a floating-point number. Data is in @c val.fnum. */ #define QCBOR_TYPE_FLOAT 26 -/** Type for a double floating-point number. Data is in @c val.double. */ + +/** Type for a double floating-point number. Data is in @c val.dfnum. */ #define QCBOR_TYPE_DOUBLE 27 #define QCBOR_TYPE_BREAK 31 /* Used internally; never returned */ /** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is - being traversed as an array. See QCBORDecode_Init() */ + * being traversed as an array. See QCBORDecode_Init() */ #define QCBOR_TYPE_MAP_AS_ARRAY 32 /** Encoded CBOR that is wrapped in a byte string. Often used when the - CBOR is to be hashed for signing or HMAC. See also @ref - QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE. Data is in @c val.string. */ + * CBOR is to be hashed for signing or HMAC. See also @ref + * QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE. Data is in @c val.string. */ #define QBCOR_TYPE_WRAPPED_CBOR 36 /** A URI as defined in RFC 3986. Data is in @c val.string. */ #define QCBOR_TYPE_URI 44 /** Text is base64 URL encoded in RFC 4648. The base64 encoding is - NOT removed. Data is in @c val.string. */ + * NOT removed. Data is in @c val.string. */ #define QCBOR_TYPE_BASE64URL 45 /** Text is base64 encoded in RFC 4648. The base64 encoding is NOT - removed. Data is in @c val.string. */ + * removed. Data is in @c val.string. */ #define QCBOR_TYPE_BASE64 46 /** PERL-compatible regular expression. Data is in @c val.string. */ #define QCBOR_TYPE_REGEX 47 /** Non-binary MIME per RFC 2045. See also @ref - QCBOR_TYPE_BINARY_MIME. Data is in @c val.string. */ + * QCBOR_TYPE_BINARY_MIME. Data is in @c val.string. */ #define QCBOR_TYPE_MIME 48 /** Binary UUID per RFC 4122. Data is in @c val.string. */ #define QCBOR_TYPE_UUID 49 /** A CBOR sequence per RFC 8742. See also @ ref - QBCOR_TYPE_WRAPPED_CBOR. Data is in @c val.string. */ + * QBCOR_TYPE_WRAPPED_CBOR. Data is in @c val.string. */ #define QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE 75 /** Binary MIME per RFC 2045. See also @ref QCBOR_TYPE_MIME. Data is - in @c val.string. */ + * in @c val.string. */ #define QCBOR_TYPE_BINARY_MIME 76 /** Type for [RFC 8943](https://tools.ietf.org/html/rfc8943) date - string, a date with no time or time zone info. Data is in - @c val.string */ + * string, a date with no time or time zone info. Data is in + * @c val.string */ #define QCBOR_TYPE_DAYS_STRING 77 /** Type for integer days since Jan 1 1970 described in - [RFC 8943](https://tools.ietf.org/html/rfc8943). Data is in - @c val.epochDays */ + * [RFC 8943](https://tools.ietf.org/html/rfc8943). Data is in + * @c val.epochDays */ #define QCBOR_TYPE_DAYS_EPOCH 78 #define QCBOR_TYPE_TAG 254 /* Used internally; never returned */ @@ -354,6 +379,49 @@ typedef enum { #define QCBOR_LAST_UNMAPPED_TAG (CBOR_TAG_INVALID16 - QCBOR_NUM_MAPPED_TAGS - 1) +/** + * @anchor expAndMantissa + * + * This holds the value for big floats and decimal fractions, as an + * exponent and mantissa. For big floats the base for exponentiation + * is 2. For decimal fractions it is 10. Whether an instance is a big + * float or decimal fraction is known by context, usually by @c uDataType + * in @ref QCBORItem which might be @ref QCBOR_TYPE_DECIMAL_FRACTION, + * @ref QCBOR_TYPE_BIGFLOAT, ... + * + * The mantissa may be an @c int64_t or a big number. This is again + * determined by context, usually @c uDataType in @ref QCBORItem which + * might be @ref QCBOR_TYPE_DECIMAL_FRACTION, + * @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, ... The sign of the + * big number also comes from the context + * (@ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, + * @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,...). + * + * @c bigNum is big endian or network byte order. The most significant + * byte is first. + * + * When @c Mantissa is @c int64_t, it represents the true value of the + * mantissa with the offset of 1 for CBOR negative values + * applied. When it is a negative big number + * (@ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM or + * @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM), the offset of 1 has NOT been + * applied (doing so requires somewhat complex big number arithmetic + * and may increase the length of the big number). To get the correct + * value @c bigNum must be incremented by one before use. + * + * Also see QCBOREncode_AddTDecimalFraction(), + * QCBOREncode_AddTBigFloat(), QCBOREncode_AddTDecimalFractionBigNum() + * and QCBOREncode_AddTBigFloatBigNum(). + */ +typedef struct { + int64_t nExponent; + union { + int64_t nInt; + UsefulBufC bigNum; + } Mantissa; +} QCBORExpAndMantissa; + + /** * This holds a decoded data item. It is returned by the * QCBORDecode_GetNext(), the principle decoding function. @@ -438,64 +506,32 @@ typedef struct _QCBORItem { /** The value for @c uDataType @ref QCBOR_TYPE_DAYS_EPOCH -- the * number of days before or after Jan 1, 1970. */ int64_t epochDays; - /** No longer used. Was the value for @ref QCBOR_TYPE_DATE_STRING, - * but now that value is in @c string. TODO: finish writing this.*/ + * but now that value is in @c string. This will be removed in QCBOR 2.0. */ UsefulBufC dateString; - /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and - @ref QCBOR_TYPE_NEGBIGNUM. TODO: change to string*/ + * @ref QCBOR_TYPE_NEGBIGNUM. */ UsefulBufC bigNum; - /** The integer value for unknown simple types. TODO: doc this better. */ + /** See @ref QCBOR_TYPE_UKNOWN_SIMPLE */ uint8_t uSimple; #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - /** - * @anchor expAndMantissa - * - * This holds the value for big floats and decimal fractions. - * The use of the fields in this structure depends on @c - * uDataType. - * - * When @c uDataType indicates a decimal fraction, the - * @c nExponent is base 10. When it indicates a big float, it - * is base 2. - * - * When @c uDataType indicates a big number, then the @c bigNum - * member of @c Mantissa is valid. Otherwise the @c nInt member - * 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_AddTDecimalFraction(), - * QCBOREncode_AddTBigFloat(), - * QCBOREncode_AddTDecimalFractionBigNum() and - * QCBOREncode_AddTBigFloatBigNum(). - */ - struct { - int64_t nExponent; - union { - int64_t nInt; - UsefulBufC bigNum; - } Mantissa; - } expAndMantissa; -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + QCBORExpAndMantissa expAndMantissa; +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ 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; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */ uint64_t uint64; + /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and + * @ref QCBOR_TYPE_TEXT_STRING */ + UsefulBufC string; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ } label; #ifndef QCBOR_DISABLE_TAGS @@ -590,7 +626,9 @@ typedef struct _QCBORItem { * strings will have to free them. How they free them, depends on the * design of the string allocator. */ -typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, void *pOldMem, size_t uNewSize); +typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, + void *pOldMem, + size_t uNewSize); /** @@ -654,7 +692,8 @@ typedef struct _QCBORDecodeContext QCBORDecodeContext; * 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); +void +QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode); /** @@ -703,7 +742,10 @@ void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDec * See also QCBORDecode_SetUpAllocator() to set up a custom allocator * if this one isn't sufficient. */ -QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings); +QCBORError +QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, + UsefulBuf MemPool, + bool bAllStrings); /** @@ -739,10 +781,11 @@ QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, b * @c uLabelAlloc @c == @c 1 in @ref QCBORItem. Note this is in a * separate GitHub repository. */ -void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, - QCBORStringAllocate pfAllocateFunction, - void *pAllocateContext, - bool bAllStrings); +void +QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, + QCBORStringAllocate pfAllocateFunction, + void *pAllocateContext, + bool bAllStrings); /** @@ -865,9 +908,10 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, * * See [Decode Error Overview](#Decode-Errors-Overview). * - * If a decoding 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, it is sufficient to check for @ref QCBOR_TYPE_NONE. + * If a decoding error occurs or previously occured, @c uDataType and + * @c uLabelType will be set to @ref QCBOR_TYPE_NONE. If there is no + * need to know the specific error, it is sufficient to check for @ref + * QCBOR_TYPE_NONE. * * Errors fall in several categories: * @@ -905,7 +949,7 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, * | __Invalid CBOR__ || * | @ref QCBOR_ERR_NO_MORE_ITEMS | Need more input data items to decode | * | @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA | The structure of a big float or big number is invalid | - * | @ref QCBOR_ERR_BAD_TAG_CONTENT | The content of a tag is of the wrong type | + * | @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT | The content of a tag is of the wrong type | * | __Implementation Limits__ || * | @ref QCBOR_ERR_INT_OVERFLOW | Input integer smaller than INT64_MIN | * | @ref QCBOR_ERR_ARRAY_DECODE_TOO_LONG | Array or map has more elements than can be handled | @@ -916,14 +960,15 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, * | __Configuration errors__ || * | @ref QCBOR_ERR_NO_STRING_ALLOCATOR | Encountered indefinite-length string with no allocator configured | * | @ref QCBOR_ERR_MAP_LABEL_TYPE | A map label that is not a string on an integer | - * | @ref QCBOR_ERR_HALF_PRECISION_DISABLED | Library compiled with half-precision disabled and half-precision input encountered | - * | @ref QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED | Library compiled with indefinite maps and arrays disabled and indefinite map or array encountered | - * | @ref QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Library compiled with indefinite strings disabled and indefinite string encountered | + * | @ref QCBOR_ERR_HALF_PRECISION_DISABLED | Half-precision input, but disabled in QCBOR library | + * | @ref QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED | Indefinite-length input, but disabled in QCBOR library | + * | @ref QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Indefinite-length input, but disabled in QCBOR library | * | @ref QCBOR_ERR_ALL_FLOAT_DISABLED | Library compiled with floating-point support turned off. | * | __Resource exhaustion errors__ || * | @ref QCBOR_ERR_STRING_ALLOCATE | The string allocator is unable to allocate more memory | */ -void QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +void +QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); /** @@ -939,7 +984,8 @@ void QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); * doesn't set the internal decoding error and will attempt to decode * even if the decoder is in the error state. */ -QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +QCBORError +QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); /** @@ -948,14 +994,24 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem * @param[in] pCtx The decoder context. * @param[out] pDecodedItem The decoded CBOR item. * - * This is the same as QCBORDecode_VGetNext() but the contents of the - * entire map or array will be consumed if the item is a map or array. + * @c pItem returned is the same as QCBORDecode_VGetNext(). If the + * item is an array or map, the entire contents of the array or map + * will be consumed leaving the cursor after the array or map. + * + * If an array or map is being consumed by this, an error will occur + * if any of the items in the array or map are in error. * - * In order to go back to decode the contents of a map or array + * If the item is a tag the contents of which is an array or map, like + * a big float, @c pItem will identify it as such and the contents + * will be consumed, but the validity of the tag won't be checked + * other than for being well-formed. + * + * In order to go back to decode the contents of an array or map * consumed by this, the decoder must be rewound using * QCBORDecode_Rewind(). */ -void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +void +QCBORDecode_VGetNextConsume(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); /** @@ -1000,6 +1056,68 @@ QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +/** + * @brief Get the current traversal cursort offset in the input CBOR. + * + * @param[in] pCtx The decoder context. + * + * @returns The traversal cursor offset or @c UINT32_MAX. + + * The position returned is always the start of the next item that + * would be next decoded with QCBORDecode_VGetNext(). The cursor + * returned may be at the end of the input in which case the next call + * to QCBORDecode_VGetNext() will result in the @ref + * QCBOR_ERR_NO_MORE_ITEMS. See also QCBORDecode_AtEnd(). + * + * If the decoder is in error state from previous decoding, + * @c UINT32_MAX is returned. + * + * When decoding map items, the position returned is always of the + * label, never the value. + * + * For indefinite-length arrays and maps, the break byte is consumed + * when the last item in the array or map is consumed so the cursor is + * at the next item to be decoded as expected. + * + * There are some special rules for the traversal cursor when fetching + * map items by label. See the description of @SpiffyDecode. + * + * When traversal is bounded because an array or map has been entered + * (e.g., QCBORDecode_EnterMap()) and all items in the array or map + * have been consumed, the position returned will be of the item + * outside of the array or map. The array or map must be exited before + * QCBORDecode_VGetNext() will decode it. + * + * In many cases the position returned will be in the middle of + * an array or map. It will not be possible to start decoding at + * that location with another instance of the decoder and go to + * the end. It is not valid CBOR. If the input is a CBOR sequence + * and the position is not in the moddle of an array or map + * then it is possible to decode to the end. + * + * There is no corresponding seek method because it is too complicated + * to restore the internal decoder state that tracks nesting. + */ +static uint32_t +QCBORDecode_Tell(QCBORDecodeContext *pCtx); + + +/** + * @brief Tell whether cursor is at end of the input. + * + * @param[in] pCtx The decoder context. + * + * @returns Error code possibly indicating end of input. + * + * This returns the same as QCBORDecode_GetError() except that @ref + * QCBOR_ERR_NO_MORE_ITEMS is returned if the travseral cursor is at + * the end of the CBOR input bytes (not the end of an entered array or + * map). + */ +QCBORError +QCBORDecode_EndCheck(QCBORDecodeContext *pCtx); + + /** * @brief Returns the tag numbers for an item. * @@ -1014,44 +1132,50 @@ QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); * in the QCBORItem. * * Tags nest. Here the tag with index 0 has the data item as its content. The - * tag with index 1 has the tag at index 0 has its content and so forth. + * tag with index 1 has the tag at index 0 has its content and so forth. * * Deep tag nesting is rare so this implementation imposes a limit of * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref * QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this - * imple* mentation, not of CBOR. (To be able to handle deeper + * implementation, not of CBOR. (To be able to handle deeper * nesting, the constant can be increased and the library * recompiled. It will use more memory). * * See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. * * To reduce memory used by a QCBORItem, tag numbers larger than - * UINT16_MAX are mapped so the tag numbers in @c uTags should be + * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be * accessed with this function rather than directly. * * This returns @ref CBOR_TAG_INVALID64 if any error occurred when * getting the item. This is also returned if there are no tags on the * item or no tag at @c uIndex. */ -uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); +uint64_t +QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); /** - * @brief Returns the tag numbers for last-fetched item. + * @brief Returns the tag numbers for last-decoded item. * * @param[in] pCtx The decoder context. * @param[in] uIndex The index of the tag to get. * - * @returns The actual nth tag value or CBOR_TAG_INVALID64. + * @returns The nth tag number or CBOR_TAG_INVALID64. + * + * This returns tags of the most recently decoded item. See + * QCBORDecode_GetNthTag(). This is particularly of use for spiffy + * decode functions that don't return a @ref QCBORItem. * - * See QCBORDecode_GetNthTag(). This is the same but works with spiffy - * decoding functions that do not return a QCBORItem with a - * list of recorded tag numbers. This gets the tags for the most - * recently decoded item. + * This does not work for QCBORDecode_GetNext(), + * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or + * QCBORDecode_VGetNextConsume() but these all return a + * @ref QCBORItem, so it is not necessary. * - * If a decoding error set then this returns CBOR_TAG_INVALID64. + * If a decoding error is set, then this returns CBOR_TAG_INVALID64. */ -uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); +uint64_t +QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); /** @@ -1092,7 +1216,8 @@ uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uI * QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a * successful decode. See also QCBORDecode_PartialFinish(). */ -QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx); +QCBORError +QCBORDecode_Finish(QCBORDecodeContext *pCtx); /** @@ -1124,6 +1249,19 @@ QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed); +/** + * @brief Retrieve the undecoded input buffer. + * + * @param[in] pCtx The decode context. + * + * @return The input that was given to QCBORDecode_Init(). + * + * A simple convenience method, should it be useful to get the original input back. + */ +static UsefulBufC +QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pCtx); + + /** * @brief Get the decoding error. * @@ -1151,7 +1289,8 @@ QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed); * QCBORDecode_GetAndResetError() may be called after these data items * are fetched. */ -static QCBORError QCBORDecode_GetError(QCBORDecodeContext *pCtx); +static QCBORError +QCBORDecode_GetError(QCBORDecodeContext *pCtx); /** @@ -1163,22 +1302,24 @@ static QCBORError QCBORDecode_GetError(QCBORDecodeContext *pCtx); * This returns the same as QCBORDecode_GetError() and also resets the * error state to @ref QCBOR_SUCCESS. */ -static QCBORError QCBORDecode_GetAndResetError(QCBORDecodeContext *pCtx); +static QCBORError +QCBORDecode_GetAndResetError(QCBORDecodeContext *pCtx); /** * @brief Whether an error indicates non-well-formed CBOR. * - * @param[in] uErr The decoder context. + * @param[in] uErr The QCBOR error code. * @return @c true if the error code indicates non-well-formed CBOR. */ -static bool QCBORDecode_IsNotWellFormedError(QCBORError uErr); +static bool +QCBORDecode_IsNotWellFormedError(QCBORError uErr); /** * @brief Whether a decoding error is recoverable. * - * @param[in] uErr The decoder context. + * @param[in] uErr The QCBOR error code. * @return @c true if the error code indicates and uncrecoverable error. * * When an error is unrecoverable, no further decoding of the input is @@ -1194,55 +1335,81 @@ static bool QCBORDecode_IsNotWellFormedError(QCBORError uErr); * The unrecoverable errors are a range of the errors in * @ref QCBORError. */ -static bool QCBORDecode_IsUnrecoverableError(QCBORError uErr); +static bool +QCBORDecode_IsUnrecoverableError(QCBORError uErr); + + +/** + * @brief Manually set error condition, or set user-defined error. + * + * @param[in] pCtx The decoder context. + * @param[in] uError The error code to set. + * + * Once set, none of the QCBORDecode methods will do anything and the + * error code set will stay until cleared with + * QCBORDecode_GetAndResetError(). A user-defined error can be set + * deep in some decoding layers to short-circuit further decoding + * and propagate up. + * + * When the error condition is set, QCBORDecode_VGetNext() will always + * return an item with data and label type as @ref QCBOR_TYPE_NONE. + * + * The main intent of this is to set a user-defined error code in the + * range of @ref QCBOR_ERR_FIRST_USER_DEFINED to + * @ref QCBOR_ERR_LAST_USER_DEFINED, but it is OK to set QCBOR-defined + * error codes too. + */ +static void +QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError); /** - @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). + * @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 1,000 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) +static inline int +QCBOR_Int64ToInt32(int64_t src, int32_t *dest) { if(src > INT32_MAX || src < INT32_MIN) { return -1; @@ -1252,7 +1419,8 @@ static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest) return 0; } -static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest) +static inline int +QCBOR_Int64ToInt16(int64_t src, int16_t *dest) { if(src > INT16_MAX || src < INT16_MIN) { return -1; @@ -1262,7 +1430,8 @@ static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest) return 0; } -static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest) +static inline int +QCBOR_Int64ToInt8(int64_t src, int8_t *dest) { if(src > INT8_MAX || src < INT8_MIN) { return -1; @@ -1272,7 +1441,8 @@ static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest) return 0; } -static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) +static inline int +QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) { if(src > UINT32_MAX || src < 0) { return -1; @@ -1282,7 +1452,14 @@ static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) return 0; } -static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest) +/** + * https://github.com/laurencelundblade/QCBOR/pull/243 + * For backwards compatibility + */ +#define QCBOR_Int64UToInt16 QCBOR_Int64ToUInt16 + +static inline int +QCBOR_Int64ToUInt16(int64_t src, uint16_t *dest) { if(src > UINT16_MAX || src < 0) { return -1; @@ -1292,7 +1469,8 @@ static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest) return 0; } -static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) +static inline int +QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) { if(src > UINT8_MAX || src < 0) { return -1; @@ -1302,7 +1480,8 @@ static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) return 0; } -static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) +static inline int +QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) { if(src < 0) { return -1; @@ -1315,11 +1494,12 @@ static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) -/* ------------------------------------------------------------------------ - * Deprecated functions retained for backwards compatibility. Their use is - * not recommended. - * ---- */ - +/* ========================================================================= * + * BEGINNING OF DEPRECATED FUNCTIONS * + * * + * There is no plan to remove these in future versions. * + * They just have been replaced by something better. * + * ========================================================================= */ /** * Deprecated -- Tag handling has been revised and this is no longer @@ -1360,7 +1540,9 @@ typedef struct { * Tag handling has been revised and it is no longer ncessary to use * this. See QCBORDecode_GetNthTag(). */ -void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList); +void +QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, + const QCBORTagListIn *pTagList); /** @@ -1388,7 +1570,10 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBO * add new tags to the internal list so they can be checked for with * this function. */ -bool QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag); +bool +QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, + const QCBORItem *pItem, + uint64_t uTag); /** @@ -1409,12 +1594,12 @@ bool QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint * been decoded. * * This is not backwards compatibile in two ways. First, it is limited - * to \ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was + * to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was * unlimited. Second, it will not inlucde the tags that QCBOR decodes * internally. * * This works the same as QCBORDecode_GetNext() except that it also - * returns the list of tags for the data item in \c pTagList. + * returns the list of tags for the data item in @c pTagList. * * The 0th tag returned here is the one furthest from the data * item. This is opposite the order for QCBORDecode_GetNthTag(). @@ -1425,28 +1610,56 @@ bool QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint * QCBOR_ERR_TOO_MANY_TAGS if the array in @c pTagList is too small to * hold all the tags for the item. */ -QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList); +QCBORError +QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, + QCBORItem *pDecodedItem, + QCBORTagListOut *pTagList); + +/* ========================================================================= * + * END OF DEPRECATED FUNCTIONS * + * ========================================================================= */ -/* ------------------------------------------------------------------------ - * Inline implementations of public functions defined above. - * ---- */ -static inline QCBORError QCBORDecode_GetError(QCBORDecodeContext *pMe) +/* ========================================================================= * + * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * + * ========================================================================= */ + +static inline uint32_t +QCBORDecode_Tell(QCBORDecodeContext *pMe) +{ + if(pMe->uLastError) { + return UINT32_MAX; + } + + /* Cast is safe because decoder input size is restricted. */ + return (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf)); +} + +static inline UsefulBufC +QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pMe) +{ + return UsefulInputBuf_RetrieveUndecodedInput(&(pMe->InBuf)); +} + +static inline QCBORError +QCBORDecode_GetError(QCBORDecodeContext *pMe) { return (QCBORError)pMe->uLastError; } -static inline QCBORError QCBORDecode_GetAndResetError(QCBORDecodeContext *pMe) +static inline QCBORError +QCBORDecode_GetAndResetError(QCBORDecodeContext *pMe) { const QCBORError uReturn = (QCBORError)pMe->uLastError; pMe->uLastError = QCBOR_SUCCESS; return uReturn; } -static inline bool QCBORDecode_IsNotWellFormedError(QCBORError uErr) +static inline bool +QCBORDecode_IsNotWellFormedError(const QCBORError uErr) { if(uErr >= QCBOR_START_OF_NOT_WELL_FORMED_ERRORS && uErr <= QCBOR_END_OF_NOT_WELL_FORMED_ERRORS) { @@ -1456,7 +1669,8 @@ static inline bool QCBORDecode_IsNotWellFormedError(QCBORError uErr) } } -static inline bool QCBORDecode_IsUnrecoverableError(QCBORError uErr) +static inline bool +QCBORDecode_IsUnrecoverableError(const QCBORError uErr) { if(uErr >= QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS && uErr <= QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS) { @@ -1466,6 +1680,18 @@ static inline bool QCBORDecode_IsUnrecoverableError(QCBORError uErr) } } + +static inline void +QCBORDecode_SetError(QCBORDecodeContext *pMe, QCBORError uError) +{ + pMe->uLastError = (uint8_t)uError; +} + +/* ======================================================================== * + * END OF PRIVATE INLINE IMPLEMENTATION * + * ======================================================================== */ + + /* A few cross checks on size constants and special value lengths */ #if QCBOR_MAP_OFFSET_CACHE_INVALID < QCBOR_MAX_DECODE_INPUT_SIZE #error QCBOR_MAP_OFFSET_CACHE_INVALID is too large diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h b/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h index 8b2ed90ab680..cf88754f255b 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2021, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - =============================================================================*/ +/* =========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * 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 @@ -50,2186 +50,2673 @@ extern "C" { /** - @file qcbor_encode.h - - @anchor Overview - - # QCBOR Overview - - This implements CBOR -- Concise Binary Object Representation as - defined in [RFC 8949] (https://tools.ietf.org/html/rfc8949). More - information is at http://cbor.io. This is a near-complete implementation of - the specification. [RFC 8742] (https://tools.ietf.org/html/rfc8742) CBOR - Sequences is also supported. Limitations are listed further down. - - See @ref Encoding for general discussion on encoding, - @ref BasicDecode for general discussion on the basic decode features - and @ref SpiffyDecode for general discussion on the easier-to-use - decoder functions. - - CBOR is intentionally designed to be translatable to JSON, but not - all CBOR can convert to JSON. See RFC 8949 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": A data item that is an explicitly labeled new data - type made up of the tagging integer and the tag content. - See @ref Tags-Overview and @ref Tag-Usage. - - - "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. - - @anchor Encoding - - ## Encoding - - A common encoding usage mode is to invoke the encoding twice. First - with the output buffer as @ref SizeCalculateUsefulBuf to compute the - length of the needed output buffer. The correct sized output buffer - is allocated. The encoder is invoked a second time with the allocated - 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 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. - - If QCBOR is compiled with QCBOR_DISABLE_ENCODE_USAGE_GUARDS defined, - the errors QCBOR_ERR_CLOSE_MISMATCH, QCBOR_ERR_ARRAY_TOO_LONG, - QCBOR_ERR_TOO_MANY_CLOSES, QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, and - QCBOR_ERR_ENCODE_UNSUPPORTED will never be returned. It is up to the - caller to make sure that opened maps, arrays and byte-string wrapping - is closed correctly and that QCBOREncode_AddType7() is called - correctly. With this defined, it is easier to make a mistake when - authoring the encoding of a protocol that will output not well formed - CBOR, but as long as the calling code is correct, it is safe to - disable these checks. Bounds checking that prevents security issues - in the code is still enforced. This define reduces the size of - encoding object code by about 150 bytes. - - @anchor Tags-Overview - - ## Tags Overview - - Any CBOR data item can be made into a tag 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. - - See also @ref CBORTags and @ref Tag-Usage - - The encoding side of tags not built-in is handled by - QCBOREncode_AddTag() and is relatively simple. Tag decoding is more - 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. - - @anchor Floating-Point - - ## Floating-Point - - By default QCBOR fully supports IEEE 754 floating-point: - - Encode/decode of double, single and half-precision - - CBOR preferred serialization of floating-point - - Floating-point epoch dates - - For the most part, the type double is used in the interface for - floating-point values. In the default configuration, all decoded - floating-point values are returned as a double. - - With CBOR preferred serialization, the encoder 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 - double and single-precision, especially if zero, NaN and infinity are - frequently used. - - To avoid use of preferred serialization in the standard configuration - when encoding, use QCBOREncode_AddDoubleNoPreferred() or - QCBOREncode_AddFloatNoPreferred(). - - This implementation of preferred floating-point serialization and - half-precision does not depend on the CPU having floating-point HW or - the compiler bringing in a (sometimes large) library to compensate - for lack of CPU support. This implementation uses shifts and masks - rather than floating-point functions. - - To reduce overall object code by about 900 bytes, define - QCBOR_DISABLE_PREFERRED_FLOAT. This will eliminate all support for - preferred serialization and half-precision. An error will be returned - when attempting to decode half-precision. A float will always be - encoded and decoded as 32-bits and a double will always be encoded - and decoded as 64 bits. - - Note that even if QCBOR_DISABLE_PREFERRED_FLOAT is not defined all - the float-point encoding object code can be avoided by never calling - any functions that encode double or float. Just not calling - floating-point functions will reduce object code by about 500 bytes. - - On CPUs that have no floating-point hardware, - QCBOR_DISABLE_FLOAT_HW_USE should be defined in most cases. If it is - not, then the compiler will bring in possibly large software - libraries to compensate. Defining QCBOR_DISABLE_FLOAT_HW_USE reduces - object code size on CPUs with floating-point hardware by a tiny - amount and eliminates the need for - - When QCBOR_DISABLE_FLOAT_HW_USE is defined, trying to decoding - floating-point dates will give error - @ref QCBOR_ERR_FLOAT_DATE_DISABLED and decoded single-precision - numbers will be returned as @ref QCBOR_TYPE_FLOAT instead of - converting them to double as usual. - - If both QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT - are defined, then the only thing QCBOR can do is encode/decode a C - float type as 32-bits and a C double type as 64-bits. Floating-point - epoch dates will be unsupported. - - If USEFULBUF_DISABLE_ALL_FLOATis defined, then floating point support is - completely disabled. Decoding functions return @ref QCBOR_ERR_ALL_FLOAT_DISABLED - if a floating point value is encountered during decoding. Functions that are - encoding floating point values are not available. - - ## Limitations - - Summary Limits of this implementation: - - The entire encoded CBOR must fit into contiguous memory. - - Max size of encoded / decoded CBOR data is a few bytes less than @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. - - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4). - - 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 - also requires this. It is possible to modify this - implementation for another integer representation, but all modern - machines seem to be two's compliment. + * @file qcbor_encode.h + * + * @anchor Overview + * + * # QCBOR Overview + * + * This implements CBOR -- Concise Binary Object Representation as + * defined in [RFC 8949] (https://www.rfc-editor.org/rfc/rfc8949.html). + * More information is at http://cbor.io. This is a near-complete + * implementation of the specification. [RFC 8742] + * (https://www.rfc-editor.org/rfc/rfc8742.html) CBOR Sequences is + * also supported. Limitations are listed further down. + * + * See @ref Encoding for general discussion on encoding, + * @ref BasicDecode for general discussion on the basic decode features + * and @ref SpiffyDecode for general discussion on the easier-to-use + * decoder functions. + * + * CBOR is intentionally designed to be translatable to JSON, but not + * all CBOR can convert to JSON. See RFC 8949 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": A data item that is an explicitly labeled new data + * type made up of the tagging integer and the tag content. + * See @ref Tags-Overview and @ref Tag-Usage. + * + * - "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. + * + * @anchor Encoding + * + * ## Encoding + * + * A common encoding usage mode is to invoke the encoding twice. First + * with the output buffer as @ref SizeCalculateUsefulBuf to compute the + * length of the needed output buffer. The correct sized output buffer + * is allocated. The encoder is invoked a second time with the allocated + * 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 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 type 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://www.rfc-editor.org/rfc/rfc8742.html). This + * encoder supports either just by whether the first item added is an + * array, map or other. + * + * If QCBOR is compiled with QCBOR_DISABLE_ENCODE_USAGE_GUARDS defined, + * the errors QCBOR_ERR_CLOSE_MISMATCH, QCBOR_ERR_ARRAY_TOO_LONG, + * QCBOR_ERR_TOO_MANY_CLOSES, QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, and + * QCBOR_ERR_ENCODE_UNSUPPORTED will never be returned. It is up to the + * caller to make sure that opened maps, arrays and byte-string wrapping + * is closed correctly and that QCBOREncode_AddType7() is called + * correctly. With this defined, it is easier to make a mistake when + * authoring the encoding of a protocol that will output not well formed + * CBOR, but as long as the calling code is correct, it is safe to + * disable these checks. Bounds checking that prevents security issues + * in the code is still enforced. This define reduces the size of + * encoding object code by about 150 bytes. + * + * @anchor Tags-Overview + * + * ## Tags Overview + * + * Any CBOR data item can be made into a tag 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_AddTDateEpoch() 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. + * + * See also @ref CBORTags and @ref Tag-Usage + * + * The encoding side of tags not built-in is handled by + * QCBOREncode_AddTag() and is relatively simple. Tag decoding is more + * 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. + * + * @anchor Floating-Point + * + * ## Floating-Point + * + * By default QCBOR fully supports IEEE 754 floating-point: + * - Encode/decode of double, single and half-precision + * - CBOR preferred serialization of floating-point + * - Floating-point epoch dates + * + * For the most part, the type double is used in the interface for + * floating-point values. In the default configuration, all decoded + * floating-point values are returned as a double. + * + * With CBOR preferred serialization, the encoder 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 + * double and single-precision, especially if zero, NaN and infinity are + * frequently used. + * + * To avoid use of preferred serialization in the standard configuration + * when encoding, use QCBOREncode_AddDoubleNoPreferred() or + * QCBOREncode_AddFloatNoPreferred(). + * + * This implementation of preferred floating-point serialization and + * half-precision does not depend on the CPU having floating-point HW or + * the compiler bringing in a (sometimes large) library to compensate + * for lack of CPU support. This implementation uses shifts and masks + * rather than floating-point functions. + * + * To reduce overall object code by about 900 bytes, define + * QCBOR_DISABLE_PREFERRED_FLOAT. This will eliminate all support for + * preferred serialization and half-precision. An error will be returned + * when attempting to decode half-precision. A float will always be + * encoded and decoded as 32-bits and a double will always be encoded + * and decoded as 64 bits. + * + * Note that even if QCBOR_DISABLE_PREFERRED_FLOAT is not defined all + * the float-point encoding object code can be avoided by never calling + * any functions that encode double or float. Just not calling + * floating-point functions will reduce object code by about 500 bytes. + * + * On CPUs that have no floating-point hardware, + * QCBOR_DISABLE_FLOAT_HW_USE should be defined in most cases. If it is + * not, then the compiler will bring in possibly large software + * libraries to compensate. Defining QCBOR_DISABLE_FLOAT_HW_USE reduces + * object code size on CPUs with floating-point hardware by a tiny + * amount and eliminates the need for + * + * When QCBOR_DISABLE_FLOAT_HW_USE is defined, trying to decoding + * floating-point dates will give error + * @ref QCBOR_ERR_FLOAT_DATE_DISABLED and decoded single-precision + * numbers will be returned as @ref QCBOR_TYPE_FLOAT instead of + * converting them to double as usual. + * + * If both QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT + * are defined, then the only thing QCBOR can do is encode/decode a C + * float type as 32-bits and a C double type as 64-bits. Floating-point + * epoch dates will be unsupported. + * + * If USEFULBUF_DISABLE_ALL_FLOAT is defined, then floating point + * support is completely disabled. Decoding functions return + * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is + * encountered during decoding. Functions that are encoding floating + * point values are not available. + * + * ## Limitations + * + * Summary limitations: + * - The entire encoded CBOR must fit into contiguous memory. + * - Max size of encoded CBOR data is a few bytes less than + * @c UINT32_MAX (4GB). + * - Max array / map nesting level when encoding or decoding is + * @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15). + * - Max items in an array or map when encoding or decoding is + * @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536). + * - Does not directly support labels in maps other than text strings & integers. + * - Does not directly support integer labels beyond whats fits in @c int64_t + * or @c uint64_t. + * - Epoch dates limited to @c INT64_MAX (+/- 292 billion years). + * - Exponents for bigfloats and decimal integers are limited to whats fits in + * @c int64_t. + * - Tags on labels are ignored during decoding. + * - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4). + * - Works only on 32- and 64-bit CPUs. + * - QCBORDecode_EnterBstrWrapped() doesn't work on indefinite-length strings. + * - Numeric reduction of big numbers to integers for preferred + * serialization is not performed. + * + * 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). + * + * This implementation requires two's compliment integers. While + * C doesn't require two's compliment, does. Other + * parts of this implementation may also require 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. + * 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) /** - Output the full CBOR tag. See @ref CBORTags, @ref Tag-Usage and - @ref Tags-Overview. + * Output the full CBOR tag. See @ref CBORTags, @ref Tag-Usage and + * @ref Tags-Overview. */ #define QCBOR_ENCODE_AS_TAG 0 /** - Output only the 'borrowed' content format for the relevant tag. - See @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. + * Output only the 'borrowed' content format for the relevant tag. + * See @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. */ #define QCBOR_ENCODE_AS_BORROWED 1 /** - 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. + * 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 the encoded result - will be written. - - Call this once at the start of an encoding of some CBOR. Then call - the many functions like QCBOREncode_AddInt64() and - QCBOREncode_AddText() to add the different data items. Finally, call - QCBOREncode_Finish() to get the pointer and length of the encoded - result. - - The primary purpose of this function is to give the pointer and - length of the output buffer into which the encoded CBOR will be - written. This is done with a @ref UsefulBuf structure, which is just - a pointer and length (it is equivalent to two parameters, one a - pointer and one a length, but a little prettier). - - The output buffer can be allocated any way (malloc, stack, - static). It is just some memory that QCBOR writes to. The length must - be the length of the allocated buffer. QCBOR will never write past - that length, but might write up to that length. If the buffer is too - small, encoding will go into an error state and not write anything - further. - - If allocating on the stack the convenience macro - UsefulBuf_MAKE_STACK_UB() can be used, but its use is not required. - - Since there is no reallocation or such, the output buffer must be - correctly sized when passed in here. It is OK, but wasteful if it is - too large. One way to pick the size is to figure out the maximum size - that will ever be needed and hard code a buffer of that size. - - Another way to do it is to have QCBOR calculate it for you. To do - this, pass @ref SizeCalculateUsefulBuf for @c Storage. - Then call all the functions to add the CBOR exactly as if - encoding for real. Finally, call QCBOREncode_FinishGetSize(). - Once the length is obtained, allocate a buffer of that - size, call QCBOREncode_Init() again with the real buffer. Call all - the add functions again and finally, QCBOREncode_Finish() to obtain - the final result. This uses twice the CPU time, but that is - usually not an issue. - - See QCBOREncode_Finish() for how the pointer and length for the - encoded CBOR is returned. - - For practical purposes QCBOR can't output encoded CBOR larger than - @c UINT32_MAX (4GB) even on 64-bit CPUs because the internal offsets - used to track the start of an array/map are 32 bits to reduce the - size of the encoding context. - - A @ref QCBOREncodeContext can be reused over and over as long as - QCBOREncode_Init() is called before each use. + * Initialize the encoder. + * + * @param[in,out] pCtx The encoder context to initialize. + * @param[in] Storage The buffer into which the encoded result + * will be written. + * + * Call this once at the start of an encoding of some CBOR. Then call + * the many functions like QCBOREncode_AddInt64() and + * QCBOREncode_AddText() to add the different data items. Finally, + * call QCBOREncode_Finish() to get the pointer and length of the + * encoded result. + * + * The primary purpose of this function is to give the pointer and + * length of the output buffer into which the encoded CBOR will be + * written. This is done with a @ref UsefulBuf structure, which is + * just a pointer and length (it is equivalent to two parameters, one + * a pointer and one a length, but a little prettier). + * + * The output buffer can be allocated any way (malloc, stack, + * static). It is just some memory that QCBOR writes to. The length + * must be the length of the allocated buffer. QCBOR will never write + * past that length, but might write up to that length. If the buffer + * is too small, encoding will go into an error state and not write + * anything further. + * + * If allocating on the stack the convenience macro + * UsefulBuf_MAKE_STACK_UB() can be used, but its use is not required. + * + * Since there is no reallocation or such, the output buffer must be + * correctly sized when passed in here. It is OK, but wasteful if it + * is too large. One way to pick the size is to figure out the maximum + * size that will ever be needed and hard code a buffer of that size. + * + * Another way to do it is to have QCBOR calculate it for you. To do + * this, pass @ref SizeCalculateUsefulBuf for @c Storage. Then call + * all the functions to add the CBOR exactly as if encoding for + * real. Finally, call QCBOREncode_FinishGetSize(). Once the length + * is obtained, allocate a buffer of that size, call + * QCBOREncode_Init() again with the real buffer. Call all the add + * functions again and finally, QCBOREncode_Finish() to obtain the + * final result. This uses twice the CPU time, but that is usually not + * an issue. + * + * See QCBOREncode_Finish() for how the pointer and length for the + * encoded CBOR is returned. + * + * For practical purposes QCBOR can't output encoded CBOR larger than + * @c UINT32_MAX (4GB) even on 64-bit CPUs because the internal + * offsets used to track the start of an array/map are 32 bits to + * reduce the size of the encoding context. + * + * A @ref QCBOREncodeContext can be reused over and over as long as + * QCBOREncode_Init() is called before each use. */ -void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage); +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 8949] (https://tools.ietf.org/html/rfc8949) Appendix A for more - examples of CBOR encoding. This compact encoding is also preferred - serialization CBOR as per section 34.1 in RFC 8949. - - 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(). + * @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 integer, like @c int16_t or a small value, + * like 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 8949 Appendix A] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-appendix.a) + * for more examples of CBOR encoding. This compact encoding is + * preferred serialization CBOR as per [RFC 8949 section 4.1] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-4.1) + * + * 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 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); +void +QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum); -static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum); +static void +QCBOREncode_AddInt64ToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nNum); -static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum); +static void +QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t nNum); /** - @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(). + * @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_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum); -static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); +static void +QCBOREncode_AddUInt64ToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); -static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, 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. + * @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://www.rfc-editor.org/rfc/rfc3629.html). 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. + * + * Text lines in Internet protocols (on the wire) are delimited by + * either a CRLF or just an LF. Officially many protocols specify + * CRLF, but implementations often work with either. CBOR type 3 text + * can be either line ending, even a mixture of both. + * + * Operating systems usually have a line end convention. Windows uses + * CRLF. Linux and MacOS use LF. Some applications on a given OS may + * work with either and some may not. + * + * The majority of use cases and CBOR protocols using type 3 text will + * work with either line ending. However, some use cases or protocols + * may not work with either in which case translation to and/or from + * the local line end convention, typically that of the OS, is + * necessary. + * + * QCBOR does no line ending translation for type 3 text when encoding + * and decoding. + * + * Error handling is the same as QCBOREncode_AddInt64(). + */ +static void +QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); - 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. +static void +QCBOREncode_AddTextToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - 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. +static void +QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); - 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. - Text lines in Internet protocols (on the wire) are delimited by - either a CRLF or just an LF. Officially many protocols specify CRLF, - but implementations often work with either. CBOR type 3 text can be - either line ending, even a mixture of both. +/** + * @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); - Operating systems usually have a line end convention. Windows uses - CRLF. Linux and MacOS use LF. Some applications on a given OS may - work with either and some may not. +static void +QCBOREncode_AddSZStringToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - The majority of use cases and CBOR protocols using type 3 text will - work with either line ending. However, some use cases or protocols - may not work with either in which case translation to and/or from the - local line end convention, typically that of the OS, is necessary. +static void +QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); - QCBOR does no line ending translation for type 3 text when encoding - and decoding. - Error handling is the same as QCBOREncode_AddInt64(). +#ifndef USEFULBUF_DISABLE_ALL_FLOAT +/** + * @brief Add a double-precision 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 encodes and outputs a double-precision floating-point + * number. CBOR major type 7 is used. + * + * This implements preferred serialization, selectively encoding the + * double-precision floating-point number as either double-precision, + * single-precision or half-precision. Infinity, NaN and zero are + * always encoded as half-precision. If no precision will be lost in + * the conversion to half-precision, then it will be converted and + * encoded. If not and no precision will be lost in conversion to + * single-precision, then it will be converted and encoded. If not, + * then no conversion is performed, and it encoded as a + * double-precision. + * + * Half-precision floating-point numbers take up two bytes, half that + * of single-precision, one quarter of double-precision. Preferred + * serialization can therefore reduce message size down to one quarter + * of the original if most of the values are zero, infinity or NaN. + * + * When decoded, QCBOR returns these values as double-precision even + * if they were encoded as single or half-precision. + * + * It is possible to disable preferred serialization when compiling + * QCBOR. In that case, this operates the same as + * QCBOREncode_AddDoubleNoPreferred(). + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat() + * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. */ -static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); +static void +QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum); -static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); +static void +QCBOREncode_AddDoubleToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); -static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); +static void +QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); /** - @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(). + * @brief Add a single-precision floating-point number to the encoded output. + * + * @param[in] pCtx The encoding context to add the single to. + * @param[in] fNum The single-precision number to add. + * + * This is identical to QCBOREncode_AddDouble() except the input is + * single-precision. The preferred serialization output will be either + * single-precision or half-precision. + * + * See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(), + * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. */ -static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString); +static void +QCBOREncode_AddFloat(QCBOREncodeContext *pCtx, float fNum); -static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); +static void +QCBOREncode_AddFloatToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); +static void +QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum); -#ifndef USEFULBUF_DISABLE_ALL_FLOAT /** - @brief Add a double-precision 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. + * @brief Add a double-precision floating-point number without preferred encoding. + * + * @param[in] pCtx The encoding context to add the double to. + * @param[in] dNum The double-precision number to add. + * + * This always outputs the number as a 64-bit double-precision. + * Preferred serialization is not used. + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and + * QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. + */ +static void +QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum); - This encodes and outputs a floating-point number. CBOR major type 7 - is used. +static void +QCBOREncode_AddDoubleNoPreferredToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - This implements preferred serialization, selectively encoding the - double-precision floating-point number as either double-precision, - single-precision or half-precision. Infinity, NaN and 0 are always - encoded as half-precision. If no precision will be lost in the - conversion to half-precision, then it will be converted and - encoded. If not and no precision will be lost in conversion to - single-precision, then it will be converted and encoded. If not, then - no conversion is performed, and it encoded as a double-precision. +static void +QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); - 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 CBOR, maybe even by - four if most of values are 0, infinity or NaN. +/** + * @brief Add a single-precision floating-point number without preferred encoding. + * + * @param[in] pCtx The encoding context to add the double to. + * @param[in] fNum The single-precision number to add. + * + * This always outputs the number as a 32-bit single-precision. + * Preferred serialization is not used. + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and + * QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point. + */ +static void +QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum); - When decoded, QCBOR will usually return these values as - double-precision. +static void +QCBOREncode_AddFloatNoPreferredToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); - It is possible to disable this preferred serialization when compiling - QCBOR. In that case, this functions the same as - QCBOREncode_AddDoubleNoPreferred(). +static void +QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum); +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ - Error handling is the same as QCBOREncode_AddInt64(). - See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat() - and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. +/** + * @brief Add a tag number. + * + * @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_AddTDateEpoch() 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_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); +static void +QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag); /** - @brief Add a single-precision floating-point number to the encoded output. + * @brief Add an epoch-based date. + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nDate Number of seconds since 1970-01-01T00:00Z + * in UTC time. + * + * As per RFC 8949 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 preferred integer serialization 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_AddTag() and QCBOREncode_AddDouble(). + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddTDaysEpoch(). + */ +static void +QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nDate); - @param[in] pCtx The encoding context to add the double to. - @param[in] fNum The single-precision number to add. +static void +QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nDate); - This is identical to QCBOREncode_AddDouble() except the input is - single-precision. +static void +QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nDate); - See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(), - and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. -*/ -void QCBOREncode_AddFloat(QCBOREncodeContext *pCtx, float fNum); -static void QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -static void QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum); /** - @brief Add a double-precision floating-point number without preferred encoding. - - @param[in] pCtx The encoding context to add the double to. - @param[in] dNum The double-precision number to add. - - This always outputs the number as a 64-bit double-precision. - Preferred serialization is not used. + * @brief Add an epoch-based day-count date. + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nDays Number of days before or after 1970-01-0. + * + * This date format is described in + * [RFC 8943] (https://www.rfc-editor.org/rfc/rfc8943.html). + * + * The preferred integer serialization rules apply here so the date + * will be encoded in a minimal number of bytes. Until about the year + * 2149 these dates will encode in 4 bytes -- one byte for the tag, + * one byte for the type and 2 bytes for the integer. + * + * See also QCBOREncode_AddTDateEpoch(). + */ +static void +QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nDays); - Error handling is the same as QCBOREncode_AddInt64(). +static void +QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nDays); - See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and - QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. -*/ -void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum); +static void +QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nDays); -static void QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); -static void QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); /** - @brief Add a single-precision floating-point number without preferred encoding. - - @param[in] pCtx The encoding context to add the double to. - @param[in] fNum The single-precision number to add. - - This always outputs the number as a 32-bit single-precision. - Preferred serialization is not used. - - Error handling is the same as QCBOREncode_AddInt64(). - - See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and - QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point. -*/ -void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum); + * @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_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); +static void +QCBOREncode_AddBytesToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -static void QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +static void +QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); /** - @brief Add an optional tag. - - @param[in] pCtx The encoding context to add the tag to. - @param[in] uTag The tag to add + * @brief Set up to write a byte string value directly to encoded output. + * + * @param[in] pCtx The encoding context to add the bytes to. + * @param[out] pPlace Pointer and length of place to write byte string value. + * + * QCBOREncode_AddBytes() is the normal way to encode a byte string. + * This is for special cases and by passes some of the pointer safety. + * + * The purpose of this is to output the bytes that make up a byte + * string value directly to the QCBOR output buffer so you don't need + * to have a copy of it in memory. This is particularly useful if the + * byte string is large, for example, the encrypted payload of a + * COSE_Encrypt message. The payload encryption algorithm can output + * directly to the encoded CBOR buffer, perhaps by making it the + * output buffer for some function (e.g. symmetric encryption) or by + * multiple writes. + * + * The pointer in @c pPlace is where to start writing. Writing is just + * copying bytes to the location by the pointer in @c pPlace. Writing + * past the length in @c pPlace will be writing off the end of the + * output buffer. + * + * If there is no room in the output buffer @ref NULLUsefulBuf will be + * returned and there is no need to call QCBOREncode_CloseBytes(). + * + * The byte string must be closed by calling QCBOREncode_CloseBytes(). + * + * Warning: this bypasses some of the usual checks provided by QCBOR + * against writing off the end of the encoded output buffer. + */ +void +QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace); - 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. +static void +QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBuf *pPlace); - 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. +static void +QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBuf *pPlace); - 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 Close out a byte string written directly to encoded output. + * + * @param[in] pCtx The encoding context to add the bytes to. + * @param[out] uAmount The number of bytes written, the length of the + * byte string. + * + * This closes out a call to QCBOREncode_OpenBytes(). This inserts a + * CBOR header at the front of the byte string value to make it a + * well-formed byte string. + * + * If there was no call to QCBOREncode_OpenBytes() then @ref + * QCBOR_ERR_TOO_MANY_CLOSES is set. + */ +void +QCBOREncode_CloseBytes(QCBOREncodeContext *pCtx, size_t uAmount); /** - @brief Add an epoch-based date. + * @brief Add a binary UUID to the encoded output. + * + * @param[in] pCtx The encoding context to add the UUID to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Bytes Pointer and length of the binary UUID. + * + * A binary UUID as defined in [RFC 4122] + * (https://www.rfc-editor.org/rfc/rfc4122.html) 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_AddTBinaryUUID(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC Bytes); - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] nDate Number of seconds since 1970-01-01T00:00Z in UTC time. +static void +QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC Bytes); - As per RFC 8949 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. +static void +QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC Bytes); - The preferred 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. +/** + * @brief Add a positive big number to the encoded output. + * + * @param[in] pCtx The encoding context. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] BigNumber Pointer and length of the big number. + * + * @c BigNumber makes up an aribtrary precision integer in + * network/big-endian byte order. The first byte is the most + * significant. + * + * It is encoded as CBOR major type 2, a binary string, possibly with + * tag @ref CBOR_TAG_POS_BIGNUM. See [RFC 8949 section 3.4.3] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No + * processing, such as removal of leading zeros, is perfomed. + * + * RFC 8949 preferred serialization requires big numbers that + * will fit in integers be encoded as integers. That is NOT + * performed. + */ +static void +QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC BigNumber); - 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. +static void +QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); - This implementation cannot encode fractional seconds using float or - double even though that is allowed by CBOR, but you can encode them - if you want to by calling QCBOREncode_AddTag() and QCBOREncode_AddDouble(). +static void +QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); - Error handling is the same as QCBOREncode_AddInt64(). - See also QCBOREncode_AddTDaysEpoch(). - */ -static void QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nDate); - -static void QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nDate); - -static void QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nDate); - - -static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, - int64_t nDate); - -static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nDate); +/** + * @brief Add a negative big number to the encoded output. + * + * @param[in] pCtx The encoding context. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] BigNumber Pointer and length of the big number. + * + * @c BigNumber makes up an aribtrary precision integer in + * network/big-endian byte order. The first byte is the most + * significant. + * + * It is encoded as CBOR major type 2, a binary string, possibly with + * tag @ref CBOR_TAG_NEG_BIGNUM. See [RFC 8949 section 3.4.3] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No + * processing, such as removal of leading zeros or the required offset + * of 1 for negative values, is perfomed. + * + * RFC 8949 preferred serialization requires big numbers that + * will fit in integers be encoded as integers. That is NOT + * performed. + */ +static void +QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC BigNumber); -static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - int64_t nDate); +static void +QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); +static void +QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA /** - @brief Add an epoch-based day-count date. - - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] nDays Number of days before or after 1970-01-0. + * @brief Add a decimal fraction to the encoded output. + * + * @param[in] pCtx Encoding context to add the decimal fraction to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nMantissa The mantissa. + * @param[in] nBase10Exponent The exponent. + * + * The value is @c nMantissa * 10 ^ @c 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). + * + * Preferred serialization is used when the mantissa or exponent are + * integers, thus they will be encoded in the smallest number of bytes. + * + * See also QCBOREncode_AddTDecimalFractionBigNum() for a decimal + * fraction with arbitrarily large precision and + * QCBOREncode_AddTBigFloat(). + * + * 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_AddTDecimalFraction(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase10Exponent); - This date format is described in - [RFC 8943] (https://tools.ietf.org/html/rfc8943). +static void +QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase10Exponent); - The integer encoding rules apply here so the date will be encoded in - a minimal number of bytes. Until about the year 2149 these dates will - encode in 4 bytes -- one byte for the tag, one byte for the type and - 2 bytes for the integer. +static void +QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase10Exponent); - See also QCBOREncode_AddTDateEpoch(). -*/ -static void QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pCtx, +/** + * @brief Add a decimal fraction with a big number mantissa to the encoded output. + * + * @param[in] pCtx Encoding context to add the decimal fraction to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Mantissa The mantissa. + * @param[in] bIsNegative false if mantissa is positive, true if negative. + * @param[in] nBase10Exponent The exponent. + * + * This is the same as QCBOREncode_AddTDecimalFraction() except the + * mantissa is a big number (See QCBOREncode_AddTPositiveBignum()) + * allowing for arbitrarily large precision. + * + * RFC 8949 preferred serialization requires reduction of big numbers + * that can fit into integers be encoded as integers, not big numbers. + * This implementation does NOT do that. + * + * See @ref expAndMantissa for decoded representation. + */ +static void +QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx, uint8_t uTagRequirement, - int64_t nDays); + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); -static void QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pCtx, +static void +QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uTagRequirement, - int64_t nDays); + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); -static void QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pCtx, +static void +QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint8_t uTagRequirement, - int64_t nDays); - - - + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); /** - @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(). + * @brief Add a big floating-point number to the encoded output. + * + * @param[in] pCtx The encoding context to add the bigfloat to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nMantissa The mantissa. + * @param[in] nBase2Exponent The exponent. + * + * The value is @c nMantissa * 2 ^ @c 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_AddTBigFloatBigNum() 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). + * + * Preferred serialization is used when the mantissa or exponent are + * integers, thus they will be encoded in the smallest number of bytes. + * + * 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_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes); +static void +QCBOREncode_AddTBigFloat(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase2Exponent); -static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase2Exponent); -static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase2Exponent); /** - @brief Set up to write a byte string value directly to encoded output. - - @param[in] pCtx The encoding context to add the bytes to. - @param[out] pPlace Pointer and length of place to write byte string value. - - QCBOREncode_AddBytes() is the normal way to encode a byte string. - This is for special cases and by passes some of the pointer safety. + * @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] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Mantissa The mantissa. + * @param[in] bIsNegative false if mantissa is positive, true if negative. + * @param[in] nBase2Exponent The exponent. + * + * This is the same as QCBOREncode_AddTBigFloat() except the mantissa + * is a big number (See QCBOREncode_AddTPositiveBignum()) allowing for + * arbitrary precision. + * + * RFC 8949 preferred serialization requires reduction of big numbers + * that can fit into integers be encoded as integers, not big numbers. + * This implementation does NOT do that. + * + * See @ref expAndMantissa for decoded representation. + */ +static void +QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - The purpose of this is to output the bytes that make up a byte string - value directly to the QCBOR output buffer so you don't need to have a - copy of it in memory. This is particularly useful if the byte string - is large, for example, the encrypted payload of a COSE_Encrypt - message. The payload encryption algorithm can output directly to the - encoded CBOR buffer, perhaps by making it the output buffer - for some function (e.g. symmetric encryption) or by multiple writes. +static void +QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - The pointer in \c pPlace is where to start writing. Writing is just - copying bytes to the location by the pointer in \c pPlace. Writing - past the length in \c pPlace will be writing off the end of the - output buffer. +static void +QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - If there is no room in the output buffer @ref NULLUsefulBuf will be - returned and there is no need to call QCBOREncode_CloseBytes(). +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - The byte string must be closed by calling QCBOREncode_CloseBytes(). - Warning: this bypasses some of the usual checks provided by QCBOR - against writing off the end of the encoded output buffer. +/** + * @brief Add a text URI to the encoded output. + * + * @param[in] pCtx The encoding context to add the URI to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] URI Pointer and length of the URI. + * + * The format of URI must be per [RFC 3986] + * (https://www.rfc-editor.org/rfc/rfc3986.html). + * + * 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_AddTURI(pCtx, QCBOR_ENCODE_AS_TAG, UsefulBuf_FromSZ(szURI)); */ -void -QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace); +static void +QCBOREncode_AddTURI(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC URI); static void -QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBuf *pPlace); +QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC URI); static void -QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBuf *pPlace); +QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC URI); /** - @brief Close out a byte string written directly to encoded output. - - @param[in] pCtx The encoding context to add the bytes to. - @param[out] uAmount The number of bytes written, the length of the byte string. - - This closes out a call to QCBOREncode_OpenBytes(). This inserts a - CBOR header at the front of the byte string value to make it a - well-formed byte string. - - If there was no call to QCBOREncode_OpenBytes() then - @ref QCBOR_ERR_TOO_MANY_CLOSES is set. + * @brief Add Base64-encoded text to encoded output. + * + * @param[in] pCtx The encoding context to add the base-64 text to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] B64Text Pointer and length of the base-64 encoded text. + * + * The text content is Base64 encoded data per [RFC 4648] + * (https://www.rfc-editor.org/rfc/rfc4648.html). + * + * It is output as CBOR major type 3, a text string, with tag @ref + * CBOR_TAG_B64 indicating the text string is Base64 encoded. */ -void QCBOREncode_CloseBytes(QCBOREncodeContext *pCtx, size_t uAmount); - +static void +QCBOREncode_AddTB64Text(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC B64Text); -/** - @brief Add a binary UUID to the encoded output. +static void +QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); - @param[in] pCtx The encoding context to add the UUID to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Bytes Pointer and length of the binary UUID. +static void +QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); - 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. +/** + * @brief Add base64url encoded data to encoded output. + * + * @param[in] pCtx The encoding context to add the base64url to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] B64Text Pointer and length of the base64url encoded text. + * + * The text content is base64URL encoded text as per + * [RFC 4648] (https://www.rfc-editor.org/rfc/rfc4648.html). + * + * 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_AddTBinaryUUID(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); +static void +QCBOREncode_AddTB64URLText(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC B64Text); -static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); -static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); /** - @brief Add a positive big number to the encoded output. - - @param[in] pCtx The encoding context to add the big number to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Bytes Pointer and length of the big number. - - Big numbers are integers larger than 64-bits. Their format is - described in [RFC 8949] (https://tools.ietf.org/html/rfc8949). - - 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. + * @brief Add Perl Compatible Regular Expression. + * + * @param[in] pCtx Encoding context to add the regular expression to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @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_AddTPositiveBignum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, - UsefulBufC Bytes); +static void +QCBOREncode_AddTRegex(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC Regex); -static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC Regex); -static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC Regex); /** - @brief Add a negative big number to the encoded output. - - @param[in] pCtx The encoding context to add the big number to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Bytes Pointer and length of the big number. - - Big numbers are integers larger than 64-bits. Their format is - described in [RFC 8949] (https://tools.ietf.org/html/rfc8949). - - 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. + * @brief MIME encoded data to the encoded output. + * + * @param[in] pCtx The encoding context to add the MIME data to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] MIMEData Pointer and length of the MIME data. + * + * The text content is in MIME format per [RFC 2045] + * (https://www.rfc-editor.org/rfc/rfc2045.html) including the headers. + * + * It is output as CBOR major type 2, a binary string, with tag + * @ref CBOR_TAG_BINARY_MIME indicating the string is MIME data. This + * outputs tag 257, not tag 36, as it can carry any type of MIME + * binary, 7-bit, 8-bit, quoted-printable and base64 where tag 36 + * cannot. + * + * Previous versions of QCBOR, those before spiffy decode, output tag + * 36. Decoding supports both tag 36 and 257. (if the old behavior + * with tag 36 is needed, copy the inline functions below and change + * the tag number). + * + * See also QCBORDecode_GetMIMEMessage() and + * @ref QCBOR_TYPE_BINARY_MIME. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. */ -static void QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, - UsefulBufC Bytes); +static void +QCBOREncode_AddTMIMEData(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC MIMEData); -static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC MIMEData); -static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC MIMEData); -#ifndef QCBOR_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] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @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. + * @brief Add an RFC 3339 date string + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] szDate Null-terminated string with date to add. + * + * The string szDate should be in the form of + * [RFC 3339] (https://www.rfc-editor.org/rfc/rfc3339.html) as defined + * by section 3.3 in [RFC 4287] (https://www.rfc-editor.org/rfc/rfc4287.html). + * This is as described in section 3.4.1 in [RFC 8949] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section3.1.4). + * + * 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(). + * + * See also QCBOREncode_AddTDayString(). */ -static void QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); +static void +QCBOREncode_AddTDateString(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + const char *szDate); +static void +QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + const char *szDate); -static void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx, - int64_t nMantissa, - int64_t nBase10Exponent); +static void +QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + const char *szDate); -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] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Mantissa The mantissa. - @param[in] bIsNegative false if mantissa is positive, true if negative. - @param[in] nBase10Exponent The exponent. - - This is the same as QCBOREncode_AddDecimalFraction() except the - mantissa is a big number (See QCBOREncode_AddPositiveBignum()) - allowing for arbitrarily large precision. - - See @ref expAndMantissa for decoded representation. + * @brief Add a date-only string. + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] szDate Null-terminated string with date to add. + * + * This date format is described in + * [RFC 8943] (https://www.rfc-editor.org/rfc/rfc8943.html), but that mainly + * references RFC 3339. The string szDate must be in the forrm + * specified the ABNF for a full-date in + * [RFC 3339] (https://www.rfc-editor.org/rfc/rfc3339.html). Examples of this + * are "1985-04-12" and "1937-01-01". The time and the time zone are + * never included. + * + * 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(). + * + * See also QCBOREncode_AddTDateString(). */ -static void QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - - -static void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -/** - @brief Add a big floating-point number to the encoded output. - - @param[in] pCtx The encoding context to add the bigfloat to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] 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. +static void +QCBOREncode_AddTDaysString(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + const char *szDate); - 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). +static void +QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + const char *szDate); - CBOR Preferred encoding of the integers is used, thus they will be encoded - in the smallest number of bytes possible. +static void +QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + const char *szDate); - This can also be used to represent floating-point numbers in - environments that don't support IEEE 754. - See @ref expAndMantissa for decoded representation. +/** + * @brief Add a standard Boolean. + * + * @param[in] pCtx The encoding context to add the Boolean to. + * @param[in] b true or false from @c . + * + * Adds a Boolean value as CBOR major type 7. + * + * Error handling is the same as QCBOREncode_AddInt64(). */ -static void QCBOREncode_AddTBigFloat(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - +static void +QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); -static void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx, - int64_t nMantissa, - int64_t nBase2Exponent); +static void +QCBOREncode_AddBoolToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, bool b); -static void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nMantissa, - int64_t nBase2Exponent); +static void +QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); -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] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Mantissa The mantissa. - @param[in] bIsNegative false if mantissa is positive, true if negative. - @param[in] nBase2Exponent The exponent. - - This is the same as QCBOREncode_AddBigFloat() except the mantissa is - a big number (See QCBOREncode_AddPositiveBignum()) allowing for - arbitrary precision. - - See @ref expAndMantissa for decoded representation. + * @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_AddTBigFloatBigNum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - - -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_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] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] URI Pointer and length of the URI. +static void +QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); - The format of URI must be per [RFC 3986] - (https://tools.ietf.org/html/rfc3986). +static void +QCBOREncode_AddNULLToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - It is output as CBOR major type 3, a text string, with tag @ref - CBOR_TAG_URI indicating the text string is a URI. +static void +QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - A URI in a NULL-terminated string, @c szURI, can be easily added with - this code: - QCBOREncode_AddURI(pCtx, UsefulBuf_FromSZ(szURI)); +/** + * @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. + * + * "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_AddTURI(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC URI); - -static void QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC URI); - -static void QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC URI); - - -static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, - UsefulBufC URI); +static void +QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC URI); +static void +QCBOREncode_AddUndefToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC URI); +static void +QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add Base64-encoded text to encoded output. - - @param[in] pCtx The encoding context to add the base-64 text to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @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. + * @brief Add a simple value. + * + * @param[in] pCtx The encode context. + * @param[in] uNum The simple value. + * + * QCBOREncode_AddBool(), QCBOREncode_AddUndef() and + * QCBOREncode_AddNull() are preferred to this for the simple values + * defined in RFC 8949, but this can be used for them too. + * + * The main purpose of this is to add simple values beyond those in + * defined RFC 8949. Note that simple values must be registered with + * IANA. Those in the range of 0 to 19 must be standardized. Those in + * the range of 32 to 255 do not require a standard, but must be + * publically specified. There is no range of values for proprietary + * use. See + * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml */ -static void QCBOREncode_AddTB64Text(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - - -static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, - UsefulBufC B64Text); - -static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC B64Text); +static void +QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, const uint8_t uNum); -static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC B64Text); +static void +QCBOREncode_AddSimpleToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + const uint8_t uSimple); +static void +QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, + const int64_t nLabel, + const uint8_t uSimple); /** - @brief Add base64url encoded data to encoded output. - - @param[in] pCtx The encoding context to add the base64url to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @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. + * @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_AddTB64URLText(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - - -static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, - UsefulBufC B64Text); +static void +QCBOREncode_OpenArray(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC B64Text); +static void +QCBOREncode_OpenArrayInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC B64Text); +static void +QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add Perl Compatible Regular Expression. - - @param[in] pCtx The encoding context to add the regular expression to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @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. + * @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_AddTRegex(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Regex); - -static void QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Regex); - -static void QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Regex); - - -static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, - UsefulBufC Regex); +static void +QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); -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 data to the encoded output. - - @param[in] pCtx The encoding context to add the MIME data to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] MIMEData Pointer and length of the MIME data. - - The text content is in MIME format per [RFC 2045] - (https://tools.ietf.org/html/rfc2045) including the headers. - - It is output as CBOR major type 2, a binary string, with tag @ref - CBOR_TAG_BINARY_MIME indicating the string is MIME data. This - outputs tag 257, not tag 36, as it can carry any type of MIME binary, - 7-bit, 8-bit, quoted-printable and base64 where tag 36 cannot. - - Previous versions of QCBOR, those before spiffy decode, output tag - 36. Decoding supports both tag 36 and 257. (if the old behavior with - tag 36 is needed, copy the inline functions below and change the tag - number). - - See also QCBORDecode_GetMIMEMessage() and - @ref QCBOR_TYPE_BINARY_MIME. - - This does no translation of line endings. See QCBOREncode_AddText() - for a discussion of line endings in CBOR. + * @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 8949 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 8949] (https://www.rfc-editor.org/rfc/rfc8949.html) + * for a lot more information on creating maps. */ -static void QCBOREncode_AddTMIMEData(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - -static void QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - -static void QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - - -static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, - UsefulBufC MIMEData); +static void +QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC MIMEData); +static void +QCBOREncode_OpenMapInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC MIMEData); +static void +QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add an RFC 3339 date string - - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @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 3.4.1 in [RFC 8949] - (https://tools.ietf.org/html/rfc8949). - - 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(). - - See also QCBOREncode_AddTDayString(). + * @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_AddTDateString(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - const char *szDate); - -static void QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - const char *szDate); - -static void QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - const char *szDate); - - -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); +static void +QCBOREncode_CloseMap(QCBOREncodeContext *pCtx); /** - @brief Add a date-only string. - - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] szDate Null-terminated string with date to add. - - This date format is described in - [RFC 8943] (https://tools.ietf.org/html/rfc8943), but that mainly - references RFC 3339. The string szDate must be in the forrm - specified the ABNF for a full-date in - [RFC 3339] (https://tools.ietf.org/html/rfc3339). Examples of this - are "1985-04-12" and "1937-01-01". The time and the time zone are - never included. - - 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(). - - See also QCBOREncode_AddTDateString(). + * @brief Indicates that the next items added are in an indefinite length array. + * + * @param[in] pCtx The encoding context to open the array in. + * + * This is the same as QCBOREncode_OpenArray() except the array is + * indefinite length. + * + * This must be closed with QCBOREncode_CloseArrayIndefiniteLength(). */ static void -QCBOREncode_AddTDaysString(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - const char *szDate); +QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx); static void -QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - const char *szDate); +QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel); static void -QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - const char *szDate); +QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, + int64_t nLabel); /** - @brief Add a standard Boolean. - - @param[in] pCtx The encoding context to add the Boolean to. - @param[in] b true or false from @c . + * @brief Close an open indefinite length array. + * + * @param[in] pCtx The encoding context to close the array in. + * + * This is the same as QCBOREncode_CloseArray(), but the open array + * that is being close must be of indefinite length. + */ +static void +QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx); - Adds a Boolean value as CBOR major type 7. - Error handling is the same as QCBOREncode_AddInt64(). +/** + * @brief Indicates that the next items added are in an indefinite length map. + * + * @param[in] pCtx The encoding context to open the map in. + * + * This is the same as QCBOREncode_OpenMap() except the array is + * indefinite length. + * + * This must be closed with QCBOREncode_CloseMapIndefiniteLength(). */ -static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); +static void +QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx); + +static void +QCBOREncode_OpenMapIndefiniteLengthInMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel); -static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); +static void +QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, + int64_t nLabel); -static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); /** - @brief Add a NULL to the encoded output. + * @brief Close an open indefinite length map. + * + * @param[in] pCtx The encoding context to close the map in. + * + * This is the same as QCBOREncode_CloseMap(), but the open map that + * is being close must be of indefinite length. + */ +static void +QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx); - @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(). +/** + * @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 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html) implementation. The + * wrapping byte string is taken as input by the hash function (which + * is why it is returned by QCBOREncode_CloseBstrWrap2()). It is also + * easy to recover on decoding with standard CBOR decoders. + * + * 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. + * + * CBOR by nature must be decoded item by item in order from the + * start. By wrapping some CBOR in a byte string, the decoding of + * that wrapped CBOR can be skipped. This is another use of wrapping, + * perhaps because the CBOR is large and deeply nested. Perhaps APIs + * for handling one defined CBOR message that is being embedded in + * another only take input as a byte string. Perhaps the desire is to + * be able to decode the out layer even in the wrapped has errors. */ -static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); +static void +QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); +static void +QCBOREncode_BstrWrapInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +static void +QCBOREncode_BstrWrapInMapN(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. + * @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 9052, COSE] (https://www.rfc-editor.org/rfc/rfc9052.html) + * 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); - Note that this value will not translate to JSON. +static void +QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); - 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(). +/** + * @brief Cancel byte string wrapping. + * + * @param[in] pCtx The encoding context. + * + * This cancels QCBOREncode_BstrWrap() making the encoding as if it + * were never called. + * + * WARNING: This does not work on QCBOREncode_BstrWrapInMapSZ() + * or QCBOREncode_BstrWrapInMapN() and there is no error detection + * of an attempt at their use. + * + * This only works if nothing has been added into the wrapped byte + * string. If something has been added, this sets the error + * @ref QCBOR_ERR_CANNOT_CANCEL. */ -static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); - -static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +void +QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pCtx); /** - @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. + * @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. 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_OpenArray(QCBOREncodeContext *pCtx); +void +QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded); -static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); +static void +QCBOREncode_AddEncodedToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); -static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +static void +QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); /** - @brief Close an open array. - - @param[in] pCtx The encoding context to close the array in. + * @brief Get the encoded result. + * + * @param[in] pCtx The context to finish encoding with. + * @param[out] pEncodedCBOR Structure in which the pointer and length of + * the encoded CBOR is returned. + * + * @retval QCBOR_SUCCESS Encoded CBOR is returned. + * + * @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 + * + * On success, the pointer and length of the encoded CBOR are returned + * in @c *pEncodedCBOR. The pointer is the same pointer that was passed + * in to QCBOREncode_Init(). Note that it is not const when passed to + * QCBOREncode_Init(), but it is const when returned here. The length + * will be smaller than or equal to the length passed in when + * QCBOREncode_Init() as this is the length of the actual result, not + * the size of the buffer it was written to. + * + * If a @c NULL was passed for @c Storage.ptr when QCBOREncode_Init() + * was called, @c NULL will be returned here, but the length will be + * that of the CBOR that would have been encoded. + * + * 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(). See QCBOREncode_SubString() for a + * means to get the thus-far-encoded CBOR. + * + * QCBOREncode_GetErrorState() can be called to get the current + * error state in order to abort encoding early as an optimization, but + * calling it is is never required. + */ +QCBORError +QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); - 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. +/** + * @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); - 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. +/** + * @brief Indicate whether the output storage buffer is NULL. + * + * @param[in] pCtx The encoding context. + * + * @return 1 if the output buffer is @c NULL. + * + * As described in QCBOREncode_Init(), @c Storage.ptr may be give as @c NULL + * for output size calculation. This returns 1 when that is the true, and 0 if not. */ -static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); +static int +QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx); /** - @brief Indicates that the next items added are in a map. - - @param[in] pCtx The encoding context to open the map in. + * @brief Retrieve the storage buffer passed in to QCBOREncode_Init(). + * + * @param[in] pCtx The encoding context. + * + * @return The output storage buffer passed to QCBOREncode_Init(). + * + * This doesn't give any information about how much has been encoded + * or the error state. It just returns the exact @ref UsefulOutBuf given + * to QCBOREncode_Init(). + */ +static UsefulBuf +QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pCtx); - 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. +/** + * @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); - 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. +/** + * @brief Returns current end of encoded data. + * + * @param[in] pCtx The encoding context. + * + * @return Byte offset of end of encoded data. + * + * The purpose of this is to enable cryptographic hashing over a + * subpart of thus far CBOR-encoded data. Then perhaps a signature + * over the hashed CBOR is added to the encoded output. There is + * nothing specific to hashing or signing in this, so this can be used + * for other too. + * + * Call this to get the offset of the start of the encoded + * to-be-hashed CBOR items, then call QCBOREncode_SubString(). + * QCBOREncode_Tell() can also be called twice, first to get the + * offset of the start and second for the offset of the end. Those + * offsets can be applied to the output storage buffer. + * + * This will return successfully even if the encoder is in the error + * state. + * + * WARNING: All definite-length arrays and maps opened before the + * first call to QCBOREncode_Tell() must not be closed until the + * substring is obtained and processed. Similarly, every + * definite-length array or map opened after the first call to + * QCBOREncode_Tell() must be closed before the substring is obtained + * and processed. The same applies for opened byte strings. There is + * no detection of these errors. This occurs because QCBOR goes back + * and inserts the lengths of definite-length arrays and maps when + * they are closed. This insertion will make the offsets incorrect. + */ +static size_t +QCBOREncode_Tell(QCBOREncodeContext *pCtx); - 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 8949 uses the term "key" instead of "label". +/** + * @brief Get a substring of encoded CBOR for cryptographic hash + * + * @param[in] pCtx The encoding context. + * @param[in] uStart The start offset of substring. + * + * @return Pointer and length of of substring. + * + * @c uStart is obtained by calling QCBOREncode_Tell() before encoding + * the first item in the substring. Then encode some data items. Then + * call this. The substring returned contains the encoded data items. + * + * The substring may have deeply nested arrays and maps as long as any + * opened after the call to QCBOREncode_Tell() are closed before this + * is called. + * + * This will return @c NULLUsefulBufC if the encoder is in the error + * state or if @c uStart is beyond the end of the thus-far encoded + * data items. + * + * If @c uStart is 0, all the thus-far-encoded CBOR will be returned. + * Unlike QCBOREncode_Finish(), this will succeed even if some arrays + * and maps are not closed. + * + * See important usage WARNING in QCBOREncode_Tell() + */ +UsefulBufC +QCBOREncode_SubString(QCBOREncodeContext *pCtx, const size_t uStart); - 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 8949] (https://tools.ietf.org/html/rfc8949) for a lot - more information on creating maps. +/** + * @brief 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 + * serialization. If this is 4, then even the + * values 0xffff and smaller will be encoded 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 + * @ref NULLUsefulBufC if the output buffer is too small. + * + * Callers do not 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 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. */ -static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); +UsefulBufC +QCBOREncode_EncodeHead(UsefulBuf Buffer, + uint8_t uMajorType, + uint8_t uMinLen, + uint64_t uNumber); -static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); -/** - @brief Close an open map. +/* ========================================================================= * + * BEGINNING OF DEPRECATED FUNCTIONS * + * * + * There is no plan to remove these in future versions. * + * They just have been replaced by something better. * + * ========================================================================= */ - @param[in] pCtx The encoding context to close the map in . +/* Use QCBOREncode_AddInt64ToMapSZ() instead */ +static void +QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nNum); - This closes a map opened by QCBOREncode_OpenMap(). It reduces nesting - level by one. +/* Use QCBOREncode_AddUInt64ToMapSZ() instead */ +static void +QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); - 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. +/* Use QCBOREncode_AddTextToMapSZ() instead */ +static void +QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - 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. +/* Use QCBOREncode_AddSZStringToMapSZ() instead */ +static void +QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - 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); +#ifndef USEFULBUF_DISABLE_ALL_FLOAT +/* Use QCBOREncode_AddDoubleToMapSZ() instead */ +static void +QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); +/* Use QCBOREncode_AddFloatToMapSZ() instead */ +static void +QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -/** - @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. The - wrapping byte string is taken as input by the hash function - (which is why it is returned by QCBOREncode_CloseBstrWrap2()). - It is also easy to recover on decoding with standard CBOR - decoders. - - 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. - - CBOR by nature must be decoded item by item in order from the start. - By wrapping some CBOR in a byte string, the decoding of that wrapped - CBOR can be skipped. This is another use of wrapping, perhaps - because the CBOR is large and deeply nested. Perhaps APIs for - handling one defined CBOR message that is being embedded in another - only take input as a byte string. Perhaps the desire is to be able - to decode the out layer even in the wrapped has errors. - */ -static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); +/* Use QCBOREncode_AddDoubleNoPreferredToMapSZ() instead */ +static void +QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); + +/* Use QCBOREncode_AddFloatNoPreferredToMapSZ() instead */ +static void +QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ -static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); +/* Use QCBOREncode_AddTDateEpoch() instead */ +static void +QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t nDate); -static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +/* Use QCBOREncode_AddTDateEpochToMapSZ() instead */ +static void +QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nDate); +/* Use QCBOREncode_AddTDateEpochToMapN() instead */ +static void +QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t nDate); -/** - @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); +/* Use QCBOREncode_AddBytesToMapSZ() instead */ +static void +QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); +/* Use QCBOREncode_AddTBinaryUUID() instead */ +static void +QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); +/* Use QCBOREncode_AddTBinaryUUIDToMapSZ() instead */ +static void +QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -/** - * @brief Cancel byte string wrapping. - * - * @param[in] pCtx The encoding context. - * - * This cancels QCBOREncode_BstrWrap() making tghe encoding as if it - * were never called. - * - * WARNING: This does not work on QCBOREncode_BstrWrapInMap() - * or QCBOREncode_BstrWrapInMapN() and there is no error detection - * of an attempt at their use. - * - * This only works if nothing has been added into the wrapped byte - * string. If something has been added, this sets the error - * @ref QCBOR_ERR_CANNOT_CANCEL. - */ -void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pCtx); +/* Use QCBOREncode_AddTBinaryUUIDToMapN() instead */ +static void +QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +/* Use QCBOREncode_AddTPositiveBignum() instead */ +static void +QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC BigNumber); -/** - @brief Add some already-encoded CBOR bytes. +/* QCBOREncode_AddTPositiveBignumToMapSZ() instead */ +static void +QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC BigNumber); - @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. +/* Use QCBOREncode_AddTPositiveBignumToMapN() instead */ +static void +QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC BigNumber); - 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. +/* Use QCBOREncode_AddTNegativeBignum() instead */ +static void +QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC BigNumber); - 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. +/* Use QCBOREncode_AddTNegativeBignumToMapSZ() instead */ +static void +QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC BigNumber); - 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); +/* Use QCBOREncode_AddTNegativeBignumToMapN() instead */ +static void +QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC BigNumber); -static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); -static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); +#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA +/* Use QCBOREncode_AddTDecimalFraction() instead */ +static void +QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx, + int64_t nMantissa, + int64_t nBase10Exponent); -/** - @brief Get the encoded result. +/* Use QCBOREncode_AddTDecimalFractionToMapSZ() instead */ +static void +QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + int64_t nMantissa, + int64_t nBase10Exponent); - @param[in] pCtx The context to finish encoding with. - @param[out] pEncodedCBOR Structure in which the pointer and length of the encoded - CBOR is returned. +/* Use QCBOREncode_AddTDecimalFractionToMapN() instead */ +static void +QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + int64_t nMantissa, + int64_t nBase10Exponent); - @retval QCBOR_SUCCESS Encoded CBOR is returned. +/* Use QCBOREncode_AddTDecimalFractionBigNum() instead */ +static void +QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); - @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error +/* Use QCBOREncode_AddTDecimalFractionBigNumToMapSZ() instead */ +static void +QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); - @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error +/* Use QCBOREncode_AddTDecimalFractionBigNumToMapN() instead */ +static void +QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); - @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error +/* Use QCBOREncode_AddTBigFloat() instead */ +static void +QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx, + int64_t nMantissa, + int64_t nBase2Exponent); - @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size +/* Use QCBOREncode_AddTBigFloatToMapSZ() instead */ +static void +QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + int64_t nMantissa, + int64_t nBase2Exponent); - @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size +/* Use QCBOREncode_AddTBigFloatToMapN() instead */ +static void +QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + int64_t nMantissa, + int64_t nBase2Exponent); - @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit +/* Use QCBOREncode_AddTBigFloatBigNum() instead */ +static void +QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit +/* Use QCBOREncode_AddTBigFloatBigNumToMapSZ() instead */ +static void +QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - On success, the pointer and length of the encoded CBOR are returned - in @c *pEncodedCBOR. The pointer is the same pointer that was passed - in to QCBOREncode_Init(). Note that it is not const when passed to - QCBOREncode_Init(), but it is const when returned here. The length - will be smaller than or equal to the length passed in when - QCBOREncode_Init() as this is the length of the actual result, not - the size of the buffer it was written to. +/* Use QCBOREncode_AddTBigFloatBigNumToMapN() instead */ +static void +QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); +#endif /* ! QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */ - If a @c NULL was passed for @c Storage.ptr when QCBOREncode_Init() - was called, @c NULL will be returned here, but the length will be - that of the CBOR that would have been encoded. +/* Use QCBOREncode_AddTURI() instead */ +static void +QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI); - 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. +/* Use QCBOREncode_AddTURIToMapSZ() instead */ +static void +QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI); - 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. +/* Use QCBOREncode_AddTURIToMapN() instead */ +static void +QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI); - 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. +/* Use QCBOREncode_AddTB64Text() instead */ +static void +QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - 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(). +/* Use QCBOREncode_AddTB64TextToMapSZ() instead */ +static void +QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); - 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. +/* Use QCBOREncode_AddTB64TextToMapN() instead */ +static void +QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); - 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. +/* Use QCBOREncode_AddTB64URLText() instead */ +static void +QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - This may be called multiple times. It will always return the same. It - can also be interleaved with calls to QCBOREncode_FinishGetSize(). +/* Use QCBOREncode_AddTB64URLTextToMapSZ() instead */ +static void +QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC B64Text); - QCBOREncode_GetErrorState() can be called to get the current - error state in order to abort encoding early as an optimization, but - calling it is is never required. - */ -QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); +/* Use QCBOREncode_AddTB64URLTextToMapN() instead */ +static void +QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC B64Text); +/* Use QCBOREncode_AddTRegex() instead */ +static void +QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex); -/** - @brief Get the encoded CBOR and error status. +/* Use QCBOREncode_AddTRegexToMapSZ() instead */ +static void +QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Regex); - @param[in] pCtx The context to finish encoding with. - @param[out] uEncodedLen The length of the encoded or potentially - encoded CBOR in bytes. +/* Use QCBOREncode_AddTRegexToMapN() instead */ +static void +QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Regex); - @return The same errors as QCBOREncode_Finish(). +/* Use QCBOREncode_AddTMIMEData() instead */ +static void +QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData); - This functions the same as QCBOREncode_Finish(), but only returns the - size of the encoded output. - */ -QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen); +/* Use QCBOREncode_AddTMIMEDataToMapSZ() instead */ +static void +QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC MIMEData); +/* Use QCBOREncode_AddTMIMEDataToMapN() instead */ +static void +QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC MIMEData); -/** - @brief Indicate whether output buffer is NULL or not. +/* Use QCBOREncode_AddTDateString() instead */ +static void +QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate); - @param[in] pCtx The encoding context. +/* Use QCBOREncode_AddTDateStringToMapSZ() instead */ +static void +QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + const char *szDate); - @return 1 if the output buffer is @c NULL. +/* Use QCBOREncode_AddTDateStringToMapN instead */ +static void +QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + const char *szDate); - 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); +/* Use QCBOREncode_AddBoolToMapSZ() instead */ +static void +QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); +/* Use QCBOREncode_AddNULLToMapSZ() instead */ +static void +QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); -/** - @brief Get the encoding error state. +/* Use QCBOREncode_AddUndefToMapSZ() instead */ +static void +QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); - @param[in] pCtx The encoding context. +/* Use QCBOREncode_AddSimpleToMapSZ instead */ +static void +QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + const uint8_t uSimple); - @return One of @ref QCBORError. See return values from - QCBOREncode_Finish() +/* Use QCBOREncode_OpenArrayInMapSZ() instead */ +static void +QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); - 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); +/* Use QCBOREncode_OpenMapInMapSZ() instead */ +static void +QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); +/* Use QCBOREncode_OpenArrayIndefiniteLengthInMapSZ() instead */ +static void +QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, + const char *szLabel); -/** - 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 - 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 - @ref NULLUsefulBufC if the output buffer is too small. - - Callers do not 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); +/* Use QCBOREncode_OpenMapIndefiniteLengthInMapSZ() instead */ +static void +QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, + const char *szLabel); +/* Use QCBOREncode_BstrWrapInMapSZ() instead */ +static void +QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); +/* Use QCBOREncode_AddEncodedToMapSZ() instead */ +static void +QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); -/* ========================================================================= - BEGINNING OF PRIVATE INLINE IMPLEMENTATION - ========================================================================= */ +/* ========================================================================= * + * END OF DEPRECATED FUNCTIONS * + * ========================================================================= */ -/** - @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); +/* ========================================================================= * + * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * + * ========================================================================= */ +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe, + const uint8_t uMajorType, + const uint64_t uArgument, + const uint8_t uMinLen); -/** - @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 +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pCtx, + uint8_t uMajorType, + UsefulBufC Bytes); - Call QCBOREncode_OpenArrayIndefiniteLength() or - QCBOREncode_OpenMapIndefiniteLength() instead of this. - */ -void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType); +/* Semi-private function for adding a double with preferred encoding. See qcbor_encode.c */ +void +QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum); -/** - @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. +/* Semi-private function for adding a float with preferred encoding. See qcbor_encode.c */ +void +QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum); - Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this. - */ -void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType); +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_OpenMapOrArray(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. +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, + uint8_t uMajorType); - Call QCBOREncode_CloseArrayIndefiniteLength() or - QCBOREncode_CloseMapIndefiniteLength() instead of this. - */ -void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, - uint8_t uMajorType); +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_CloseMapOrArray(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. +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, + uint8_t uMajorType); - This is used to add simple types like true and false. - Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), - QCBOREncode_AddUndef() instead of this. +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pCtx, + uint64_t uTag, + UsefulBufC BigNumMantissa, + bool bBigNumIsNegative, + int64_t nMantissa, + int64_t nExponent); - 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(). +/** + * @brief Semi-private method to add simple items and floating-point. + * + * @param[in] pMe The encoding context. + * @param[in] uMinLen Minimum encoding size for uNum. Usually 0. + * @param[in] uArgument The value to add. + * + * This is used to add simple types like true and false and float-point + * values, both of which are type 7. + * + * Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), + * QCBOREncode_AddUndef() QCBOREncode_AddDouble() instead of this. + * + * Error handling is the same as QCBOREncode_AddInt64(). */ -void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, uint8_t uMinLen, uint64_t uNum); +static inline void +QCBOREncode_Private_AddType7(QCBOREncodeContext *pMe, + const uint8_t uMinLen, + const uint64_t uArgument) +{ + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uArgument, uMinLen); +} /** - @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] bBigNumIsNegative This is @c true if the big number is negative. - @param[in] nMantissa The @c int64_t mantissa if it is not a big number. - @param[in] nExponent The exponent. - - This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or @ref - CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64, then - this outputs the "borrowed" content format. - - The tag content output by this is an array with two members, the - exponent and then the mantissa. The mantissa can be either a big - number or an @c int64_t. - - This implementation cannot output an exponent further from 0 than - @c INT64_MAX. - - To output a mantissa that is between INT64_MAX and UINT64_MAX from 0, - it must be as a big number. - - Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(), - QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum() - is called instead of this. + * @brief Semi-private method to add only the type and length of a byte string. + * + * @param[in] pCtx The context to initialize. + * @param[in] Bytes Pointer and length of the input data. + * + * This will be removed in QCBOR 2.0. It was never a public function. + * + * This is the same as QCBOREncode_AddBytes() except it only adds the + * CBOR encoding for the type and the length. It doesn't actually add + * the bytes. You can't actually produce correct CBOR with this and + * the rest of this API. It is only used for a special case where the + * valid CBOR is created manually by putting this type and length in + * and then adding the actual bytes. In particular, when only a hash + * of the encoded CBOR is needed, where the type and header are hashed + * separately and then the bytes is hashed. This makes it possible to + * implement COSE Sign1 with only one copy of the payload in the + * output buffer, rather than two, roughly cutting memory use in half. + * + * This is only used for this odd case, but this is a supported + * tested function for QCBOR 1.0. + * + * See also QCBOREncode_EncodeHead(). */ -void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pCtx, - uint64_t uTag, - UsefulBufC BigNumMantissa, - bool bBigNumIsNegative, - int64_t nMantissa, - int64_t nExponent); +static void +QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, + UsefulBufC Bytes); -/** - @brief Semi-private method to add only the type and length of a byte string. +static void +QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Bytes); - @param[in] pCtx The context to initialize. - @param[in] Bytes Pointer and length of the input data. +static void +QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Bytes); - 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. +/* Forward declaration */ +static void +QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString); - 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_AddInt64ToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const int64_t nNum) +{ + QCBOREncode_AddSZString(pMe, szLabel); + QCBOREncode_AddInt64(pMe, nNum); +} +static inline void +QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t nNum) +{ + QCBOREncode_AddInt64ToMapSZ(pMe, szLabel, nNum); +} +static inline void +QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const int64_t nNum) +{ + QCBOREncode_AddInt64(pMe, nLabel); + QCBOREncode_AddInt64(pMe, nNum); +} static inline void -QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t uNum) +QCBOREncode_AddUInt64(QCBOREncodeContext *pMe, const uint64_t uValue) { - // Use _AddBuffer() because _AddSZString() is defined below, not above - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); - QCBOREncode_AddInt64(pMe, uNum); + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0); } + static inline void -QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, int64_t uNum) +QCBOREncode_AddUInt64ToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint64_t uNum) { - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddInt64(pMe, uNum); + QCBOREncode_AddSZString(pMe, szLabel); + QCBOREncode_AddUInt64(pMe, uNum); } - static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, uint64_t uNum) { - // Use _AddBuffer() because _AddSZString() is defined below, not above - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); - QCBOREncode_AddUInt64(pMe, uNum); + QCBOREncode_AddUInt64ToMapSZ(pMe, szLabel, uNum); } static inline void -QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint64_t uNum) +QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint64_t uNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddUInt64(pMe, uNum); @@ -2237,20 +2724,30 @@ QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint64_t uN static inline void -QCBOREncode_AddText(QCBOREncodeContext *pMe, UsefulBufC Text) +QCBOREncode_AddText(QCBOREncodeContext *pMe, const UsefulBufC Text) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text); + QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text); } static inline void -QCBOREncode_AddTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Text) +QCBOREncode_AddTextToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Text) { QCBOREncode_AddText(pMe, UsefulBuf_FromSZ(szLabel)); QCBOREncode_AddText(pMe, Text); } static inline void -QCBOREncode_AddTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Text) +QCBOREncode_AddTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Text) +{ + QCBOREncode_AddTextToMapSZ(pMe, szLabel, Text); +} + +static inline void +QCBOREncode_AddTextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Text) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddText(pMe, Text); @@ -2264,82 +2761,184 @@ QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString) } static inline void -QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szString) +QCBOREncode_AddSZStringToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const char *szString) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddSZString(pMe, szString); } static inline void -QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, const char *szString) +QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szString) +{ + QCBOREncode_AddSZStringToMapSZ(pMe, szLabel, szString); +} + +static inline void +QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const char *szString) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddSZString(pMe, szString); } +static inline void +QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag) +{ + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0); +} + + + + #ifndef USEFULBUF_DISABLE_ALL_FLOAT + static inline void -QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pMe, const double dNum) +{ + QCBOREncode_Private_AddType7(pMe, + sizeof(uint64_t), + UsefulBufUtil_CopyDoubleToUint64(dNum)); +} + +static inline void +QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pMe, const float fNum) +{ + QCBOREncode_Private_AddType7(pMe, + sizeof(uint32_t), + UsefulBufUtil_CopyFloatToUint32(fNum)); +} + + +static inline void +QCBOREncode_AddDouble(QCBOREncodeContext *pMe, const double dNum) +{ +#ifndef QCBOR_DISABLE_PREFERRED_FLOAT + QCBOREncode_Private_AddPreferredDouble(pMe, dNum); +#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ + QCBOREncode_AddDoubleNoPreferred(pMe, dNum); +#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ +} + +static inline void +QCBOREncode_AddDoubleToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const double dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddDouble(pMe, dNum); } static inline void -QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pMe, int64_t nLabel, double dNum) +QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +{ + QCBOREncode_AddDoubleToMapSZ(pMe, szLabel, dNum); +} + +static inline void +QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const double dNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddDouble(pMe, dNum); } + +static inline void +QCBOREncode_AddFloat(QCBOREncodeContext *pMe, const float fNum) +{ +#ifndef QCBOR_DISABLE_PREFERRED_FLOAT + QCBOREncode_Private_AddPreferredFloat(pMe, fNum); +#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ + QCBOREncode_AddFloatNoPreferred(pMe, fNum); +#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ +} + static inline void -QCBOREncode_AddFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, float dNum) +QCBOREncode_AddFloatToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const float dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddFloat(pMe, dNum); } static inline void -QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pMe, int64_t nLabel, float fNum) +QCBOREncode_AddFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, float fNum) +{ + QCBOREncode_AddFloatToMapSZ(pMe, szLabel, fNum); +} + +static inline void +QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const float fNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddFloat(pMe, fNum); } static inline void -QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +QCBOREncode_AddDoubleNoPreferredToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const double dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddDoubleNoPreferred(pMe, dNum); } static inline void -QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pMe, int64_t nLabel, double dNum) +QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +{ + QCBOREncode_AddDoubleNoPreferredToMapSZ(pMe, szLabel, dNum); +} + +static inline void +QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const double dNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddDoubleNoPreferred(pMe, dNum); } static inline void -QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, float dNum) +QCBOREncode_AddFloatNoPreferredToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const float dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddFloatNoPreferred(pMe, dNum); } static inline void -QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pMe, int64_t nLabel, float dNum) +QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, float fNum) +{ + QCBOREncode_AddFloatNoPreferredToMapSZ(pMe, szLabel, fNum); +} + +static inline void +QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const float dNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddFloatNoPreferred(pMe, dNum); } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ + + static inline void -QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDate) +QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, + const uint8_t uTag, + const int64_t nDate) { if(uTag == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_EPOCH); @@ -2348,34 +2947,45 @@ QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDate) } static inline void -QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTag, int64_t nDate) +QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTag, + const int64_t nDate) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTDateEpoch(pMe, uTag, nDate); } static inline void -QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTag, int64_t nDate) +QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTag, + const int64_t nDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDateEpoch(pMe, uTag, nDate); } static inline void -QCBOREncode_AddDateEpoch(QCBOREncodeContext *pMe, int64_t nDate) +QCBOREncode_AddDateEpoch(QCBOREncodeContext *pMe, + const int64_t nDate) { QCBOREncode_AddTDateEpoch(pMe, QCBOR_ENCODE_AS_TAG, nDate); } static inline void -QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t nDate) +QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const int64_t nDate) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddDateEpoch(pMe, nDate); } static inline void -QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, int64_t nDate) +QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const int64_t nDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddDateEpoch(pMe, nDate); @@ -2383,7 +2993,9 @@ QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, int64_t static inline void -QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDays) +QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, + const uint8_t uTag, + const int64_t nDays) { if(uTag == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_EPOCH); @@ -2392,14 +3004,20 @@ QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDays) } static inline void -QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTag, int64_t nDays) +QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTag, + const int64_t nDays) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTDaysEpoch(pMe, uTag, nDays); } static inline void -QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTag, int64_t nDays) +QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTag, + const int64_t nDays) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDaysEpoch(pMe, uTag, nDays); @@ -2407,54 +3025,75 @@ QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t static inline void -QCBOREncode_AddBytes(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddBytes(QCBOREncodeContext *pMe, + const UsefulBufC Bytes) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); + QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); } static inline void -QCBOREncode_AddBytesToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddBytes(pMe, Bytes); } static inline void -QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddBytesToMapSZ(pMe, szLabel, Bytes); +} + +static inline void +QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddBytes(pMe, Bytes); } static inline void -QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pMe, const char *szLabel, UsefulBuf *pPlace) +QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + UsefulBuf *pPlace) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenBytes(pMe, pPlace); } static inline void -QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBuf *pPlace) +QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + UsefulBuf *pPlace) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenBytes(pMe, pPlace); } + static inline void -QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes); + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes.len, 0); } + static inline void -QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddBytesLenOnly(pMe, Bytes); } static inline void -QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddBytesLenOnly(pMe, Bytes); @@ -2462,7 +3101,9 @@ QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, int64_t nLabel, Usefu static inline void -QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_BIN_UUID); @@ -2473,41 +3114,53 @@ QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Use static inline void QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes) + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTBinaryUUID(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTBinaryUUID(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTBinaryUUID(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddTBinaryUUIDToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTBinaryUUIDToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTBinaryUUIDToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_POS_BIGNUM); @@ -2518,41 +3171,56 @@ QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, static inline void QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes) + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTPositiveBignumToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTPositiveBignumToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTPositiveBignumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTPositiveBignumToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_NEG_BIGNUM); @@ -2563,36 +3231,49 @@ QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, static inline void QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes) + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTNegativeBignumToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTNegativeBignumToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTNegativeBignumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTNegativeBignumToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } @@ -2601,9 +3282,9 @@ QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, Use static inline void QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase10Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2611,7 +3292,7 @@ QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, + QCBOREncode_Private_AddExpMantissa(pMe, uTag, NULLUsefulBufC, false, @@ -2622,59 +3303,76 @@ QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase10Exponent) { QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDecimalFraction(pMe, uTagRequirement, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFraction(pMe, + uTagRequirement, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase10Exponent) { QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDecimalFraction(pMe, uTagRequirement, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFraction(pMe, + uTagRequirement, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pMe, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nMantissa, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFraction(pMe, QCBOR_ENCODE_AS_TAG, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFraction(pMe, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pMe, const char *szLabel, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nMantissa, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFractionToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFractionToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nLabel, + const int64_t nMantissa, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFractionToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFractionToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2682,9 +3380,10 @@ QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, + QCBOREncode_Private_AddExpMantissa(pMe, uTag, - Mantissa, bIsNegative, + Mantissa, + bIsNegative, 0, nBase10Exponent); } @@ -2692,42 +3391,54 @@ QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDecimalFractionBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase10Exponent); + QCBOREncode_AddTDecimalFractionBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase10Exponent); } static inline void QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDecimalFractionBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase10Exponent); + QCBOREncode_AddTDecimalFractionBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pMe, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFractionBigNum(pMe, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase10Exponent); + QCBOREncode_AddTDecimalFractionBigNum(pMe, + QCBOR_ENCODE_AS_TAG, + Mantissa, + bIsNegative, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { QCBOREncode_AddTDecimalFractionBigNumToMapSZ(pMe, szLabel, @@ -2739,10 +3450,10 @@ QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const int64_t nLabel, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { QCBOREncode_AddTDecimalFractionBigNumToMapN(pMe, nLabel, @@ -2758,9 +3469,9 @@ QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTBigFloat(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase2Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2768,15 +3479,20 @@ QCBOREncode_AddTBigFloat(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, uTag, NULLUsefulBufC, false, nMantissa, nBase2Exponent); + QCBOREncode_Private_AddExpMantissa(pMe, + uTag, + NULLUsefulBufC, + false, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase2Exponent) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent); @@ -2784,10 +3500,10 @@ QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase2Exponent) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent); @@ -2795,38 +3511,49 @@ QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddBigFloat(QCBOREncodeContext *pMe, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nMantissa, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloat(pMe, QCBOR_ENCODE_AS_TAG, nMantissa, nBase2Exponent); + QCBOREncode_AddTBigFloat(pMe, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nMantissa, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase2Exponent); + QCBOREncode_AddTBigFloatToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nLabel, + const int64_t nMantissa, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase2Exponent); + QCBOREncode_AddTBigFloatToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2834,67 +3561,95 @@ QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, uTag, Mantissa, bIsNegative, 0, nBase2Exponent); + QCBOREncode_Private_AddExpMantissa(pMe, + uTag, + Mantissa, + bIsNegative, + 0, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTBigFloatBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTBigFloatBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pMe, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatBigNum(pMe, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNum(pMe, + QCBOR_ENCODE_AS_TAG, + Mantissa, bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pMe, const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatBigNumToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNumToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + Mantissa, + bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const int64_t nLabel, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatBigNumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNumToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Mantissa, + bIsNegative, + nBase2Exponent); } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ static inline void -QCBOREncode_AddTURI(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC URI) +QCBOREncode_AddTURI(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC URI) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_URI); @@ -2903,33 +3658,43 @@ QCBOREncode_AddTURI(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC } static inline void -QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC URI) +QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBufC URI) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTURI(pMe, uTagRequirement, URI); } static inline void -QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC URI) +QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC URI) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTURI(pMe, uTagRequirement, URI); } static inline void -QCBOREncode_AddURI(QCBOREncodeContext *pMe, UsefulBufC URI) +QCBOREncode_AddURI(QCBOREncodeContext *pMe, const UsefulBufC URI) { QCBOREncode_AddTURI(pMe, QCBOR_ENCODE_AS_TAG, URI); } static inline void -QCBOREncode_AddURIToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC URI) +QCBOREncode_AddURIToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC URI) { QCBOREncode_AddTURIToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, URI); } static inline void -QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC URI) +QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC URI) { QCBOREncode_AddTURIToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, URI); } @@ -2937,7 +3702,9 @@ QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC URI static inline void -QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_B64); @@ -2948,34 +3715,41 @@ QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Useful static inline void QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text) + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTB64Text(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTB64Text(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddB64Text(QCBOREncodeContext *pMe, UsefulBufC B64Text) +QCBOREncode_AddB64Text(QCBOREncodeContext *pMe, const UsefulBufC B64Text) { QCBOREncode_AddTB64Text(pMe, QCBOR_ENCODE_AS_TAG, B64Text); } static inline void -QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC B64Text) +QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC B64Text) { QCBOREncode_AddTB64TextToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, B64Text); } static inline void -QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC B64Text) +QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC B64Text) { QCBOREncode_AddTB64TextToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, B64Text); } @@ -2983,7 +3757,9 @@ QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC static inline void -QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_B64URL); @@ -2994,34 +3770,44 @@ QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Use static inline void QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text) + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTB64URLText(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTB64URLText(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddB64URLText(QCBOREncodeContext *pMe, UsefulBufC B64Text) +QCBOREncode_AddB64URLText(QCBOREncodeContext *pMe, const UsefulBufC B64Text) { QCBOREncode_AddTB64URLText(pMe, QCBOR_ENCODE_AS_TAG, B64Text); } static inline void -QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC B64Text) +QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC B64Text) { - QCBOREncode_AddTB64URLTextToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, B64Text); + QCBOREncode_AddTB64URLTextToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + B64Text); } static inline void -QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC B64Text) +QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC B64Text) { QCBOREncode_AddTB64URLTextToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, B64Text); } @@ -3029,7 +3815,9 @@ QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulB static inline void -QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_REGEX); @@ -3038,33 +3826,43 @@ QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBu } static inline void -QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTRegex(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTRegex(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddRegex(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddRegex(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTRegex(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddRegexToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddRegexToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddTRegexToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { QCBOREncode_AddTRegexToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); @@ -3072,7 +3870,9 @@ QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC B static inline void -QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC MIMEData) +QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC MIMEData) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_BINARY_MIME); @@ -3083,15 +3883,18 @@ QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Usefu static inline void QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData) + const uint8_t uTagRequirement, + const UsefulBufC MIMEData) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTMIMEData(pMe, uTagRequirement, MIMEData); } static inline void -QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC MIMEData) +QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC MIMEData) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTMIMEData(pMe, uTagRequirement, MIMEData); @@ -3104,20 +3907,26 @@ QCBOREncode_AddMIMEData(QCBOREncodeContext *pMe, UsefulBufC MIMEData) } static inline void -QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC MIMEData) +QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC MIMEData) { QCBOREncode_AddTMIMEDataToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, MIMEData); } static inline void -QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC MIMEData) +QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC MIMEData) { QCBOREncode_AddTMIMEDataToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, MIMEData); } static inline void -QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const char *szDate) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_STRING); @@ -3128,7 +3937,7 @@ QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, con static inline void QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, const char *szDate) { QCBOREncode_AddSZString(pMe, szLabel); @@ -3136,7 +3945,10 @@ QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pMe, } static inline void -QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const char *szDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDateString(pMe, uTagRequirement, szDate); @@ -3149,20 +3961,26 @@ QCBOREncode_AddDateString(QCBOREncodeContext *pMe, const char *szDate) } static inline void -QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szDate) +QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const char *szDate) { QCBOREncode_AddTDateStringToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, szDate); } static inline void -QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, const char *szDate) +QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const char *szDate) { QCBOREncode_AddTDateStringToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, szDate); } static inline void -QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const char *szDate) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_STRING); @@ -3173,7 +3991,7 @@ QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, con static inline void QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, const char *szDate) { QCBOREncode_AddSZString(pMe, szLabel); @@ -3181,29 +3999,51 @@ QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pMe, } static inline void -QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const char *szDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDaysString(pMe, uTagRequirement, szDate); } - static inline void -QCBOREncode_AddSimple(QCBOREncodeContext *pMe, uint64_t uNum) +QCBOREncode_AddSimple(QCBOREncodeContext *pMe, const uint8_t uNum) { - QCBOREncode_AddType7(pMe, 0, uNum); + /* This check often is optimized out because uNum is known at compile time. */ +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) { + pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED; + return; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + QCBOREncode_Private_AddType7(pMe, 0, uNum); } static inline void -QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uSimple) +QCBOREncode_AddSimpleToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uSimple) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddSimple(pMe, uSimple); } static inline void -QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, int nLabel, uint8_t uSimple) +QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uSimple) +{ + QCBOREncode_AddSimpleToMapSZ(pMe, szLabel, uSimple); +} + +static inline void +QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uSimple) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddSimple(pMe, uSimple); @@ -3211,7 +4051,7 @@ QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, int nLabel, uint8_t uSimple static inline void -QCBOREncode_AddBool(QCBOREncodeContext *pMe, bool b) +QCBOREncode_AddBool(QCBOREncodeContext *pMe, const bool b) { uint8_t uSimple = CBOR_SIMPLEV_FALSE; if(b) { @@ -3221,14 +4061,20 @@ QCBOREncode_AddBool(QCBOREncodeContext *pMe, bool b) } static inline void -QCBOREncode_AddBoolToMap(QCBOREncodeContext *pMe, const char *szLabel, bool b) +QCBOREncode_AddBoolToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, const bool b) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddBool(pMe, b); } static inline void -QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pMe, int64_t nLabel, bool b) +QCBOREncode_AddBoolToMap(QCBOREncodeContext *pMe, const char *szLabel, bool b) +{ + QCBOREncode_AddBoolToMapSZ(pMe, szLabel, b); +} + +static inline void +QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pMe, const int64_t nLabel, const bool b) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddBool(pMe, b); @@ -3242,14 +4088,20 @@ QCBOREncode_AddNULL(QCBOREncodeContext *pMe) } static inline void -QCBOREncode_AddNULLToMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_AddNULLToMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddNULL(pMe); } static inline void -QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_AddNULLToMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_AddNULLToMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddNULL(pMe); @@ -3263,14 +4115,20 @@ QCBOREncode_AddUndef(QCBOREncodeContext *pMe) } static inline void -QCBOREncode_AddUndefToMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_AddUndefToMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddUndef(pMe); } static inline void -QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddUndefToMapSZ(pCtx, szLabel); +} + +static inline void +QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddUndef(pMe); @@ -3280,18 +4138,25 @@ QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, int64_t nLabel) static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); } static inline void -QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenArrayInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenArray(pMe); } static inline void -QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_OpenArrayInMapSZ(pMe, szLabel); +} + + +static inline void +QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenArray(pMe); @@ -3300,25 +4165,31 @@ QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, int64_t nLabel) static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); + QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); } static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); } static inline void -QCBOREncode_OpenMapInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenMapInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenMap(pMe); } static inline void -QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenMapInMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_OpenMapInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenMap(pMe); @@ -3327,24 +4198,33 @@ QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, int64_t nLabel) static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); + QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); } static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); + QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); } static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(QCBOREncodeContext *pMe, + const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenArrayIndefiniteLength(pMe); } static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pMe, + const char *szLabel) +{ + QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, + const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenArrayIndefiniteLength(pMe); @@ -3353,25 +4233,34 @@ QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nL static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); + QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); } static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); + QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); } static inline void -QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenMapIndefiniteLengthInMapSZ(QCBOREncodeContext *pMe, + const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenMapIndefiniteLength(pMe); } static inline void -QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pMe, + const char *szLabel) +{ + QCBOREncode_OpenMapIndefiniteLengthInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, + const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenMapIndefiniteLength(pMe); @@ -3380,25 +4269,31 @@ QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nLabe static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); + QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); } static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_BYTE_STRING); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_BYTE_STRING); } static inline void -QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_BstrWrapInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_BstrWrap(pMe); } static inline void -QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_BstrWrapInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_BstrWrap(pMe); @@ -3411,21 +4306,26 @@ QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pMe, UsefulBufC *pWrappedCBOR) } + static inline void -QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, UsefulBufC Encoded) +QCBOREncode_AddEncodedToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Encoded) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_RAW, Encoded); + QCBOREncode_AddSZString(pMe, szLabel); + QCBOREncode_AddEncoded(pMe, Encoded); } static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Encoded) { - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddEncoded(pMe, Encoded); + QCBOREncode_AddEncodedToMapSZ(pMe, szLabel, Encoded); } static inline void -QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Encoded) +QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Encoded) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddEncoded(pMe, Encoded); @@ -3438,28 +4338,44 @@ QCBOREncode_IsBufferNULL(QCBOREncodeContext *pMe) return UsefulOutBuf_IsBufferNULL(&(pMe->OutBuf)); } + +static inline UsefulBuf +QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pMe) +{ + return UsefulOutBuf_RetrieveOutputStorage(&(pMe->OutBuf)); +} + + static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pMe) { if(UsefulOutBuf_GetError(&(pMe->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. + /* 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. + */ pMe->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. + /* QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is + * OK. Once the caller fixes this, they'll be unmasked. + */ } return (QCBORError)pMe->uError; } -/* ======================================================================== - END OF PRIVATE INLINE IMPLEMENTATION - ======================================================================== */ +static inline size_t +QCBOREncode_Tell(QCBOREncodeContext *pMe) +{ + return UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); +} + +/* ======================================================================== * + * END OF PRIVATE INLINE IMPLEMENTATION * + * ======================================================================== */ #ifdef __cplusplus } diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_private.h b/3rdparty/exported/QCBOR/qcbor/qcbor_private.h index 9a2a720fe6d6..a061809cc508 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_private.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_private.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2021, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - =============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * 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 @@ -38,6 +38,7 @@ #include #include "UsefulBuf.h" +#include "qcbor/qcbor_common.h" #ifdef __cplusplus @@ -48,56 +49,52 @@ extern "C" { #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 tested 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. +/* This was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, + * but this is inconsistent with all the other QCBOR_DISABLE_ + * #defines, so the name was changed and this was added for backwards + * compatibility */ -#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) - +#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA +#define QCBOR_DISABLE_EXP_AND_MANTISSA +#endif -/* The number of tags that are 16-bit or larger that can be handled - in a decode. +/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define + * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT */ -#define QCBOR_NUM_MAPPED_TAGS 4 +#ifdef USEFULBUF_DISABLE_ALL_FLOAT +#ifndef QCBOR_DISABLE_FLOAT_HW_USE +#define QCBOR_DISABLE_FLOAT_HW_USE +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ +#ifndef QCBOR_DISABLE_PREFERRED_FLOAT +#define QCBOR_DISABLE_PREFERRED_FLOAT +#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ -/* The number of tags (of any size) recorded for an individual item. */ -#define QCBOR_MAX_TAGS_PER_ITEM1 4 /* - Convenience macro for selecting the proper return value in case floating - point feature(s) are disabled. - - The macros: - - FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should - result error, and all other cases should return - 'x'. - - The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all floating - point is disabled. - - FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float - results in error, and all other cases should - return 'x'. - FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating - point results in error, and all other cases - should return 'x'. - FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled - preferred float or disabling - hardware floating point results in - error, and all other cases should - return 'x'. + * Convenience macro for selecting the proper return value in case floating + * point feature(s) are disabled. + * + * The macros: + * + * FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should + * result error, and all other cases should return + * 'x'. + * + * The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all + * floating point is disabled. + * + * FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float + * results in error, and all other cases should + * return 'x'. + * FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating + * point results in error, and all other cases + * should return 'x'. + * FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled + * preferred float or disabling + * hardware floating point results in + * error, and all other cases should + * return 'x'. */ #ifdef USEFULBUF_DISABLE_ALL_FLOAT #define FLOAT_ERR_CODE_NO_FLOAT(x) QCBOR_ERR_ALL_FLOAT_DISABLED @@ -126,103 +123,163 @@ extern "C" { /* - PRIVATE DATA STRUCTURE + * 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 - 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. +/* + * 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 + + +/* + * 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 + + +/* The largest offset to the start of an array or map. It is slightly + * less than UINT32_MAX so the error condition can be tested 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) + - 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 -*/ +/* The number of tags that are 16-bit or larger that can be handled + * in a decode. + */ +#define QCBOR_NUM_MAPPED_TAGS 4 + +/* The number of tags (of any size) recorded for an individual item. */ +#define QCBOR_MAX_TAGS_PER_ITEM1 4 + + + + +/* + * 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 + /* 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 + /* See QCBOREncode_OpenMapOrArray() for details on how this works */ + uint32_t uStart; /* uStart is the 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_NESTING+1], /* stored state for 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 -*/ + * 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 */ + 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 in qcbor_decode.c - form an "object" that does the work for arrays and maps. All access - to this structure is through DecodeNesting_Xxx() functions. - - 64-bit machine size - 128 = 16 * 8 for the two unions - 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment - 16 = 16 bytes for two pointers - 208 TOTAL - - 32-bit machine size is 200 bytes + * PRIVATE DATA STRUCTURE + * + * Holds the data for array and map nesting for decoding work. This + * structure and the DecodeNesting_Xxx() functions in qcbor_decode.c + * form an "object" that does the work for arrays and maps. All access + * to this structure is through DecodeNesting_Xxx() functions. + * + * 64-bit machine size + * 128 = 16 * 8 for the two unions + * 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment + * 16 = 16 bytes for two pointers + * 208 TOTAL + * + * 32-bit machine size is 200 bytes */ typedef struct __QCBORDecodeNesting { - // PRIVATE DATA STRUCTURE + /* PRIVATE DATA STRUCTURE */ struct nesting_decode_level { /* - This keeps tracking info for each nesting level. There are two - main types of levels: - 1) Byte count tracking. This is for the top level input CBOR - which might be a single item or a CBOR sequence and byte - string wrapped encoded CBOR. - 2) Item tracking. This is for maps and arrays. - - uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and - QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY - for 2). - - Item tracking is either for definite or indefinite-length - maps/arrays. For definite lengths, the total count and items - unconsumed are tracked. For indefinite-length, uTotalCount is - QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and there - is no per-item count of members. For indefinite-length maps and - arrays, uCountCursor is UINT16_MAX if not consumed and zero if - it is consumed in the pre-order traversal. Additionally, if - entered in bounded mode, uCountCursor is - QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate it is empty. - - This also records whether a level is bounded or not. All - byte-count tracked levels (the top-level sequence and - bstr-wrapped CBOR) are bounded. Maps and arrays may or may not - be bounded. They are bounded if they were Entered() and not if - they were traversed with GetNext(). They are marked as bounded - by uStartOffset not being UINT32_MAX. + * This keeps tracking info for each nesting level. There are two + * main types of levels: + * 1) Byte count tracking. This is for the top level input CBOR + * which might be a single item or a CBOR sequence and byte + * string wrapped encoded CBOR. + * 2) Item count tracking. This is for maps and arrays. + * + * uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and + * QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY + * for 2). + * + * Item count tracking is either for definite or indefinite-length + * maps/arrays. For definite lengths, the total count and items + * unconsumed are tracked. For indefinite-length, uTotalCount is + * QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and + * there is no per-item count of members. For indefinite-length + * maps and arrays, uCountCursor is UINT16_MAX if not consumed + * and zero if it is consumed in the pre-order + * traversal. Additionally, if entered in bounded mode, + * uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate + * it is empty. + * + * This also records whether a level is bounded or not. All + * byte-count tracked levels (the top-level sequence and + * bstr-wrapped CBOR) are bounded implicitly. Maps and arrays + * may or may not be bounded. They are bounded if they were + * Entered() and not if they were traversed with GetNext(). They + * are marked as bounded by uStartOffset not being @c UINT32_MAX. */ /* - If uLevelType can put in a separately indexed array, the union/ - struct will be 8 bytes rather than 9 and a lot of wasted - padding for alignment will be saved. + * If uLevelType can put in a separately indexed array, the + * union/struct will be 8 bytes rather than 9 and a lot of + * wasted padding for alignment will be saved. */ uint8_t uLevelType; union { @@ -232,6 +289,8 @@ typedef struct __QCBORDecodeNesting { uint16_t uCountTotal; uint16_t uCountCursor; #define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX + /* The start of the array or map in bounded mode so + * the input can be rewound for GetInMapXx() by label. */ uint32_t uStartOffset; } ma; /* for maps and arrays */ struct { @@ -242,88 +301,87 @@ typedef struct __QCBORDecodeNesting { uint32_t uBstrStartOffset; } bs; /* for top-level sequence and bstr-wrapped CBOR */ } u; - } pLevels[QCBOR_MAX_ARRAY_NESTING1+1], + } pLevels[QCBOR_MAX_ARRAY_NESTING+1], *pCurrent, *pCurrentBounded; /* - pCurrent is for item-by-item pre-order traversal. - - pCurrentBounded points to the current bounding level or is NULL if - there isn't one. - - pCurrent must always be below pCurrentBounded as the pre-order - traversal is always bounded by the bounding level. - - When a bounded level is entered, the pre-order traversal is set to - the first item in the bounded level. When a bounded level is - exited, the pre-order traversl is set to the next item after the - map, array or bstr. This may be more than one level up, or even - the end of the input CBOR. + * pCurrent is for item-by-item pre-order traversal. + * + * pCurrentBounded points to the current bounding level or is NULL + * if there isn't one. + * + * pCurrent must always be below pCurrentBounded as the pre-order + * traversal is always bounded by the bounding level. + * + * When a bounded level is entered, the pre-order traversal is set + * to the first item in the bounded level. When a bounded level is + * exited, the pre-order traversl is set to the next item after the + * map, array or bstr. This may be more than one level up, or even + * the end of the input CBOR. */ } QCBORDecodeNesting; typedef struct { - // PRIVATE DATA STRUCTURE + /* PRIVATE DATA STRUCTURE */ void *pAllocateCxt; UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize); } QCBORInternalAllocator; /* - 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 + * 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 + /* PRIVATE DATA STRUCTURE */ UsefulInputBuf InBuf; - QCBORDecodeNesting nesting; - - // If a string allocator is configured for indefinite-length - // strings, it is configured here. + /* If a string allocator is configured for indefinite-length + * strings, it is configured here. + */ QCBORInternalAllocator 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. + /* 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; - // A cached offset to the end of the current map - // 0 if no value is cached. + /* A cached offset to the end of the current map 0 if no value is + * cached. + */ #define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX uint32_t uMapEndOffsetCache; uint8_t uDecodeMode; uint8_t bStringAllocateAll; - uint8_t uLastError; // QCBORError stuffed into a uint8_t + uint8_t uLastError; /* QCBORError stuffed into a uint8_t */ /* See MapTagNumber() for description of how tags are mapped. */ uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS]; uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1]; - }; -// 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_OPEN_BSTR 12 + +/* Used internally in the impementation here Must not conflict with + * any of the official CBOR types + */ +#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 +#define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12 -// Add this to types to indicate they are to be encoded as indefinite lengths +/* Add this to types to indicate they are to be encoded as indefinite lengths */ #define QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 0x80 #define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN \ CBOR_MAJOR_TYPE_ARRAY + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h b/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h index 0faddc386307..48e3bbd2e510 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h @@ -1,15 +1,15 @@ -/*============================================================================ - qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding. - - Copyright (c) 2020-2021, Laurence Lundblade. All rights reserved. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Forked from qcbor_decode.h on 7/23/2020 - ============================================================================*/ +/* ========================================================================== + * qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding. + * + * Copyright (c) 2020-2024, Laurence Lundblade. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Forked from qcbor_decode.h on 7/23/2020 + * ========================================================================== */ #ifndef qcbor_spiffy_decode_h #define qcbor_spiffy_decode_h @@ -26,1725 +26,2189 @@ extern "C" { /** - @file qcbor_spiffy_decode.h - - @anchor SpiffyDecode - # Spiffy Decode - - This section discusses spiffy decoding assuming familiarity with - the general description of decoding in the - @ref BasicDecode section. - - Spiffy decode is extra decode features over and above the @ref - BasicDecode features that generally are easier to use, mirror the - encoding functions better and can result in smaller code size for - larger and more complex CBOR protocols. In particular, spiffy decode - facilitates getting the next data item of a specific type, setting an - error if it is not of that type. It facilitates explicitly entering - and exiting arrays and maps. It facilates fetching items by label - from a map including duplicate label detection. - - Encoded CBOR can be viewed to have a tree structure where the leaf - nodes are non-aggregate types like integers and strings and the - intermediate nodes are either arrays or maps. Fundamentally, all - decoding is a pre-order traversal of the tree. Calling - QCBORDecode_GetNext() repeatedly will perform this. - - This pre-order traversal gives natural decoding of arrays where the - array members are taken in order, but does not give natural decoding - of maps where access by label is usually preferred. Using the - QCBORDecode_EnterMap() and QCBORDecode_GetXxxxInMapX() methods like - QCBORDecode_GetInt64InMapN(), map items can be accessed by - label. QCBORDecode_EnterMap() bounds decoding to a particular - map. QCBORDecode_GetXxxxInMapX() methods allows decoding the item of - a particular label in the particular map. This can be used with - nested maps by using QCBORDecode_EnterMapFromMapX(). - - When QCBORDecode_EnterMap() is called, pre-order traversal continues - to work. There is a cursor that is run over the tree with calls to - QCBORDecode_GetNext(). This can be intermixed with calls to - QCBORDecode_GetXxxxInMapX(). The pre-order traversal is limited just - to the map entered. Attempts to QCBORDecode_GetNext() beyond the end - of the map will give the @ref QCBOR_ERR_NO_MORE_ITEMS error. - - There is also QCBORDecode_EnterArray() to decode arrays. It will - narrow the traversal to the extent of the array entered. - - All the QCBORDecode_GetXxxxInMapX() methods support duplicate label - detection and will result in an error if the map has duplicate - labels. - - All the QCBORDecode_GetXxxxInMapX() methods are implemented by - performing the pre-order traversal of the map to find the labeled - item everytime it is called. It doesn't build up a hash table, a - binary search tree or some other efficiently searchable structure - internally. For simple trees this is fine and for high-speed CPUs - this is fine, but for complex trees on slow CPUs, it may have - performance issues (these have not be quantified yet). One way ease - this is to use QCBORDecode_GetItemsInMap() which allows decoding of a - list of items expected in an map in one traveral. - - @anchor Tag-Usage - ## Tag Usage - - Data types beyond the basic CBOR types of numbers, strings, maps and - arrays are called tags. The main registry of these new types is in - the IANA CBOR tags registry. These new types may be simple such a - number that is to be interpreted as a date, or of moderate complexity - such as defining a decimal fraction that is an array containing a - mantissa and exponent, or complex such as format for signing and - encryption. - - When a tag occurs in a protocol it is encoded as an integer tag - number plus the content of the tag. - - The content format of a tag may also be "borrowed". For example, a - protocol definition may say that a particular data item is an epoch - date just like tag 1, but not actually tag 1. In practice the - difference is the presence or absence of the integer tag number in - the encoded CBOR. - - The decoding functions for these new types takes a tag requirement - parameter to say whether the item is a tag, is just borrowing the - content format and is not a tag, or whether either is OK. - - If the parameter indicates the item must be a tag (@ref - QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is - set if it is not one of the expected tag types. To decode correctly - the contents of the tag must also be of the correct type. For - example, to decode an epoch date tag the content must be an integer - or floating-point value. - - If the parameter indicates it should not be a tag - (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then - @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the - encoded CBOR is not what is expected. In the example of an epoch - date, the data type must be an integer or floating-point value. This - is the case where the content format of a tag is borrowed. - - The parameter can also indicate that either a tag or no tag is - allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol - design should however be clear and choose one or the other and not - need this option. This is a way to implement "be liberal in what you - accept", however these days that is less in favor. See - https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. - - Map searching works with indefinite length strings. A string - allocator must be set up the same as for any handling of indefinite - length strings. However, It currently over-allocates memory from the - string pool and thus requires a much larger string pool than it - should. The over-allocation happens every time a map is searched by - label. (This may be corrected in the future). -*/ + * @file qcbor_spiffy_decode.h + * + * @anchor SpiffyDecode + * # Spiffy Decode + * + * This section discusses spiffy decoding assuming familiarity with + * the general description of decoding in the + * @ref BasicDecode section. + * + * Spiffy decode is extra decode features over and above the @ref + * BasicDecode features that generally are easier to use, mirror the + * encoding functions better and can result in smaller code size for + * larger and more complex CBOR protocols. In particular, spiffy + * decode facilitates getting the next data item of a specific type, + * setting an error if it is not of that type. It facilitates + * explicitly entering and exiting arrays and maps. It facilates + * fetching items by label from a map including duplicate label + * detection. + * + * Encoded CBOR can be viewed to have a tree structure where the leaf + * nodes are non-aggregate types like integers and strings and the + * intermediate nodes are either arrays or maps. Fundamentally, all + * decoding is a pre-order traversal of the tree. Calling + * QCBORDecode_GetNext() repeatedly will perform this. + * + * This pre-order traversal gives natural decoding of arrays where the + * array members are taken in order, but does not give natural decoding + * of maps where access by label is usually preferred. Using the + * QCBORDecode_EnterMap() and QCBORDecode_GetXxxxInMapX() methods like + * QCBORDecode_GetInt64InMapN(), map items can be accessed by + * label. QCBORDecode_EnterMap() bounds decoding to a particular + * map. QCBORDecode_GetXxxxInMapX() methods allows decoding the item of + * a particular label in the particular map. This can be used with + * nested maps by using QCBORDecode_EnterMapFromMapX(). + * + * When QCBORDecode_EnterMap() is called, pre-order traversal + * continues to work. There is a cursor that is run over the tree with + * calls to QCBORDecode_GetNext(). Attempts to use + * QCBORDecode_GetNext() beyond the end of the map will give the + * @ref QCBOR_ERR_NO_MORE_ITEMS error. + * + * Use of the traversal cursor can be mixed with the fetching of items + * by label with some caveats. When a non-aggregate item like an + * integer or string is fetched by label, the traversal cursor is + * unaffected so the mixing can be done freely. When an aggregate + * item is entered by label (by QCBORDecode_EnterMapFromMapN() and + * similar), the traversal cursor is set to the item after the + * subordinate aggregate item when it is exited. This will not matter + * to many use cases. Use cases that mix can be sure to separate + * traversal by the cursor from fetching by label. + * QCBORDecode_Rewind() may be useful to reset the traversal cursor + * after fetching aggregate items by label. + * + * (This behavior was incorrectly documented in QCBOR 1.2 and prior + * which described aggregate and non-aggregate as behaving the same. + * Rather than changing to make aggregate and non-aggregate + * consistent, the behavior is retained and documented because 1) it + * is usable as is, 2) a change would bring backward compatibility + * issues, 3) the change would increase the decode context size and + * code size. In QCBOR 1.3 test cases were added to validate the + * behavior. No problems were uncovered.) + * + * QCBORDecode_EnterArray() can be used to narrow the traversal to the + * extent of the array. + * + * All the QCBORDecode_GetXxxxInMapX() methods support duplicate label + * detection and will result in an error if the map has duplicate + * labels. + * + * All the QCBORDecode_GetXxxxInMapX() methods are implemented by + * performing the pre-order traversal of the map to find the labeled + * item everytime it is called. It doesn't build up a hash table, a + * binary search tree or some other efficiently searchable structure + * internally. For small maps this is fine and for high-speed CPUs + * this is fine, but for large, perhaps deeply nested, maps on slow + * CPUs, it may have performance issues (these have not be + * quantified). One way ease this is to use + * QCBORDecode_GetItemsInMap() which allows decoding of a list of + * items expected in an map in one traveral. + * + * @anchor Tag-Usage + * ## Tag Usage + * + * Data types beyond the basic CBOR types of numbers, strings, maps and + * arrays are called tags. The main registry of these new types is in + * the IANA CBOR tags registry. These new types may be simple such a + * number that is to be interpreted as a date, or of moderate complexity + * such as defining a decimal fraction that is an array containing a + * mantissa and exponent, or complex such as format for signing and + * encryption. + * + * When a tag occurs in a protocol it is encoded as an integer tag + * number plus the content of the tag. + * + * The content format of a tag may also be "borrowed". For example, a + * protocol definition may say that a particular data item is an epoch + * date just like tag 1, but not actually tag 1. In practice the + * difference is the presence or absence of the integer tag number in + * the encoded CBOR. + * + * The decoding functions for these new types takes a tag requirement + * parameter to say whether the item is a tag, is just borrowing the + * content format and is not a tag, or whether either is OK. + * + * If the parameter indicates the item must be a tag (@ref + * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is + * set if it is not one of the expected tag types. To decode correctly + * the contents of the tag must also be of the correct type. For + * example, to decode an epoch date tag the content must be an integer + * or floating-point value. + * + * If the parameter indicates it should not be a tag + * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then + * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the + * encoded CBOR is not what is expected. In the example of an epoch + * date, the data type must be an integer or floating-point value. This + * is the case where the content format of a tag is borrowed. + * + * The parameter can also indicate that either a tag or no tag is + * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol + * design should however be clear and choose one or the other and not + * need this option. This is a way to implement "be liberal in what you + * accept", however these days that is less in favor. See + * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. + * + * Map searching works with indefinite length strings. A string + * allocator must be set up the same as for any handling of indefinite + * length strings. However, It currently over-allocates memory from the + * string pool and thus requires a much larger string pool than it + * should. The over-allocation happens every time a map is searched by + * label. (This may be corrected in the future). + */ /** The data item must be a tag of the expected type. It is an error - if it is not. For example when calling QCBORDecode_GetEpochDate(), - the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. - See @ref Tag-Usage. */ + * if it is not. For example when calling QCBORDecode_GetEpochDate(), + * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See + * @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_TAG 0 /** The data item must be of the type expected for content data type - being fetched. It is an error if it is not. For example, when - calling QCBORDecode_GetEpochDate() and it must not be an @ref - CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ + * being fetched. It is an error if it is not. For example, when + * calling QCBORDecode_GetEpochDate() and it must not be an @ref + * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1 /** Either of the above two are allowed. This allows implementation of - being liberal in what you receive, but it is better if CBOR-based - protocols pick one and stick to and not required the reciever to - take either. See @ref Tag-Usage. */ + * being liberal in what you receive, but it is better if CBOR-based + * protocols pick one and stick to and not required the reciever to + * take either. See @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2 /** Add this into the above value if other tags not processed by QCBOR - are to be allowed to surround the data item. See @ref Tag-Usage. */ + * are to be allowed to surround the data item. See @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80 /** Conversion will proceed if the CBOR item to be decoded is an - integer or either type 0 (unsigned) or type 1 (negative). */ + * integer or either type 0 (unsigned) or type 1 (negative). */ #define QCBOR_CONVERT_TYPE_XINT64 0x01 /** Conversion will proceed if the CBOR item to be decoded is either - double, single or half-precision floating-point (major type 7). */ + * double, single or half-precision floating-point (major type 7). */ #define QCBOR_CONVERT_TYPE_FLOAT 0x02 /** Conversion will proceed if the CBOR item to be decoded is a big - number, positive or negative (tag 2 or tag 3). */ + * number, positive or negative (tag 2 or tag 3). */ #define QCBOR_CONVERT_TYPE_BIG_NUM 0x04 /** Conversion will proceed if the CBOR item to be decoded is a - decimal fraction (tag 4). */ + * decimal fraction (tag 4). */ #define QCBOR_CONVERT_TYPE_DECIMAL_FRACTION 0x08 /** Conversion will proceed if the CBOR item to be decoded is a big - float (tag 5). */ + * float (tag 5). */ #define QCBOR_CONVERT_TYPE_BIGFLOAT 0x10 /** - @brief Decode next item into a signed 64-bit integer. - - @param[in] pCtx The decode context. - @param[out] pnValue The returned 64-bit signed integer. - - The CBOR data item to decode must be a positive or negative integer - (CBOR major type 0 or 1). If not @ref QCBOR_ERR_UNEXPECTED_TYPE is set. - - If the CBOR integer is either too large or too small to fit in an - int64_t, the error @ref QCBOR_ERR_INT_OVERFLOW or @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW is set. Note that type 0 - unsigned integers can be larger than will fit in an int64_t and type - 1 negative integers can be smaller than will fit in an int64_t. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See also QCBORDecode_GetUInt64(), QCBORDecode_GetInt64Convert() and - QCBORDecode_GetInt64ConvertAll(). + * @brief Decode next item into a signed 64-bit integer. + * + * @param[in] pCtx The decode context. + * @param[out] pnValue The returned 64-bit signed integer. + * + * The CBOR data item to decode must be a positive or negative integer + * (CBOR major type 0 or 1). If not @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * + * If the CBOR integer is either too large or too small to fit in an + * int64_t, the error @ref QCBOR_ERR_INT_OVERFLOW or + * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW is set. Note that type 0 + * unsigned integers can be larger than will fit in an int64_t and + * type 1 negative integers can be smaller than will fit in an + * int64_t. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetUInt64(), QCBORDecode_GetInt64Convert(), + * QCBORDecode_GetInt64ConvertAll() and QCBORDecode_GetDoubleConvert() */ -static void QCBORDecode_GetInt64(QCBORDecodeContext *pCtx, - int64_t *pnValue); +static void +QCBORDecode_GetInt64(QCBORDecodeContext *pCtx, + int64_t *pnValue); -static void QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - int64_t *pnValue); +static void +QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + int64_t *pnValue); -static void QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - int64_t *pnValue); +static void +QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + int64_t *pnValue); /** - @brief Decode next item into a signed 64-bit integer with basic conversions. + * @brief Decode next item into a signed 64-bit integer with basic conversions. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pnValue The returned 64-bit signed integer. + * + * @c uConvertTypes controls what conversions this will perform and + * thus what CBOR types will be decoded. @c uConvertType is a bit map + * listing the conversions to be allowed. This function supports + * @ref QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT + * conversions. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If the CBOR data type can never be convered by this function or the + * conversion was not selected in @c uConversionTypes + * @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * + * When converting floating-point values, the integer is rounded to + * the nearest integer using llround(). By default, floating-point + * suport is enabled for QCBOR. + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number + * is encountered. + * + * If floating-point usage is disabled this will set + * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is + * encountered. + * + * See also QCBORDecode_GetInt64ConvertAll() which will perform the + * same conversions as this and a lot more at the cost of adding more + * object code to your executable. + */ +static void +QCBORDecode_GetInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + int64_t *pnValue); - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pnValue The returned 64-bit signed integer. +static void +QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - @c uConvertTypes controls what conversions this will perform and thus - what CBOR types will be decoded. @c uConvertType is a bit map - listing the conversions to be allowed. This function supports @ref - QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT - conversions. +static void +QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - If the CBOR data type can never be convered by this function or the - conversion was not selected in @c uConversionTypes @ref - @ref QCBOR_ERR_UNEXPECTED_TYPE is set. +/** + * @brief Decode next item into a signed 64-bit integer with conversions. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pnValue The returned 64-bit signed integer. + * + * This is the same as QCBORDecode_GetInt64Convert() but additionally + * supports conversion from positive and negative bignums, decimal + * fractions and big floats, including decimal fractions and big floats + * that use bignums. The conversion types supported are + * @ref QCBOR_CONVERT_TYPE_XINT64, @ref QCBOR_CONVERT_TYPE_FLOAT, + * @ref QCBOR_CONVERT_TYPE_BIG_NUM, + * @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and + * @ref QCBOR_CONVERT_TYPE_BIGFLOAT. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * Note that most these types can support numbers much larger that can + * be represented by in a 64-bit integer, so + * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW may often be encountered. + * + * When converting bignums and decimal fractions, + * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be set if the result + * is below 1, unless the mantissa is zero, in which case the + * coversion is successful and the value of 0 is returned. + * + * See also QCBORDecode_GetInt64ConvertAll() which does some of these + * conversions, but links in much less object code. See also + * QCBORDecode_GetUInt64ConvertAll(). + * + * This relies on CBOR tags to identify big numbers, decimal fractions + * and big floats. It will not attempt to decode non-tag CBOR that might + * be one of these. (If QCBOR_DISABLE_TAGS is set, this is effectively + * the same as QCBORDecode_GetInt64Convert() because all the additional + * number types this decodes are tags). + */ +void +QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + int64_t *pnValue); - When converting floating-point values, the integer is rounded to the - nearest integer using llround(). By default, floating-point suport is - enabled for QCBOR. +void +QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. +void +QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - If floating-point usage is disabled this will set @ref QCBOR_ERR_ALL_FLOAT_DISABLED - if a floating point value is encountered. - See also QCBORDecode_GetInt64ConvertAll() which will perform the same - conversions as this and a lot more at the cost of adding more object - code to your executable. +/** + * @brief Decode next item into an unsigned 64-bit integer. + * + * @param[in] pCtx The decode context. + * @param[out] puValue The returned 64-bit unsigned integer. + * + * This is the same as QCBORDecode_GetInt64(), but returns an unsigned integer + * and thus can only decode CBOR positive integers. + * @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION is set if the input is a negative + * integer. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetUInt64Convert() and QCBORDecode_GetUInt64ConvertAll(). */ -static void QCBORDecode_GetInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64(QCBORDecodeContext *pCtx, + uint64_t *puValue); -static void QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint64_t *puValue); -static void QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint64_t *puValue); /** - @brief Decode next item into a signed 64-bit integer with conversions. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pnValue The returned 64-bit signed integer. - - This is the same as QCBORDecode_GetInt64Convert() but additionally - supports conversion from positive and negative bignums, decimal - fractions and big floats, including decimal fractions and big floats - that use bignums. The conversion types supported are @ref - QCBOR_CONVERT_TYPE_XINT64, @ref QCBOR_CONVERT_TYPE_FLOAT, @ref - QCBOR_CONVERT_TYPE_BIG_NUM, @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION - and @ref QCBOR_CONVERT_TYPE_BIGFLOAT. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - Note that most these types can support numbers much larger that can - be represented by in a 64-bit integer, so @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW may often be encountered. - - When converting bignums and decimal fractions @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be set if the result is - below 1, unless the mantissa is zero, in which case the coversion is - successful and the value of 0 is returned. - - See also QCBORDecode_GetInt64ConvertAll() which does some of these - conversions, but links in much less object code. See also - QCBORDecode_GetUInt64ConvertAll(). - - This relies on CBOR tags to identify big numbers, decimal fractions - and big floats. It will not attempt to decode non-tag CBOR that might - be one of these. (If QCBOR_DISABLE_TAGS is set, this is effectively - the same as QCBORDecode_GetInt64Convert() because all the additional - number types this decodes are tags). + * @brief Decode next item as an unsigned 64-bit integer with basic conversions. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] puValue The returned 64-bit unsigned integer. + * + * This is the same as QCBORDecode_GetInt64Convert(), but returns an + * unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION + * if the value to be decoded is negatve. + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number + * is encountered. + * + * If floating-point usage is disabled this will set + * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is + * encountered. + * + * See also QCBORDecode_GetUInt64Convert() and + * QCBORDecode_GetUInt64ConvertAll(). */ -void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + uint64_t *puValue); -void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + uint64_t *puValue); -void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + uint64_t *puValue); /** - @brief Decode next item into an unsigned 64-bit integer. - - @param[in] pCtx The decode context. - @param[out] puValue The returned 64-bit unsigned integer. - - This is the same as QCBORDecode_GetInt64(), but returns an unsigned integer - and thus can only decode CBOR positive integers. - @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION is set if the input is a negative - integer. + * @brief Decode next item into an unsigned 64-bit integer with conversions + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] puValue The returned 64-bit unsigned integer. + * + * This is the same as QCBORDecode_GetInt64ConvertAll(), but returns + * an unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION + * if the value to be decoded is negatve. + * + * See also QCBORDecode_GetUInt64() and QCBORDecode_GetUInt64Convert(). + */ +void +QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + uint64_t *puValue); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +void +QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + uint64_t *puValue); - See also QCBORDecode_GetUInt64Convert() and QCBORDecode_GetUInt64ConvertAll(). -*/ -static void QCBORDecode_GetUInt64(QCBORDecodeContext *pCtx, - uint64_t *puValue); +void +QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + uint64_t *puValue); -static void QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint64_t *puValue); -static void QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint64_t *puValue); /** - @brief Decode next item as an unsigned 64-bit integer with basic conversions. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] puValue The returned 64-bit unsigned integer. - - This is the same as QCBORDecode_GetInt64Convert(), but returns an - unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION - is set if the value to be decoded is negatve. - - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. - - If floating-point usage is disabled this will set @ref QCBOR_ERR_ALL_FLOAT_DISABLED - if a floating point value is encountered. - - See also QCBORDecode_GetUInt64Convert() and - QCBORDecode_GetUInt64ConvertAll(). -*/ -static void QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue); + * @brief Decode the next item as a byte string + * + * @param[in] pCtx The decode context. + * @param[out] pBytes The decoded byte string. + * + * The CBOR item to decode must be a byte string, CBOR type 2. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If the CBOR item to decode is not a byte string, the + * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + */ +static void +QCBORDecode_GetByteString(QCBORDecodeContext *pCtx, + UsefulBufC *pBytes); -static void QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + UsefulBufC *pBytes); -static void QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + UsefulBufC *pBytes); /** - @brief Decode next item into an unsigned 64-bit integer with conversions - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] puValue The returned 64-bit unsigned integer. - - This is the same as QCBORDecode_GetInt64ConvertAll(), but returns an - unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION - if the value to be decoded is negatve. - - See also QCBORDecode_GetUInt64() and - QCBORDecode_GetUInt64Convert(). -*/ -void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue); + * @brief Decode the next item as a text string. + * + * @param[in] pCtx The decode context. + * @param[out] pText The decoded byte string. + * + * The CBOR item to decode must be a text string, CBOR type 3. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * It the CBOR item to decode is not a text string, the + * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. + */ +static void +QCBORDecode_GetTextString(QCBORDecodeContext *pCtx, + UsefulBufC *pText); -void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + UsefulBufC *pText); -void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + UsefulBufC *pText); +#ifndef USEFULBUF_DISABLE_ALL_FLOAT /** - @brief Decode the next item as a byte string + * @brief Decode next item into a double floating-point value. + * + * @param[in] pCtx The decode context. + * @param[out] pValue The returned floating-point value. + * + * The CBOR data item to decode must be a half-precision, + * single-precision or double-precision floating-point value. If not + * @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number + * is encountered. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetDoubleConvert() and + * QCBORDecode_GetDoubleConvertAll(). + */ +static void +QCBORDecode_GetDouble(QCBORDecodeContext *pCtx, + double *pValue); + +static void +QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + double *pdValue); - @param[in] pCtx The decode context - @param[out] pBytes The decoded byte string +static void +QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + double *pdValue); - The CBOR item to decode must be a byte string, CBOR type 2. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +/** + * @brief Decode next item into a double floating-point with basic conversion. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pdValue The returned floating-point value. + * + * This will decode CBOR integer and floating-point numbers, returning + * them as a double floating-point number. This function supports - If the CBOR item to decode is not a byte string, the @ref - QCBOR_ERR_UNEXPECTED_TYPE error is set. + * @ref QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT + * conversions. If the encoded CBOR is not one of the requested types + * or a type not supported by this function, @ref QCBOR_ERR_UNEXPECTED_TYPE + * is set. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number is + * encountered. + * + * Positive and negative integers can always be converted to + * floating-point, so this will never error on CBOR major type 0 or 1. + * + * Note that a large 64-bit integer can have more precision (64 bits) + * than even a double floating-point (52 bits) value, so there is loss + * of precision in some conversions. + * + * See also QCBORDecode_GetDouble() and QCBORDecode_GetDoubleConvertAll(). */ -static void QCBORDecode_GetByteString(QCBORDecodeContext *pCtx, - UsefulBufC *pBytes); +static void +QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + double *pdValue); -static void QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - UsefulBufC *pBytes); +static void +QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + double *pdValue); -static void QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - UsefulBufC *pBytes); +static void +QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + double *pdValue); /** - @brief Decode the next item as a text string. + * @brief Decode next item as a double floating-point value with conversion. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pdValue The returned floating-point value. + * + * This is the same as QCBORDecode_GetDoubleConvert() but supports + * many more conversions at the cost of linking in more object + * code. The conversion types supported are @ref QCBOR_CONVERT_TYPE_XINT64, + * @ref QCBOR_CONVERT_TYPE_FLOAT, @ref QCBOR_CONVERT_TYPE_BIG_NUM, + * @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and + * @ref QCBOR_CONVERT_TYPE_BIGFLOAT. + * + * Big numbers, decimal fractions and big floats that are too small or + * too large to be reprented as a double floating-point number will be + * returned as plus or minus zero or infinity rather than setting an + * under or overflow error. + * + * There is often loss of precision in the conversion. + * + * See also QCBORDecode_GetDoubleConvert() and QCBORDecode_GetDoubleConvert(). + */ +void +QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + double *pdValue); - @param[in] pCtx The decode context. - @param[out] pText The decoded byte string. +void +QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + double *pdValue); - The CBOR item to decode must be a text string, CBOR type 3. +void +QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + double *pdValue); +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - Please see @ref Decode-Errors-Overview "Decode Errors Overview". It the CBOR item - to decode is not a text string, the @ref QCBOR_ERR_UNEXPECTED_TYPE - error is set. - This does no translation of line endings. See QCBOREncode_AddText() - for a discussion of line endings in CBOR. -*/ -static void QCBORDecode_GetTextString(QCBORDecodeContext *pCtx, - UsefulBufC *pText); -static void QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - UsefulBufC *pText); -static void QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - UsefulBufC *pText); +/** + * @brief Enter an array for decoding in bounded mode. + * + * @param[in] pCtx The decode context. + * @param[out] pItem The optionally returned QCBORItem that has the + * label and tags for the array. May be @c NULL (and + * usually is). + * + * This enters an array for decoding in bounded mode. The items in + * the array are decoded in order the same as when not in bounded mode, + * but the decoding will not proceed past the end or the array. + * + * The typical way to iterate over items in an array is to call + * QCBORDecode_VGetNext() until QCBORDecode_GetError() returns + * @ref QCBOR_ERR_NO_MORE_ITEMS. Other methods like QCBORDecode_GetInt64(), + * QCBORDecode_GetBignum() and such may also called until + * QCBORDecode_GetError() doesn't return QCBOR_SUCCESS. + * + * Another option is to get the array item count from + * @c pItem->val.uCount, but note that that will not work with + * indefinte-length arrays, where as QCBORDecode_GetError() will. + * + * Nested decoding of arrays may be handled by calling + * QCBORDecode_EnterArray() or by using QCBORDecode_VGetNext() to + * descend into and back out of the nested array. + * + * QCBORDecode_Rewind() can be called to restart decoding from the + * first item in the array. + * + * When all decoding in an array is complete, QCBORDecode_ExitArray() must + * be called. It is a decoding error to not have a corresponding call + * to QCBORDecode_ExitArray() for every call to QCBORDecode_EnterArray(). + * If not, @ref QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN will be returned when + * QCBORDecode_Finish() is called. + * + * After QCBORDecode_ExitArray() is called the traversal cusor is at + * the item right after the array. This is true whether or not all + * items in the array were consumed. QCBORDecode_ExitArray() can even + * be called right after QCBORDecode_EnterArray() as a way to skip + * over an array and all its contents. + * + * This works the same for definite and indefinite length arrays. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If attempting to enter a data item that is not an array + * @ref QCBOR_ERR_UNEXPECTED_TYPE wil be set. + * + * Nested arrays and maps may be entered to a depth of + * @ref QCBOR_MAX_ARRAY_NESTING. + * + * See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap(), + * QCBORDecode_EnterBstrWrapped() and QCBORDecode_GetArray(). + */ +static void +QCBORDecode_EnterArray(QCBORDecodeContext *pCtx, QCBORItem *pItem); +void +QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t uLabel); +void +QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel); -#ifndef USEFULBUF_DISABLE_ALL_FLOAT /** - @brief Decode next item into a double floating-point value. - - @param[in] pCtx The decode context - @param[out] pValue The returned floating-point value. - - The CBOR data item to decode must be a half-precision, - single-precision or double-precision floating-point value. If not - @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * @brief Exit an array that has been enetered. + * + * @param[in] pCtx The decode context. + * + * An array must have been entered for this to succeed. + * + * The items in the array that was entered do not have to have been + * consumed for this to succeed. + * + * This sets the traversal cursor to the item after the + * array that was exited. + * + * This will result in an error if any item in the array is not well + * formed (since all items in the array must be decoded to find its + * end), or there are not enough items in the array. + */ +static void +QCBORDecode_ExitArray(QCBORDecodeContext *pCtx); - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - See also QCBORDecode_GetDoubleConvert() and - QCBORDecode_GetDoubleConvertAll(). -*/ -static void QCBORDecode_GetDouble(QCBORDecodeContext *pCtx, - double *pValue); +/** + * @brief Get the encoded bytes that make up an array. + * + * @param[in] pCtx The decode context. + * @param[out] pItem Place to return the item. + * @param[out] pEncodedCBOR Place to return pointer and length of the array. + * + * The next item to decode must be an array. + * + * The encoded bytes of the array will be returned. They can be + * decoded by another decoder instance. + * + * @c pItem will have the label and tags for the array. It is filled + * in the same as if QCBORDecode_GetNext() were called on the array item. In + * particular, the array count will be filled in for definite-length + * arrays and set to @c UINT16_MAX for indefinite-length arrays. + * + * This works on both definite and indefinite length arrays (unless + * indefinite length array decoding has been disabled). + * + * The pointer returned is to the data item that opens the array. The + * length in bytes includes it and all the member data items. If the array + * occurs in another map and thus has a label, the label is not included + * in what is returned. + * + * If the array is preceeded by tags, those encoded tags are included + * in the encoded CBOR that is returned. + * + * QCBORDecode_GetArray() consumes the entire array and leaves the + * traversal cursor at the item after the array. + * QCBORDecode_GetArrayFromMapN() and QCBORDecode_GetArrayFromMapSZ() + * don't affect the traversal cursor. + * + * This traverses the whole array and every subordinate array or map in + * it. This is necessary to determine the length of the array. + * + * This will fail if any item in the array is not well-formed. + * + * This uses a few hundred bytes of stack, more than most methods. + * + * See also QCBORDecode_EnterArray(). + */ +static void +QCBORDecode_GetArray(QCBORDecodeContext *pCtx, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - double *pdValue); +static void +QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - double *pdValue); +static void +QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); /** - @brief Decode next item into a double floating-point value with basic conversion. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pdValue The returned floating-point value. + * @brief Enter a map for decoding and searching. + * + * @param[in] pCtx The decode context. + * @param[out] pItem The optionally returned QCBORItem that has the + * label and tags for the map. May be @c NULL (and + * usually is). + * + * The next item in the CBOR input must be map or this sets an error. + * + * This puts the decoder in bounded mode which narrows decoding to the + * map entered and enables getting items by label. + * + * All items in the map must be well-formed to be able to search it by + * label because a full traversal is done for each search. If not, the + * search will retun an error for the item that is not well-formed. + * This will be the first non-well-formed item which may not be the + * item with the label that is the target of the search. + * + * Nested maps can be decoded like this by entering each map in turn. + * + * Call QCBORDecode_ExitMap() to exit the current map decoding + * level. When all map decoding layers are exited then bounded mode is + * fully exited. + * + * While in bounded mode, QCBORDecode_GetNext() works as usual on the + * map and the traversal cursor is maintained. It starts out + * at the first item in the map just entered. Attempts to get items + * off the end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS + * rather going to the next item after the map as it would when not in + * bounded mode. + * + * It is possible to mix use of the traversal cursor with the fetching + * of items in a map by label with the caveat that fetching + * non-aggregate items by label behaves differently from entering subordinate + * aggregate items by label. See dicussion in @ref SpiffyDecode. + * + * Exiting leaves the traversal cursor at the data item following the + * last entry in the map or at the end of the input CBOR if there + * nothing after the map. + * + * Entering and Exiting a map is a way to skip over an entire map and + * its contents. After QCBORDecode_ExitMap(), the traversal + * cursor will be at the first item after the map. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_EnterArray() and + * QCBORDecode_EnterBstrWrapped(). Entering and exiting any nested + * combination of maps, arrays and bstr-wrapped CBOR is supported up + * to the maximum of @ref QCBOR_MAX_ARRAY_NESTING. + * + * See also QCBORDecode_GetMap(). + */ +static void +QCBORDecode_EnterMap(QCBORDecodeContext *pCtx, QCBORItem *pItem); - This will decode CBOR integer and floating-point numbers, returning - them as a double floating-point number. This function supports @ref - QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT - conversions. If the encoded CBOR is not one of the requested types or a type - not supported by this function, @ref QCBOR_ERR_UNEXPECTED_TYPE is - set. +void +QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +void +QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel); - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. - Positive and negative integers can always be converted to - floating-point, so this will never error on CBOR major type 0 or 1. +/** + * @brief Exit a map that has been enetered. + * + * @param[in] pCtx The decode context. + * + * A map must have been entered for this to succeed. + * + * The items in the map that was entered do not have to have been + * consumed for this to succeed. + * + * This sets the traversal cursor to the item after the map + * that was exited. + * + * This will result in an error if any item in the map is not well + * formed (since all items in the map must be decoded to find its + * end), or there are not enough items in the map. + */ +static void +QCBORDecode_ExitMap(QCBORDecodeContext *pCtx); - Note that a large 64-bit integer can have more precision (64 bits) - than even a double floating-point (52 bits) value, so there is loss - of precision in some conversions. - See also QCBORDecode_GetDouble() and QCBORDecode_GetDoubleConvertAll(). -*/ -static void QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pdValue); +/** + * @brief Get the bytes that make up a map. + * + * @param[in] pCtx The decode context. + * @param[out] pItem Place to return the item. + * @param[out] pEncodedCBOR Place to return pointer and length of the map. + * + * The next item to decode must be a map. + * + * The encoded bytes of the map will be returned. They can be + * decoded by another decoder instance. + * + * @c pItem will have the label and tags for the array. It is filled + * in the same as if QCBORDecode_GetNext() were called on the map item. In + * particular, the map count will be filled in for definite-length + * maps and set to @c UINT16_MAX for indefinite-length maps. + * + * This works on both definite and indefinite length maps (unless + * indefinite length map decoding has been disabled). + * + * The pointer returned is to the data item that opens the map. The + * length in bytes includes it and all the member data items. If the map + * occurs in another map and thus has a label, the label is not included + * in what is returned. + * + * If the map is preceeded by tags, those encoded tags are included in + * the encoded CBOR that is returned. + * + * QCBORDecode_GetMap() consumes the entire array and leaves the + * traversal cursor at the item after the map. + * QCBORDecode_GetMapFromMapN() and QCBORDecode_GetMapFromMapSZ() + * don't affect the traversal cursor. + * + * This traverses the whole map and every subordinate array or map in + * it. This is necessary to determine the length of the map. The + * traversal cursor is left at the first item after the map. + * + * This will fail if any item in the map is not well-formed. + * + * This uses a few hundred bytes of stack, more than most methods. + * + * See also QCBORDecode_EnterMap(). + */ +static void +QCBORDecode_GetMap(QCBORDecodeContext *pCtx, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue); +static void +QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue); +static void +QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); /** - @brief Decode next item as a double floating-point value with conversion. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pdValue The returned floating-point value. - - This is the same as QCBORDecode_GetDoubleConvert() but supports many - more conversions at the cost of linking in more object code. The - conversion types supported are @ref QCBOR_CONVERT_TYPE_XINT64, @ref - QCBOR_CONVERT_TYPE_FLOAT, @ref QCBOR_CONVERT_TYPE_BIG_NUM, @ref - QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and @ref - QCBOR_CONVERT_TYPE_BIGFLOAT. - - Big numbers, decimal fractions and big floats that are too small or - too large to be reprented as a double floating-point number will be - returned as plus or minus zero or infinity rather than setting an - under or overflow error. - - There is often loss of precision in the conversion. + * @brief Reset traversal cursor to start of map, array, byte-string + * wrapped CBOR or start of input. + * + * @param[in] pCtx The decode context. + * + * If an array, map or wrapping byte string has been entered this sets + * the traversal cursor to its beginning. If several arrays, maps or + * byte strings have been entered, this sets the traversal cursor to + * the beginning of the one most recently entered. + * + * If no map or array has been entered, this resets the traversal + * cursor to the beginning of the input CBOR. + * + * This also resets the error state. + */ +void +QCBORDecode_Rewind(QCBORDecodeContext *pCtx); - See also QCBORDecode_GetDoubleConvert() and QCBORDecode_GetDoubleConvert(). -*/ -void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pdValue); -void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue); +/** + * @brief Get an item in map by label and type. + * + * @param[in] pCtx The decode context. + * @param[in] nLabel The integer label. + * @param[in] uQcborType The QCBOR type. One of @c QCBOR_TYPE_XXX. + * @param[out] pItem The returned item. + * + * A map must have been entered to use this. If not + * @ref QCBOR_ERR_MAP_NOT_ENTERED is set. + * + * The map is searched for an item of the requested label and type. + * @ref QCBOR_TYPE_ANY can be given to search for the label without + * matching the type. + * + * This will always search the entire map. This will always perform + * duplicate label detection, setting @ref QCBOR_ERR_DUPLICATE_LABEL + * if there is more than one occurance of the label being searched + * for. + * + * Duplicate label detection is performed for the item being sought + * and only for the item being sought. + * + * This performs a full decode of every item in the map being + * searched which involves a full traversal of every item. For maps + * with little nesting, this is of little consequence, but may be of + * consequence for large deeply nested CBOR structures on slow CPUs. + * + * The position of the traversal cursor is not changed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetItemsInMap() for error discussion. + */ +void +QCBORDecode_GetItemInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uQcborType, + QCBORItem *pItem); -void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +void +QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uQcborType, + QCBORItem *pItem); +/** + * @brief Get a group of labeled items all at once from a map + * + * @param[in] pCtx The decode context. + * @param[in,out] pItemList On input, the items to search for. On output, + * the returne *d items. + * + * This gets several labeled items out of a map. + * + * @c pItemList is an array of items terminated by an item with @c + * uLabelType @ref QCBOR_TYPE_NONE. + * + * On input the labels to search for are in the @c uLabelType and + * label fields in the items in @c pItemList. + * + * Also on input are the requested QCBOR types in the field + * @c uDataType. To match any type, searching just by label, + * @c uDataType can be @ref QCBOR_TYPE_ANY. + * + * This is a CPU-efficient way to decode a bunch of items in a map. It + * is more efficient than scanning each individually because the map + * only needs to be traversed once. + * + * This will return maps and arrays that are in the map, but provides + * no way to descend into and decode them. Use + * QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and + * such to descend into and process maps and arrays. + * + * The position of the traversal cursor is not changed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * The following errors are set: + * + * @ref QCBOR_ERR_MAP_NOT_ENTERED when calling this without previousl + * calling QCBORDecode_EnterMap() or other methods to enter a map. + * + * @ref QCBOR_ERR_DUPLICATE_LABEL when one of the labels being searched + * for is duplicate. + * + * @ref QCBOR_ERR_HIT_END or other errors classifed as not-well-formed + * by QCBORDecode_IsNotWellFormed() as it is not possible to traverse + * maps that have any non-well formed items. + * + * @ref QCBOR_ERR_UNEXPECTED_TYPE when the type of an item found by + * matching a label is not the type requested. + * + * @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP and other implementation + * limit errors as it is not possible to travere a map beyond the + * limits of the implementation. + * + * The error may occur on items that are not being searched for. For + * example, it is impossible to traverse over a map that has an array in + * it that is not closed or over array and map nesting deeper than this + * implementation can track. + * + * See also QCBORDecode_GetItemInMapN(). + */ +void +QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList); /** - @brief Enter an array for decoding in bounded mode. - - @param[in] pCtx The decode context. - @param[out] pItem The optionally returned QCBORItem that has the - label and tags for the array. May be @c NULL (and - usually is). + * @brief Per-item callback for map searching. + * + * @param[in] pCallbackCtx Pointer to the caller-defined context for the callback. + * @param[in] pItem The item from the map. + * + * The error set is intended for QCBOR errors, not general protocol + * decoding errors. If this sets other than @ref QCBOR_SUCCESS, the + * search will stop and the value it returns will be set in + * QCBORDecode_GetItemsInMapWithCallback(). The special error, + * @ref QCBOR_ERR_CALLBACK_FAIL, can be returned to indicate some + * protocol processing error that is not a CBOR error. The specific + * details of the protocol processing error can be returned the call + * back context. + */ +typedef QCBORError (*QCBORItemCallback)(void *pCallbackCtx, + const QCBORItem *pItem); - This enters an array for decoding in bounded mode. The items in array - are decoded in order the same as when not in bounded mode, but the - decoding will not proceed past the end or the array. The error @ref - QCBOR_ERR_NO_MORE_ITEMS will be set when the end of the array is - encountered. To decode past the end of the array, - QCBORDecode_ExitArray() must be called. Also, QCBORDecode_Finish() - will return an error if all arrays that were enetered are not exited. - This works the same for definite and indefinite length arrays. +/** + * @brief Get a group of labeled items all at once from a map with a callback. + * + * @param[in] pCtx The decode context. + * @param[in,out] pItemList On input, the items to search for. On output, + * the returne *d items. + * @param[in,out] pCallbackCtx Pointer to a context structure for + * @ref QCBORItemCallback + * @param[in] pfCB Pointer to function of type + * @ref QCBORItemCallback that is called on + * unmatched items. + * + * This searchs a map like QCBORDecode_GetItemsInMap(), but calls a + * callback on items not matched rather than ignoring them. If @c + * pItemList is empty, the call back will be called on every item in the + * map. + * + * Like QCBORDecode_GetItemsInMap(), this only matches and calls back on + * the items at the top level of the map entered. Items in nested + * maps and arrays are skipped over and not candidate for matching or the + * callback. + * + * See QCBORItemCallback() for error handling. + */ +void +QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, + QCBORItem *pItemList, + void *pCallbackCtx, + QCBORItemCallback pfCB); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - If attempting to enter a data item that is not an array @ref - QCBOR_ERR_UNEXPECTED_TYPE wil be set. - Nested arrays and maps may be entered to a depth of @ref - QCBOR_MAX_ARRAY_NESTING. - See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap() and - QCBORDecode_EnterBstrWrapped(). +/** + * @brief Decode the next item as a Boolean. + * + * @param[in] pCtx The decode context. + * @param[out] pbBool The decoded byte string. + * + * The CBOR item to decode must be either the CBOR simple value (CBOR + * type 7) @c true or @c false. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". If + * the CBOR item to decode is not true or false the @ref + * QCBOR_ERR_UNEXPECTED_TYPE error is set. */ -static void QCBORDecode_EnterArray(QCBORDecodeContext *pCtx, QCBORItem *pItem); +void +QCBORDecode_GetBool(QCBORDecodeContext *pCtx, bool *pbBool); -void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t uLabel); +void +QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + bool *pbBool); -void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel); +void +QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + bool *pbBool); /** - @brief Exit an array that has been enetered. - - @param[in] pCtx The decode context. + * @brief Decode the next item as a null. + * + * @param[in] pCtx The decode context. + * + * The CBOR item to decode must be the CBOR simple value (CBOR type 7) + * @c null. The reason to call this is to see if an error is returned + * or not indicating whether the item is a CBOR null. If it is not + * then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + */ +static void +QCBORDecode_GetNull(QCBORDecodeContext *pCtx); - An array must have been entered for this to succeed. +static void +QCBORDecode_GetNullInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel); - The items in the array that was entered do not have to have been - consumed for this to succeed. +static void +QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel); - This sets the pre-order traversal cursor to the item after the array - that was exited. - This will result in an error if any item in the array is not well - formed (since all items in the array must be decoded to find its - end), or there are not enough items in the array. -*/ -static void QCBORDecode_ExitArray(QCBORDecodeContext *pCtx); +/** + * @brief Decode the next item as a CBOR "undefined" item. + * + * @param[in] pCtx The decode context. + * + * The CBOR item to decode must be the CBOR simple value (CBOR type 7) + * @c undefined. The reason to call this is to see if an error is + * returned or not indicating whether the item is a CBOR undefed + * item. If it is not then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is + * set. + */ +static void +QCBORDecode_GetUndefined(QCBORDecodeContext *pCtx); +static void +QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel); +static void +QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel); /** - @brief Enter a map for decoding and searching. - - @param[in] pCtx The decode context. - @param[out] pItem The optionally returned QCBORItem that has the - label and tags for the map. May be @c NULL (and - usually is). + * @brief Decode the next item as a CBOR simple value. + * + * @param[in] pCtx The decode context. + * @param[out] puSimpleValue The simplle value returned. + * + * The purpose of this is to get a CBOR simple value other than a + * Boolean, NULL or "undefined", but this works on all simple + * values. See QCBOREncode_AddSimple() for more details on simple + * values in general. + * + * See QCBORDecode_GetBool(), QCBORDecode_GetNull(), + * QCBORDecode_GetUndefined() for the preferred way of getting those + * simple values. + */ +void +QCBORDecode_GetSimple(QCBORDecodeContext *pCtx, uint8_t *puSimpleValue); - The next item in the CBOR input must be map or this sets an error. +void +QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t *puSimpleValue); - This puts the decoder in bounded mode which narrows decoding to the - map entered and enables getting items by label. +void +QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t *puSimpleValue); - All items in the map must be well-formed to be able to search it by - label because a full traversal is done for each search. If not, the - search will retun an error for the item that is not well-formed. - This will be the first non-well-formed item which may not be the item - with the label that is the target of the search. - Nested maps can be decoded like this by entering each map in turn. - Call QCBORDecode_ExitMap() to exit the current map decoding - level. When all map decoding layers are exited then bounded mode is - fully exited. - While in bounded mode, QCBORDecode_GetNext() works as usual on the - map and the in-order traversal cursor is maintained. It starts out at - the first item in the map just entered. Attempts to get items off the - end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS rather - going to the next item after the map as it would when not in bounded - mode. +/** + * @brief Decode the next item as a date string. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pDateString The decoded date. + * + * This decodes the standard CBOR date/time string tag, integer tag + * number of 0, or encoded CBOR that is not a tag, but borrows the + * date string content format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and + * @ref QCBOR_TYPE_DATE_STRING. + */ +static void +QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pDateString); - Exiting leaves the pre-order cursor at the data item following the - last entry in the map or at the end of the input CBOR if there - nothing after the map. +static void +QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); - Entering and Exiting a map is a way to skip over an entire map and - its contents. After QCBORDecode_ExitMap(), the pre-order traversal - cursor will be at the first item after the map. +static void +QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - See also QCBORDecode_EnterArray() and QCBORDecode_EnterBstrWrapped(). - Entering and exiting any nested combination of maps, arrays and - bstr-wrapped CBOR is supported up to the maximum of @ref - QCBOR_MAX_ARRAY_NESTING. +/** + * @brief Decode the next item as a date-only string. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pDateString The decoded date. + * + * This decodes the CBOR date-only string tag, integer tag number of + * 1004, or encoded CBOR that is not a tag, but borrows the date-only + * string content format. An example of the format is "1985-04-12". + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and + * @ref QCBOR_TYPE_DAYS_STRING. */ -static void QCBORDecode_EnterMap(QCBORDecodeContext *pCtx, QCBORItem *pItem); +static void +QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pDateString); -void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel); +static void +QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); -void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel); +static void +QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); /** - @brief Exit a map that has been enetered. - - @param[in] pCtx The decode context. - - A map must have been entered for this to succeed. - - The items in the map that was entered do not have to have been - consumed for this to succeed. + * @brief Decode the next item as an epoch date. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnTime The decoded epoch date. + * + * This decodes the standard CBOR epoch date/time tag, integer tag + * number of 1. This will also decode any integer or floating-point + * number as an epoch date (a tag 1 epoch date is just an integer or + * floating-point number). + * + * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer + * will not fit in an @c int64_t. Note that an @c int64_t can + * represent a range of over 500 billion years with one second + * resolution. + * + * Floating-point dates are always returned as an @c int64_t. The + * fractional part is discarded. + * + * If the input is a floating-point date and the QCBOR library is + * compiled with some or all floating-point features disabled, the + * following errors will be set. If the input is half-precision and + * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED + * is set. This function needs hardware floating-point to convert the + * floating-point value to an integer so if HW floating point is + * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all + * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED + * is set. A previous version of this function would return + * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when + * floating-point decoding was disabled. + * + * Floating-point dates that are plus infinity, minus infinity or NaN + * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW + * error. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and + * @ref QCBOR_TYPE_DATE_EPOCH. +*/ +void +QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnTime); - This sets the pre-order traversal cursor to the item after the map - that was exited. +void +QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnTime); - This will result in an error if any item in the map is not well - formed (since all items in the map must be decoded to find its end), - or there are not enough items in the map. -*/ -static void QCBORDecode_ExitMap(QCBORDecodeContext *pCtx); +void +QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnTime); /** - @brief Reset traversal cursor to start of map, array, byte-string - wrapped CBOR or start of input. + * @brief Decode the next item as an days-count epoch date. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnDays The decoded epoch date. + * + * This decodes the CBOR epoch date tag, integer tag number of 100, or + * encoded CBOR that is not a tag, but borrows the content format. The + * date is the number of days (not number of seconds) before or after + * Jan 1, 1970. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and + * @ref QCBOR_TYPE_DAYS_EPOCH. +*/ +void +QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnDays); - @param[in] pCtx The decode context. +void +QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnDays); - If an array, map or wrapping byte string has been entered this sets - the traversal cursor to its beginning. If several arrays, maps or - byte strings have been entered, this sets the traversal cursor to the - beginning of the one most recently entered. +void +QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnDays); - If no map or array has been entered, this resets the traversal cursor - to the beginning of the input CBOR. - This also resets the error state. - */ -void QCBORDecode_Rewind(QCBORDecodeContext *pCtx); /** - @brief Get an item in map by label and type. - - @param[in] pCtx The decode context. - @param[in] nLabel The integer label. - @param[in] uQcborType The QCBOR type. One of @c QCBOR_TYPE_XXX. - @param[out] pItem The returned item. - - A map must have been entered to use this. If not @ref - QCBOR_ERR_MAP_NOT_ENTERED is set. + * @brief Decode the next item as a big number. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pValue The returned big number. + * @param[out] pbIsNegative Is @c true if the big number is negative. This + * is only valid when @c uTagRequirement is + * @ref QCBOR_TAG_REQUIREMENT_TAG. + * + * This decodes a standard CBOR big number, integer tag number of 2 or + * 3, or encoded CBOR that is not a tag, but borrows the content + * format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * The big number is in network byte order. The first byte in @c + * pValue is the most significant byte. There may be leading zeros. + * + * The negative value is computed as -1 - n, where n is the postive + * big number in @c pValue. There is no standard representation for + * big numbers, positive or negative in C, so this implementation + * leaves it up to the caller to apply this computation for negative + * big numbers. + * + * RFC 8949 preferred serialization requires that big numbers + * that fit into integers be encoded as integers. This function + * will error if the input CBOR is a type 0 or 1 integers. A + * future version of QCBOR fixes this, but in the mean time + * the application must handle this manually. + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Determination of the sign of the big number depends on the tag + * requirement of the protocol using the big number. If the protocol + * requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign + * indication is in the protocol and @c pbIsNegative indicates the + * sign. If the protocol doesn't use a tag, @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + * then the protocol design must have some way of indicating the sign. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big numbers. + * + * See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM, + * QCBOREncode_AddTPositiveBignum(), QCBOREncode_AddTNegativeBignum(), + * @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM. + */ +void +QCBORDecode_GetBignum(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative); - The map is searched for an item of the requested label and type. - @ref QCBOR_TYPE_ANY can be given to search for the label without - matching the type. +void +QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative); - This will always search the entire map. This will always perform - duplicate label detection, setting @ref QCBOR_ERR_DUPLICATE_LABEL if - there is more than one occurance of the label being searched for. +void +QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative); - Duplicate label detection is performed for the item being sought, but - only for the item being sought. - This performs a full decode of every item in the map being searched, - which involves a full traversal of every item. For maps with little - nesting, this is of little consequence, but may be of consequence for - large deeply nested CBOR structures on slow CPUs. - The position of the pre-order traversal cursor is not changed. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA +/** + * @brief Decode the next item as a decimal fraction. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnMantissa The mantissa. + * @param[out] pnExponent The base 10 exponent. + * + * This decodes a standard CBOR decimal fraction, integer tag number + * of 4, or encoded CBOR that is not a tag, but borrows the content + * format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * The value of this is computed by: + * + * mantissa * ( 10 ** exponent ) + * + * In the encoded CBOR, the mantissa and exponent may be of CBOR type + * 0 (positive integer), type 1 (negative integer), type 2 tag 2 + * (positive big number) or type 2 tag 3 (negative big number). This + * implementation will attempt to convert all of these to an @c + * int64_t. If the value won't fit, @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW + * or @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA will be set. + * + * This implementation limits the exponent to between @c INT64_MIN and + * @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to + * @c UINT64_MAX. + * + * Various format and type issues will result in + * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA being set. + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big numbers. + * + * See also @ref CBOR_TAG_DECIMAL_FRACTION, + * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION + * and QCBORDecode_GetDecimalFractionBig(). + * + * If QCBOR_DISABLE_TAGS is set, the only input this will decode is an + * array of two integers. It will set an error if the the array is + * preceded by by a tag number or if the mantissa is a big number. + */ +void +QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - See also QCBORDecode_GetItemsInMap() for error discussion. -*/ -void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uQcborType, - QCBORItem *pItem); +void +QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); -void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uQcborType, - QCBORItem *pItem); +void +QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); /** - @brief Get a group of labeled items all at once from a map - - @param[in] pCtx The decode context. - @param[in,out] pItemList On input the items to search for. On output the returned items. + * @brief Decode the next item as a decimal fraction with a big number mantissa. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] MantissaBuffer The buffer in which to put the mantissa. + * @param[out] pMantissa The big num mantissa. + * @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. + * @param[out] pnExponent The base 10 exponent. + * + * This is the same as QCBORDecode_GetDecimalFraction() except the + * mantissa is returned as a big number. + * + * In the encoded CBOR, the mantissa may be a type 0 (positive + * integer), type 1 (negative integer), type 2 tag 2 (positive big + * number) or type 2 tag 3 (negative big number). This implementation + * will convert all these to a big number. The limit to this + * conversion is the size of @c MantissaBuffer. + * + * The mantissa returned does NOT have the offset + * of one applied when it is negative. To get the true value + * one must be added to @c *pMantissa (which requires + * some big number arithmetic and may increase the length + * of it by one). + * + * For QCBOR before v1.5, this function had a bug where + * by the negative mantissa sometimes had the offset of + * one applied, making this function somewhat usless for + * negative mantissas. Specifically if the to-be-decoded CBOR + * was a type 1 integer the offset was applied and when it + * was a tag 3, the offset was not applied. It is possible + * that a tag 3 could contain a value in the range of a type 1 + * integer. @ref QCBORExpAndMantissa is + * correct and can be used instead of this. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert decimal + * fractions. + * + * See also @ref CBOR_TAG_DECIMAL_FRACTION, + * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION + * and QCBORDecode_GetDecimalFraction(). + */ +void +QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - This gets several labeled items out of a map. +void +QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pbMantissaIsNegative, + bool *pbIsNegative, + int64_t *pnExponent); - @c pItemList is an array of items terminated by an item with @c - uLabelType @ref QCBOR_TYPE_NONE. +void +QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - On input the labels to search for are in the @c uLabelType and label - fields in the items in @c pItemList. - Also on input are the requested QCBOR types in the field @c - uDataType. To match any type, searching just by label, @c uDataType - can be @ref QCBOR_TYPE_ANY. +/** + * @brief Decode the next item as a big float. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnMantissa The mantissa. + * @param[out] pnExponent The base 2 exponent. + * + * This decodes a standard CBOR big float, integer tag number of 5, or + * encoded CBOR that is not a tag, but borrows the content format. + * + * This is the same as QCBORDecode_GetDecimalFraction() with the + * important distinction that the value is computed by: + * + * mantissa * ( 2 ** exponent ) + * + * If the mantissa is a tag that is a positive or negative big number, + * this will attempt to fit it into the int64_t that @c pnMantissa is + * and set an overflow error if it doesn't fit. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big floats. + * + * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), @ref + * QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloatBig(). + */ +void +QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - This is a CPU-efficient way to decode a bunch of items in a map. It - is more efficient than scanning each individually because the map - only needs to be traversed once. +void +QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - This will return maps and arrays that are in the map, but provides no - way to descend into and decode them. Use - QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and such - to descend into and process maps and arrays. +void +QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - The position of the pre-order traversal cursor is not changed. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +/** + * @brief Decode the next item as a big float with a big number mantissa. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] MantissaBuffer The buffer in which to put the mantissa. + * @param[out] pMantissa The big num mantissa. + * @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. + * @param[out] pnExponent The base 2 exponent. + * + * This is the same as QCBORDecode_GetDecimalFractionBig() with the + * important distinction that the value is computed by: + * + * mantissa * ( 2 ** exponent ) + * + * This has the same issue with negative mantissas as + * QCBORDecode_GetDecimalFractionBig(). + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big floats. + * + * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), + * @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloat(). + */ +void +QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - The following errors are set: +void +QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - @ref QCBOR_ERR_MAP_NOT_ENTERED when calling this without previousl - calling QCBORDecode_EnterMap() or other methods to enter a map. +void +QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); +#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */ - @ref QCBOR_ERR_DUPLICATE_LABEL when one of the labels being searched - for is duplicate. - @ref QCBOR_ERR_HIT_END or other errors classifed as not-well-formed - by QCBORDecode_IsNotWellFormed() as it is not possible to traverse - maps that have any non-well formed items. - @ref QCBOR_ERR_UNEXPECTED_TYPE when the type of an item found by - matching a label is not the type requested. - @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP and other implementation limit - errors as it is not possible to travere a map beyond the limits of - the implementation. +/** + * @brief Decode the next item as a URI. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pURI The decoded URI. + * + * This decodes a standard CBOR URI tag, integer tag number of 32, or + * encoded CBOR that is not a tag, that is a URI encoded in a text + * string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and + * @ref QCBOR_TYPE_URI. + */ +static void +QCBORDecode_GetURI(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pURI); - The error may occur on items that are not being searched for. For - example, it is impossible to traverse over a map that has an array in - it that is not closed or over array and map nesting deeper than this - implementation can track. +static void +QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pURI); - See also QCBORDecode_GetItemInMapN(). - */ -void QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList); +static void +QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, + const char * szLabel, + uint8_t uTagRequirement, + UsefulBufC *pURI); /** - @brief Per-item callback for map searching. - - @param[in] pCallbackCtx Pointer to the caller-defined context for the callback - @param[in] pItem The item from the map. - - The error set is intended for QCBOR errors, not general protocol - decoding errors. If this sets other than @ref QCBOR_SUCCESS, the - search will stop and the value it returns will be set in - QCBORDecode_GetItemsInMapWithCallback(). The special error, @ref - QCBOR_ERR_CALLBACK_FAIL, can be returned to indicate some protocol - processing error that is not a CBOR error. The specific details of - the protocol processing error can be returned the call back context. - */ -typedef QCBORError (*QCBORItemCallback)(void *pCallbackCtx, - const QCBORItem *pItem); - - -/** - @brief Get a group of labeled items all at once from a map with a callback - - @param[in] pCtx The decode context. - @param[in,out] pItemList On input the items to search for. On output the returned items. - @param[in,out] pCallbackCtx Pointer to a context structure for @ref QCBORItemCallback - @param[in] pfCB pointer to function of type @ref QCBORItemCallback that is called on unmatched items. - - This searchs a map like QCBORDecode_GetItemsInMap(), but calls a - callback on items not matched rather than ignoring them. If @c - pItemList is empty, the call back will be called on every item in the - map. - - Like QCBORDecode_GetItemsInMap(), this only matches and calls back on - the items at the top level of the map entered. Items in nested - maps and arrays are skipped over and not candidate for matching or the - callback. - - See QCBORItemCallback() for error handling. + * @brief Decode the next item as base64 encoded text. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pB64Text The decoded base64 text. + * + * This decodes a standard CBOR base64 tag, integer tag number of 34, + * or encoded CBOR that is not a tag, that is base64 encoded bytes + * encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Note that this does not actually remove the base64 encoding. + * + * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and + * @ref QCBOR_TYPE_BASE64. */ -void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, - QCBORItem *pItemList, - void *pCallbackCtx, - QCBORItemCallback pfCB); - - - - -/** - @brief Decode the next item as a Boolean. - - @param[in] pCtx The decode context. - @param[out] pbBool The decoded byte string. - - The CBOR item to decode must be either the CBOR simple value (CBOR - type 7) @c true or @c false. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". If - the CBOR item to decode is not true or false the @ref - QCBOR_ERR_UNEXPECTED_TYPE error is set. -*/ -void QCBORDecode_GetBool(QCBORDecodeContext *pCtx, bool *pbBool); - -void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - bool *pbBool); - -void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - bool *pbBool); - - -/** - @brief Decode the next item as a null. - - @param[in] pCtx The decode context. - - The CBOR item to decode must be the CBOR simple value (CBOR type 7) - @c null. The reason to call this is to see if an error is returned or - not indicating whether the item is a CBOR null. If it is not then the - @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. -*/ -static void QCBORDecode_GetNull(QCBORDecodeContext *pCtx); - -static void QCBORDecode_GetNullInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel); - -static void QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel); - +static void +QCBORDecode_GetB64(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); -/** - @brief Decode the next item as a CBOR "undefined" item. - - @param[in] pCtx The decode context. - - The CBOR item to decode must be the CBOR simple value (CBOR type 7) - @c undefined. The reason to call this is to see if an error is - returned or not indicating whether the item is a CBOR undefed - item. If it is not then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is - set. -*/ -static void QCBORDecode_GetUndefined(QCBORDecodeContext *pCtx); - -static void QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel); - -static void QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel); - - -/** - @brief Decode the next item as a date string. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pDateString The decoded date. - - This decodes the standard CBOR date/time string tag, integer tag - number of 0, or encoded CBOR that is not a tag, but borrows the - date string content format. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and - @ref QCBOR_TYPE_DATE_STRING. -*/ -static void QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - - -/** - @brief Decode the next item as a date-only string. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pDateString The decoded date. - - This decodes the CBOR date-only string tag, integer tag - number of 1004, or encoded CBOR that is not a tag, but borrows the - date-only string content format. An example of the format - is "1985-04-12". - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and - @ref QCBOR_TYPE_DAYS_STRING. -*/ -static void QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); +static void +QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); +static void +QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); /** - @brief Decode the next item as an epoch date. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnTime The decoded epoch date. - - This decodes the standard CBOR epoch date/time tag, integer tag - number of 1. This will also decode any integer or floating-point - number as an epoch date (a tag 1 epoch date is just an integer or - floating-point number). - - This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer will - not fit in an @c int64_t. Note that an @c int64_t can represent a - range of over 500 billion years with one second resolution. - - Floating-point dates are always returned as an @c int64_t. The - fractional part is discarded. - - If the input is a floating-point date and the QCBOR library is - compiled with some or all floating-point features disabled, the - following errors will be set. If the input is half-precision and - half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED is - set. This function needs hardware floating-point to convert the - floating-point value to an integer so if HW floating point is - disabled QCBOR_ERR_HW_FLOAT_DISABLED is set. If all floating-point is - disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED is set. A previous - version of this function would return @ref QCBOR_ERR_FLOAT_DATE_DISABLED - in some, but not all, cases when floating-point decoding was disabled. - - Floating-point dates that are plus infinity, minus infinity or NaN - (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW error. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddDateEpoch() and - @ref QCBOR_TYPE_DATE_EPOCH. -*/ -void QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnTime); - -void QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnTime); + * @brief Decode the next item as base64URL encoded text. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pB64Text The decoded base64 text. + * + * This decodes a standard CBOR base64url tag, integer tag number of + * 33, or encoded CBOR that is not a tag, that is base64url encoded + * bytes encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Note that this does not actually remove the base64url encoding. + * + * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and + * @ref QCBOR_TYPE_BASE64URL. + */ +static void +QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); -void QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnTime); +static void +QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); +static void +QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); /** - @brief Decode the next item as an days-count epoch date. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnDays The decoded epoch date. - - This decodes the CBOR epoch date tag, integer tag number of 100, or - encoded CBOR that is not a tag, but borrows the content format. The - date is the number of days (not number of seconds) before or after - Jan 1, 1970. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and - @ref QCBOR_TYPE_DAYS_EPOCH. -*/ -void QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnDays); - -void QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnDays); - -void QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnDays); + * @brief Decode the next item as a regular expression. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pRegex The decoded regular expression. + * + * This decodes a standard CBOR regex tag, integer tag number of 35, + * or encoded CBOR that is not a tag, that is a PERL-compatible + * regular expression encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and + * @ref QCBOR_TYPE_REGEX. + */ +static void +QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pRegex); +static void +QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pRegex); +static void +QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, + const char * szLabel, + uint8_t uTagRequirement, + UsefulBufC *pRegex); /** - @brief Decode the next item as a big number. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pValue The returned big number. - @param[out] pbIsNegative Is @c true if the big number is negative. This - is only valid when @c uTagRequirement is - @ref QCBOR_TAG_REQUIREMENT_TAG. - - This decodes a standard CBOR big number, integer tag number of 2 or - 3, or encoded CBOR that is not a tag, but borrows the content format. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - The big number is in network byte order. The first byte in @c pValue - is the most significant byte. There may be leading zeros. - - The negative value is computed as -1 - n, where n is the postive big - number in @c pValue. There is no standard representation for - big numbers, positive or negative in C, so this implementation leaves - it up to the caller to apply this computation for negative big numbers. - - See @ref Tag-Usage for discussion on tag requirements. - - Determination of the sign of the big number depends on the tag - requirement of the protocol using the big number. If the protocol - requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign - indication is in the protocol and @c pbIsNegative indicates the - sign. If the protocol doesn't use a tag, @ref - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, then the protocol design must have some - way of indicating the sign. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big numbers. - - See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM, - QCBOREncode_AddPositiveBignum(), QCBOREncode_AddNegativeBignum(), - @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM. - -*/ -// Improvement: Add function that converts integers and other to big nums -void QCBORDecode_GetBignum(QCBORDecodeContext *pCtx, + * @brief Decode the next item as a MIME message. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pMessage The decoded regular expression. + * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. + * + * This decodes the standard CBOR MIME and binary MIME tags, integer + * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that + * is a MIME message encoded in a text or binary string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * The MIME message itself is not parsed. + * + * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is + * @c true. The difference between the two is that tag 36 is utf8 and + * tag 257 is a byte string that can carry binary MIME. QCBOR + * processes them exactly the same. Possibly the difference can be + * ignored. NULL can be passed to have no value returned. + * + * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, + * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and + * @ref QCBOR_TYPE_BINARY_MIME. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. + */ +static void +QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); + UsefulBufC *pMessage, + bool *pbIsTag257); + +static void +QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257); -void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); -void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx, +static void +QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); - - - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/** - @brief Decode the next item as a decimal fraction. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnMantissa The mantissa. - @param[out] pnExponent The base 10 exponent. - - This decodes a standard CBOR decimal fraction, integer tag number of - 4, or encoded CBOR that is not a tag, but borrows the content format. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - The value of this is computed by: - - mantissa * ( 10 ** exponent ) - - In the encoded CBOR, the mantissa and exponent may be of CBOR type 0 - (positive integer), type 1 (negative integer), type 2 tag 2 (positive - big number) or type 2 tag 3 (negative big number). This - implementation will attempt to convert all of these to an @c - int64_t. If the value won't fit, @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW or - QCBOR_ERR_BAD_EXP_AND_MANTISSA will be set. - - This implementation limits the exponent to between @c INT64_MIN and - @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to - @c UINT64_MAX. - - Various format and type issues will result in @ref - QCBOR_ERR_BAD_EXP_AND_MANTISSA being set. - - See @ref Tag-Usage for discussion on tag requirements. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big numbers. - - See also @ref CBOR_TAG_DECIMAL_FRACTION, - QCBOREncode_AddDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION - and QCBORDecode_GetDecimalFractionBig(). - - If QCBOR_DISABLE_TAGS is set, the only input this will decode is - an array of two integers. It will set an error if the the array is preceded - by by a tag number or if the mantissa is a big number. -*/ -void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - - -/** - @brief Decode the next item as a decimal fraction with a big number mantissa. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[in] MantissaBuffer The buffer in which to put the mantissa. - @param[out] pMantissa The big num mantissa. - @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. - @param[out] pnExponent The base 10 exponent. - - This is the same as QCBORDecode_GetDecimalFraction() except the - mantissa is returned as a big number. - - In the encoded CBOR, the mantissa may be a type 0 (positive integer), - type 1 (negative integer), type 2 tag 2 (positive big number) or type - 2 tag 3 (negative big number). This implementation will convert all - these to a big number. The limit to this conversion is the size of @c - MantissaBuffer. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert decimal - fractions. - - See also @ref CBOR_TAG_DECIMAL_FRACTION, - QCBOREncode_AddDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION - and QCBORDecode_GetDecimalFraction(). -*/ -void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pbMantissaIsNegative, - bool *pbIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - + UsefulBufC *pMessage, + bool *pbIsTag257); /** - @brief Decode the next item as a big float. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnMantissa The mantissa. - @param[out] pnExponent The base 2 exponent. - - This decodes a standard CBOR big float, integer tag number of 5, or - encoded CBOR that is not a tag, but borrows the content format. - - This is the same as QCBORDecode_GetDecimalFraction() with the - important distinction that the value is computed by: - - mantissa * ( 2 ** exponent ) - - If the mantissa is a tag that is a positive or negative big number, - this will attempt to fit it into the int64_t that @c pnMantissa is - and set an overflow error if it doesn't fit. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big floats. - - See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddBigFloat(), @ref - QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloatBig(). + * @brief Decode the next item as a UUID. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pUUID The decoded UUID + * + * This decodes a standard CBOR UUID tag, integer tag number of 37, or + * encoded CBOR that is not a tag, that is a UUID encoded in a byte + * string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and + * @ref QCBOR_TYPE_UUID. */ -void QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - - -/** - @brief Decode the next item as a big float with a big number mantissa. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[in] MantissaBuffer The buffer in which to put the mantissa. - @param[out] pMantissa The big num mantissa. - @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. - @param[out] pnExponent The base 2 exponent. - - This is the same as QCBORDecode_GetDecimalFractionBig() with the - important distinction that the value is computed by: - - mantissa * ( 2 ** exponent ) - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big floats. +static void +QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pUUID); - See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddBigFloat(), - @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloat(). - */ -void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx, +static void +QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); -#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */ + UsefulBufC *pUUID); +static void +QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pUUID); /** - @brief Decode the next item as a URI. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pURI The decoded URI. - - This decodes a standard CBOR URI tag, integer tag number of 32, - or encoded CBOR that is not a tag, that is a URI encoded in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_URI, QCBOREncode_AddURI() and - @ref QCBOR_TYPE_URI. + * @brief Decode some byte-string wrapped CBOR. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). + * + * This is for use on some CBOR that has been wrapped in a byte + * string. There are several ways that this can occur. + * + * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item + * and 63 a CBOR sequence. This implementation doesn't distinguish + * between the two (it would be more code and doesn't seem important). + * + * The @ref Tag-Usage discussion on the tag requirement applies here + * just the same as any other tag. + * + * In other cases, CBOR is wrapped in a byte string, but it is + * identified as CBOR by other means. The contents of a COSE payload + * are one example of that. They can be identified by the COSE content + * type, or they can be identified as CBOR indirectly by the protocol + * that uses COSE. for example, if a blob of CBOR is identified as a + * CWT, then the COSE payload is CBOR. To enter into CBOR of this + * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c + * uTagRequirement argument. + * + * Note that byte string wrapped CBOR can also be decoded by getting + * the byte string with QCBORDecode_GetItem() or + * QCBORDecode_GetByteString() and feeding it into another instance of + * QCBORDecode. Doing it with this function has the advantage of using + * less memory as another instance of QCBORDecode is not necessary. + * + * When the wrapped CBOR is entered with this function, the pre-order + * traversal and such are bounded to the wrapped + * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume + * processing CBOR outside the wrapped CBOR. + * + * This does not work on indefinite-length strings. The + * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set. + * + * If @c pBstr is not @c NULL the pointer and length of the wrapped + * CBOR will be returned. This is usually not needed, but sometimes + * useful, particularly in the case of verifying signed data like the + * COSE payload. This is usually the pointer and length of the data is + * that is hashed or MACed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and + * QCBORDecode_EnterArray(). */ -static void QCBORDecode_GetURI(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - - -/** - @brief Decode the next item as base64 encoded text. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pB64Text The decoded base64 text. - - This decodes a standard CBOR base64 tag, integer tag number of 34, or - encoded CBOR that is not a tag, that is base64 encoded bytes encoded - in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - Note that this does not actually remove the base64 encoding. - - See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and - @ref QCBOR_TYPE_BASE64. -*/ -static void QCBORDecode_GetB64(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); +void +QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pBstr); -static void QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, +void +QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint8_t uTagRequirement, - UsefulBufC *pB64Text); + UsefulBufC *pBstr); -static void QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, +void +QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -/** - @brief Decode the next item as base64URL encoded text. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pB64Text The decoded base64 text. - - This decodes a standard CBOR base64url tag, integer tag number of 33, - or encoded CBOR that is not a tag, that is base64url encoded bytes - encoded in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. + UsefulBufC *pBstr); - Note that this does not actually remove the base64url encoding. - - See also @ref CBOR_TAG_B64URL, QCBOREncode_AddB64URLText() and - @ref QCBOR_TYPE_BASE64URL. -*/ -static void QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); /** - @brief Decode the next item as a regular expression. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pRegex The decoded regular expression. - - This decodes a standard CBOR regex tag, integer tag number of 35, or - encoded CBOR that is not a tag, that is a PERL-compatible regular - expression encoded in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_REGEX, QCBOREncode_AddRegex() and - @ref QCBOR_TYPE_REGEX. - */ -static void QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - - -/** - @brief Decode the next item as a MIME message. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pMessage The decoded regular expression. - @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. - - This decodes the standard CBOR MIME and binary MIME tags, integer tag - numbers of 36 or 257, or encoded CBOR that is not a tag, that is a - MIME message encoded in a text or binary string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - The MIME message itself is not parsed. - - This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 - is @c true. The difference between the two is that - tag 36 is utf8 and tag 257 is a byte string that can - carry binary MIME. QCBOR processes them exactly - the same. Possibly the difference can be ignored. - NULL can be passed to have no value returned. - - See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, - QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and - @ref QCBOR_TYPE_BINARY_MIME. - - This does no translation of line endings. See QCBOREncode_AddText() - for a discussion of line endings in CBOR. -*/ -static void QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -static void QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - - -static void QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -/** - @brief Decode the next item as a UUID - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pUUID The decoded UUID - - This decodes a standard CBOR UUID tag, integer tag number of 37, or - encoded CBOR that is not a tag, that is a UUID encoded in a byte - string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddBinaryUUID() and - @ref QCBOR_TYPE_UUID. + * @brief Exit some bstr-wrapped CBOR has been enetered. + * + * @param[in] pCtx The decode context. + * + * Bstr-wrapped CBOR must have been entered for this to succeed. + * + * The items in the wrapped CBOR that was entered do not have to have + * been consumed for this to succeed. + * + * The this sets the traversal cursor to the item after the + * byte string that was exited. */ -static inline void QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -inline static void QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -inline static void QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); +void +QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); -/** - @brief Decode some byte-string wrapped CBOR. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). - - This is for use on some CBOR that has been wrapped in a byte - string. There are several ways that this can occur. - - First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item and - 63 a CBOR sequence. This implementation doesn't distinguish between - the two (it would be more code and doesn't seem important). - - The @ref Tag-Usage discussion on the tag requirement applies here - just the same as any other tag. - - In other cases, CBOR is wrapped in a byte string, but it is - identified as CBOR by other means. The contents of a COSE payload are - one example of that. They can be identified by the COSE content type, - or they can be identified as CBOR indirectly by the protocol that - uses COSE. for example, if a blob of CBOR is identified as a CWT, - then the COSE payload is CBOR. To enter into CBOR of this type use - the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c uTagRequirement - argument. - - Note that byte string wrapped CBOR can also be decoded by getting the - byte string with QCBORDecode_GetItem() or QCBORDecode_GetByteString() - and feeding it into another instance of QCBORDecode. Doing it with - this function has the advantage of using less memory as another - instance of QCBORDecode is not necessary. - - When the wrapped CBOR is entered with this function, the pre-order - traversal and such are bounded to the wrapped - CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume processing - CBOR outside the wrapped CBOR. - - This does not (currently) work on indefinite-length strings. The - (confusing) error @ref QCBOR_ERR_INPUT_TOO_LARGE will be set. - - If @c pBstr is not @c NULL the pointer and length of the wrapped - CBOR will be returned. This is usually not needed, but sometimes - useful, particularly in the case of verifying signed data like the - COSE payload. This is usually the pointer and length of the - data is that is hashed or MACed. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and - QCBORDecode_EnterArray(). - */ -void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pBstr); -void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); +/* ========================================================================= * + * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * + * ========================================================================= */ -void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem); -/** - @brief Exit some bstr-wrapped CBOR has been enetered. +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem); - @param[in] pCtx The decode context. - Bstr-wrapped CBOR must have been entered for this to succeed. +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem); - The items in the wrapped CBOR that was entered do not have to have been - consumed for this to succeed. +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pCtx, + uint8_t uType, + QCBORItem *pItem); - The this sets the pre-order traversal cursor to the item after - the byte string that was exited. -*/ -void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pCtx, + uint8_t uType); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem); -/* =========================================================================== - BEGINNING OF PRIVATE INLINE IMPLEMENTATION - ========================================================================== */ +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem); -// Semi-private +#ifndef USEFULBUF_DISABLE_ALL_FLOAT +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe, +QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pCtx, uint32_t uConvertTypes, - uint64_t *puValue, + double *pValue, QCBORItem *pItem); -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetUInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, +QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint32_t uConvertTypes, - uint64_t *puValue, + double *pdValue, QCBORItem *pItem); -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetUInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, +QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint32_t uConvertTypes, - uint64_t *puValue, + double *pdValue, QCBORItem *pItem); +#endif /* !USEFULBUF_DISABLE_ALL_FLOAT */ + +#define QCBOR_TAGSPEC_NUM_TYPES 4 +/* Semi-private data structure (which might change). + * + * See QCBOR_Private_CheckTagRequirement() which uses this to check the + * type of an item to be decoded as a tag or tag content. + * + * Improvement: Carefully understand what compilers do with this, + * particularly initialization and see if it can be optimized so there + * is less code and maybe so it can be smaller. + */ +typedef struct { + /* One of QCBOR_TAGSPEC_MATCH_xxx */ + uint8_t uTagRequirement; + /* The tagged type translated into QCBOR_TYPE_XXX. Used to match + * explicit tagging */ + uint8_t uTaggedTypes[QCBOR_TAGSPEC_NUM_TYPES]; + /* The types of the content, which are used to match implicit + * tagging */ + uint8_t uAllowedContentTypes[QCBOR_TAGSPEC_NUM_TYPES]; +} QCBOR_Private_TagSpec; -void QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - uint64_t *puValue) +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pCtx, + QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pBstr); + + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString); + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString); + + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +QCBORError +QCBORDecode_Private_GetMIME(uint8_t uTagRequirement, + const QCBORItem *pItem, + UsefulBufC *pMessage, + bool *pbIsTag257); + + + + + +static inline void +QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternal(pMe, uConvertTypes, puValue, &Item); + QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item); } -inline static void +static inline void QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, + const int64_t nLabel, + const uint32_t uConvertTypes, uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapN(pMe, nLabel, uConvertTypes, puValue, &Item); } -inline static void +static inline void QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, puValue, @@ -1757,9 +2221,9 @@ QCBORDecode_GetUInt64(QCBORDecodeContext *pMe, uint64_t *puValue) QCBORDecode_GetUInt64Convert(pMe, QCBOR_CONVERT_TYPE_XINT64, puValue); } -inline static void +static inline void QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, uint64_t *puValue) { QCBORDecode_GetUInt64ConvertInMapN(pMe, @@ -1768,7 +2232,7 @@ QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pMe, puValue); } -inline static void +static inline void QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puValue) @@ -1780,103 +2244,188 @@ QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pMe, } -// Semi-private -void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, QCBORItem *pItem); - -// Semi-private -inline static void QCBORDecode_EnterMap(QCBORDecodeContext *pMe, QCBORItem *pItem) { - QCBORDecode_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_MAP, pItem); +static inline void +QCBORDecode_EnterMap(QCBORDecodeContext *pMe, QCBORItem *pItem) { + QCBORDecode_Private_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_MAP, pItem); } -// Semi-private -inline static void QCBORDecode_EnterArray(QCBORDecodeContext *pMe, QCBORItem *pItem) { - QCBORDecode_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY, pItem); +static inline void +QCBORDecode_EnterArray(QCBORDecodeContext *pMe, QCBORItem *pItem) { + QCBORDecode_Private_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY, pItem); } -// Semi-private -void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType); - -static inline void QCBORDecode_ExitArray(QCBORDecodeContext *pMe) +static inline void +QCBORDecode_ExitArray(QCBORDecodeContext *pMe) { - QCBORDecode_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY); + QCBORDecode_Private_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY); } -static inline void QCBORDecode_ExitMap(QCBORDecodeContext *pMe) +static inline void +QCBORDecode_ExitMap(QCBORDecodeContext *pMe) { - QCBORDecode_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_MAP); + QCBORDecode_Private_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_MAP); } -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); +QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx, + uint8_t uType, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -// Semi-private -void -QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); +QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx, + QCBORItem *pTarget, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); + + +static inline void +QCBORDecode_GetArray(QCBORDecodeContext *pMe, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_ARRAY, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; + OneItemSeach[0].label.int64 = nLabel; + OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; + OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); + OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +#else + (void)szLabel; + (void)pItem; + (void)pEncodedCBOR; + pMe->uLastError = QCBOR_ERR_MAP_LABEL_TYPE; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +} + +static inline void +QCBORDecode_GetMap(QCBORDecodeContext *pMe, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_MAP, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; + OneItemSeach[0].label.int64 = nLabel; + OneItemSeach[0].uDataType = QCBOR_TYPE_MAP; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; -inline static void + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; + OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); + OneItemSeach[0].uDataType = QCBOR_TYPE_MAP; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +#else + (void)szLabel; + (void)pItem; + (void)pEncodedCBOR; + pMe->uLastError = QCBOR_ERR_MAP_LABEL_TYPE; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +} + + + +static inline void QCBORDecode_GetInt64Convert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternal(pMe, uConvertTypes, pnValue, &Item); + QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item); } -inline static void +static inline void QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, + const int64_t nLabel, + const uint32_t uConvertTypes, int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetInt64ConvertInMapN(pMe, nLabel, uConvertTypes, pnValue, &Item); } -inline static void +static inline void QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, pnValue, &Item); } -inline static void +static inline void QCBORDecode_GetInt64(QCBORDecodeContext *pMe, int64_t *pnValue) { QCBORDecode_GetInt64Convert(pMe, QCBOR_CONVERT_TYPE_XINT64, pnValue); } -inline static void +static inline void QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, int64_t *pnValue) { QCBORDecode_GetInt64ConvertInMapN(pMe, @@ -1885,7 +2434,7 @@ QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pMe, pnValue); } -inline static void +static inline void QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pMe, const char *szLabel, int64_t *pnValue) @@ -1901,76 +2450,52 @@ QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pMe, #ifndef USEFULBUF_DISABLE_ALL_FLOAT -// Semi-private -void -QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - double *pValue, - QCBORItem *pItem); - -// Semi-private -void -QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem); - -// Semi-private -void -QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem); - - -inline static void +static inline void QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, double *pdValue) { - QCBORItem Item; - QCBORDecode_GetDoubleConvertInternal(pMe, uConvertTypes, pdValue, &Item); + QCBORItem Item; + QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item); } -inline static void +static inline void QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, uint32_t uConvertTypes, double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapN(pMe, + QCBORDecode_Private_GetDoubleConvertInMapN(pMe, nLabel, uConvertTypes, pdValue, &Item); } -inline static void +static inline void QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe, szLabel, uConvertTypes, pdValue, &Item); } -inline static void +static inline void QCBORDecode_GetDouble(QCBORDecodeContext *pMe, double *pValue) { QCBORDecode_GetDoubleConvert(pMe, QCBOR_CONVERT_TYPE_FLOAT, pValue); } -inline static void +static inline void QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, double *pdValue) { QCBORDecode_GetDoubleConvertInMapN(pMe, @@ -1979,7 +2504,7 @@ QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pMe, pdValue); } -inline static void +static inline void QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, double *pdValue) @@ -1993,96 +2518,49 @@ QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pMe, -#define QCBOR_TAGSPEC_NUM_TYPES 4 -/* Semi-private data structure (which might change). - * - * See CheckTagRequirement() which uses this to check the type of a - * item to be decoded as a tag or tag content. - * - * Improvement: Carefully understand what compilers do with this, - * particularly initialization and see if it can be optimized so there - * is less code and maybe so it can be smaller. - */ -typedef struct { - /* One of QCBOR_TAGSPEC_MATCH_xxx */ - uint8_t uTagRequirement; - /* The tagged type translated into QCBOR_TYPE_XXX. Used to match - * explicit tagging */ - uint8_t uTaggedTypes[QCBOR_TAGSPEC_NUM_TYPES]; - /* The types of the content, which are used to match implicit - * tagging */ - uint8_t uAllowedContentTypes[QCBOR_TAGSPEC_NUM_TYPES]; -} TagSpecification; - - -// Semi private -void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, - TagSpecification TagSpec, - UsefulBufC *pBstr); - - -// Semi private -void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - TagSpecification TagSpec, - UsefulBufC *pString); - -// Semi private -void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - TagSpecification TagSpec, - UsefulBufC *pString); - - -// Semi private -QCBORError QCBORDecode_GetMIMEInternal(uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pMessage, - bool *pbIsTag257); - static inline void QCBORDecode_GetByteString(QCBORDecodeContext *pMe, UsefulBufC *pValue) { // Complier should make this just a 64-bit integer parameter - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, UsefulBufC *pBstr) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pBstr); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pBstr); } -inline static void +static inline void QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, UsefulBufC *pBstr) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pBstr); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pBstr); } @@ -2090,46 +2568,46 @@ static inline void QCBORDecode_GetTextString(QCBORDecodeContext *pMe, UsefulBufC *pValue) { // Complier should make this just 64-bit integer parameter - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, UsefulBufC *pText) { // This TagSpec only matches text strings; it also should optimize down // to passing a 64-bit integer - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); } -inline static void +static inline void QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); } static inline void @@ -2145,7 +2623,7 @@ QCBORDecode_GetNull(QCBORDecodeContext *pMe) static inline void QCBORDecode_GetNullInMapN(QCBORDecodeContext *pMe, - int64_t nLabel) + const int64_t nLabel) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_NULL, &Item); @@ -2153,7 +2631,7 @@ QCBORDecode_GetNullInMapN(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel) + const char *szLabel) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_NULL, &Item); @@ -2172,7 +2650,7 @@ QCBORDecode_GetUndefined(QCBORDecodeContext *pMe) static inline void QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pMe, - int64_t nLabel) + const int64_t nLabel) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_UNDEF, &Item); @@ -2180,304 +2658,309 @@ QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel) + const char *szLabel) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_UNDEF, &Item); } + static inline void QCBORDecode_GetDateString(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pValue) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); } -inline static void +static inline void QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); } static inline void QCBORDecode_GetDaysString(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pValue) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); } -inline static void +static inline void QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); } -static inline void QCBORDecode_GetURI(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pUUID) +static inline void +QCBORDecode_GetURI(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); } -static inline void QCBORDecode_GetB64(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pB64Text) +static inline void +QCBORDecode_GetB64(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text); } -inline static void QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text) +static inline void +QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); } -inline static void +static inline void QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); } static inline void QCBORDecode_GetB64URL(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text); } -inline static void +static inline void QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); } -inline static void +static inline void QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); } -static inline void QCBORDecode_GetRegex(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pRegex) +static inline void +QCBORDecode_GetRegex(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pRegex) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pRegex); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pRegex); } static inline void QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pRegex) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pRegex); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pRegex); } static inline void QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe, const char * szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pRegex) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pRegex); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pRegex); } static inline void QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pMessage, bool *pbIsTag257) { if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing + /* Already in error state, do nothing */ return; } @@ -2488,7 +2971,7 @@ QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)QCBORDecode_GetMIMEInternal(uTagRequirement, + pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, &Item, pMessage, pbIsTag257); @@ -2496,8 +2979,8 @@ QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pMessage, bool *pbIsTag257) { @@ -2505,7 +2988,7 @@ QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_GetMIMEInternal(uTagRequirement, + pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, &Item, pMessage, pbIsTag257); @@ -2515,7 +2998,7 @@ QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pMessage, bool *pbIsTag257) { @@ -2523,7 +3006,7 @@ QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_GetMIMEInternal(uTagRequirement, + pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, &Item, pMessage, pbIsTag257); @@ -2533,51 +3016,54 @@ QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); } +/* ======================================================================== * + * END OF PRIVATE INLINE IMPLEMENTATION * + * ======================================================================== */ #ifdef __cplusplus } diff --git a/3rdparty/exported/QCBOR/src/UsefulBuf.c b/3rdparty/exported/QCBOR/src/UsefulBuf.c index b36e5d00d36d..4a7970f9e133 100644 --- a/3rdparty/exported/QCBOR/src/UsefulBuf.c +++ b/3rdparty/exported/QCBOR/src/UsefulBuf.c @@ -1,33 +1,36 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, 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. - =============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ + + /*============================================================================= FILE: UsefulBuf.c @@ -41,9 +44,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. when who what, where, why -------- ---- --------------------------------------------------- + 08/08/2024 llundblade Add UsefulOutBuf_SubString(). + 21/05/2024 llundblade Comment formatting and some code tidiness. 19/12/2022 llundblade Don't pass NULL to memmove when adding empty data. 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf - 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual + 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual 01/28/2020 llundblade Refine integer signedness to quiet static analysis. 01/08/2020 llundblade Documentation corrections & improved code formatting. 11/08/2019 llundblade Re check pointer math and update comments @@ -61,18 +66,20 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UsefulBuf.h" -// used to catch use of uninitialized or corrupted UsefulOutBuf +/* used to catch use of uninitialized or corrupted UsefulOutBuf */ #define USEFUL_OUT_BUF_MAGIC (0x0B0F) /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src) { - // Do this with subtraction so it doesn't give erroneous - // result if uOffset + Src.len overflows - if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len + /* Do this with subtraction so it doesn't give an erroneous + * result if uOffset + Src.len overflows. Right side is equivalent to + * uOffset + Src.len > Dest.len + */ + if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { return NULLUsefulBufC; } @@ -83,24 +90,25 @@ UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2) { - // use the comparisons rather than subtracting lengths to - // return an int instead of a size_t + /* Use comparisons rather than subtracting lengths to + * return an int instead of a size_t + */ if(UB1.len < UB2.len) { return -1; } else if (UB1.len > UB2.len) { return 1; - } // else UB1.len == UB2.len + } /* else UB1.len == UB2.len */ return memcmp(UB1.ptr, UB2.ptr, UB1.len); } /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) { @@ -113,7 +121,7 @@ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) for(const uint8_t *p = UB.ptr; p < pEnd; p++) { if(*p != uValue) { /* Byte didn't match */ - /* Cast from signed to unsigned . Safe because the loop increments.*/ + /* Cast from signed to unsigned. Safe because the loop increments.*/ return (size_t)(p - (const uint8_t *)UB.ptr); } } @@ -124,7 +132,7 @@ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) { @@ -133,7 +141,11 @@ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) } for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) { - if(!UsefulBuf_Compare((UsefulBufC){((const uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) { + UsefulBufC SearchNext; + + SearchNext.ptr = ((const uint8_t *)BytesToSearch.ptr) + uPos; + SearchNext.len = BytesToFind.len; + if(!UsefulBuf_Compare(SearchNext, BytesToFind)) { return uPos; } } @@ -143,9 +155,9 @@ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) /* - Public function -- see UsefulBuf.h - - Code Reviewers: THIS FUNCTION DOES POINTER MATH + * Public function -- see UsefulBuf.h + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH */ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) { @@ -154,17 +166,18 @@ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) pMe->UB = Storage; #if 0 - // This check is off by default. - - // The following check fails on ThreadX - - // Sanity check on the pointer and size to be sure we are not - // passed a buffer that goes off the end of the address space. - // Given this test, we know that all unsigned lengths less than - // me->size are valid and won't wrap in any pointer additions - // based off of pStorage in the rest of this code. + /* This check is off by default. + * + * The following check fails on ThreadX + * + * Sanity check on the pointer and size to be sure we are not + * passed a buffer that goes off the end of the address space. + * Given this test, we know that all unsigned lengths less than + * me->size are valid and won't wrap in any pointer additions + * based off of pStorage in the rest of this code. + */ const uintptr_t ptrM = UINTPTR_MAX - Storage.len; - if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) // Check #0 + if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) /* Check #0 */ me->err = 1; #endif } @@ -172,101 +185,107 @@ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) /* - Public function -- see UsefulBuf.h - - The core of UsefulOutBuf -- put some bytes in the buffer without writing off - the end of it. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - - This function inserts the source buffer, NewData, into the destination - buffer, me->UB.ptr. - - Destination is represented as: - me->UB.ptr -- start of the buffer - me->UB.len -- size of the buffer UB.ptr - me->data_len -- length of value data in UB - - Source is data: - NewData.ptr -- start of source buffer - NewData.len -- length of source buffer - - Insertion point: - uInsertionPos. - - Steps: - - 0. Corruption checks on UsefulOutBuf - - 1. Figure out if the new data will fit or not - - 2. Is insertion position in the range of valid data? - - 3. If insertion point is not at the end, slide data to the right of the - insertion point to the right - - 4. Put the new data in at the insertion position. - + * Public function -- see UsefulBuf.h + * + * The core of UsefulOutBuf -- put some bytes in the buffer without writing off + * the end of it. + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH + * + * This function inserts the source buffer, NewData, into the destination + * buffer, me->UB.ptr. + * + * Destination is represented as: + * me->UB.ptr -- start of the buffer + * me->UB.len -- size of the buffer UB.ptr + * me->data_len -- length of value data in UB + * + * Source is data: + * NewData.ptr -- start of source buffer + * NewData.len -- length of source buffer + * + * Insertion point: + * uInsertionPos. + * + * Steps: + * + * 0. Corruption checks on UsefulOutBuf + * + * 1. Figure out if the new data will fit or not + * + * 2. Is insertion position in the range of valid data? + * + * 3. If insertion point is not at the end, slide data to the right of the + * insertion point to the right + * + * 4. Put the new data in at the insertion position. + * */ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos) { if(pMe->err) { - // Already in error state. + /* Already in error state. */ return; } - /* 0. Sanity check the UsefulOutBuf structure */ - // A "counter measure". If magic number is not the right number it - // probably means me was not initialized or it was corrupted. Attackers - // can defeat this, but it is a hurdle and does good with very - // little code. + /* 0. Sanity check the UsefulOutBuf structure + * A "counter measure". If magic number is not the right number it + * probably means pMe was not initialized or it was corrupted. Attackers + * can defeat this, but it is a hurdle and does good with very + * little code. + */ if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { pMe->err = 1; - return; // Magic number is wrong due to uninitalization or corrption + return; /* Magic number is wrong due to uninitalization or corrption */ } - // Make sure valid data is less than buffer size. This would only occur - // if there was corruption of me, but it is also part of the checks to - // be sure there is no pointer arithmatic under/overflow. - if(pMe->data_len > pMe->UB.len) { // Check #1 + /* Make sure valid data is less than buffer size. This would only occur + * if there was corruption of me, but it is also part of the checks to + * be sure there is no pointer arithmatic under/overflow. + */ + if(pMe->data_len > pMe->UB.len) { /* Check #1 */ pMe->err = 1; - // Offset of valid data is off the end of the UsefulOutBuf due to - // uninitialization or corruption + /* Offset of valid data is off the end of the UsefulOutBuf due to + * uninitialization or corruption + */ return; } - /* 1. Will it fit? */ - // WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len) - // Check #1 makes sure subtraction in RoomLeft will not wrap around - if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { // Check #2 - // The new data will not fit into the the buffer. + /* 1. Will it fit? + * WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len) + * Check #1 makes sure subtraction in RoomLeft will not wrap around + */ + if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { /* Check #2 */ + /* The new data will not fit into the the buffer. */ pMe->err = 1; return; } - /* 2. Check the Insertion Position */ - // This, with Check #1, also confirms that uInsertionPos <= me->data_len and - // that uInsertionPos + pMe->UB.ptr will not wrap around the end of the - // address space. - if(uInsertionPos > pMe->data_len) { // Check #3 - // Off the end of the valid data in the buffer. + /* 2. Check the Insertion Position + * This, with Check #1, also confirms that uInsertionPos <= me->data_len and + * that uInsertionPos + pMe->UB.ptr will not wrap around the end of the + * address space. + */ + if(uInsertionPos > pMe->data_len) { /* Check #3 */ + /* Off the end of the valid data in the buffer. */ pMe->err = 1; return; } /* 3. Slide existing data to the right */ if (!UsefulOutBuf_IsBufferNULL(pMe)) { - uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; // PtrMath #1 - size_t uNumBytesToMove = pMe->data_len - uInsertionPos; // PtrMath #2 - uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3 + uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; /* PtrMath #1 */ + size_t uNumBytesToMove = pMe->data_len - uInsertionPos; /* PtrMath #2 */ + uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; /* PtrMath #3*/ - // To know memmove won't go off end of destination, see PtrMath #4 - // Use memove because it handles overlapping buffers + /* To know memmove won't go off end of destination, see PtrMath #4. + * Use memove because it handles overlapping buffers + */ memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove); /* 4. Put the new data in */ uint8_t *pInsertionPoint = pSourceOfMove; - // To know memmove won't go off end of destination, see PtrMath #5 + /* To know memmove won't go off end of destination, see PtrMath #5 */ if(NewData.ptr != NULL) { memmove(pInsertionPoint, NewData.ptr, NewData.len); } @@ -277,30 +296,30 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t /* - Rationale that describes why the above pointer math is safe - - PtrMath #1 will never wrap around over because - Check #0 in UsefulOutBuf_Init makes sure me->UB.ptr + me->UB.len doesn't wrap - Check #1 makes sure me->data_len is less than me->UB.len - Check #3 makes sure uInsertionPos is less than me->data_len - - PtrMath #2 will never wrap around under because - Check #3 makes sure uInsertionPos is less than me->data_len - - PtrMath #3 will never wrap around over because - PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len - Check #2 that NewData.len will fit in the unused space left in me->UB - - PtrMath #4 will never wrap under because - Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) - Check #3 makes sure uInsertionPos is less than me->data_len - Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) - This algebraically rearranges to me->size > uInsertionPos + NewData.len - - PtrMath #5 will never wrap under because - Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; - Check #1 makes sure me->data_len is less than me->size - Check #3 makes sure uInsertionPos is less than me->data_len + * Rationale that describes why the above pointer math is safe + * + * PtrMath #1 will never wrap around over because + * Check #0 in UsefulOutBuf_Init that me->UB.ptr + me->UB.len doesn't wrap + * Check #1 makes sure me->data_len is less than me->UB.len + * Check #3 makes sure uInsertionPos is less than me->data_len + * + * PtrMath #2 will never wrap around under because + * Check #3 makes sure uInsertionPos is less than me->data_len + * + * PtrMath #3 will never wrap around over because + * PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len + * Check #2 that NewData.len will fit in the unused space left in me->UB + * + * PtrMath #4 will never wrap under because + * Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) + * Check #3 makes sure uInsertionPos is less than me->data_len + * Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) + * This algebraically rearranges to me->size > uInsertionPos + NewData.len + * + * PtrMath #5 will never wrap under because + * Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; + * Check #1 makes sure me->data_len is less than me->size + * Check #3 makes sure uInsertionPos is less than me->data_len */ @@ -338,7 +357,7 @@ void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount) * checks to be sure there is no pointer arithmatic * under/overflow. */ - if(pMe->data_len > pMe->UB.len) { // Check #1 + if(pMe->data_len > pMe->UB.len) { /* Check #1 */ pMe->err = 1; /* Offset of valid data is off the end of the UsefulOutBuf due * to uninitialization or corruption. @@ -363,7 +382,7 @@ void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount) /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe) { @@ -381,9 +400,9 @@ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe) /* - Public function -- see UsefulBuf.h - - Copy out the data accumulated in to the output buffer. + * Public function -- see UsefulBuf.h + * + * Copy out the data accumulated in to the output buffer. */ UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest) { @@ -395,32 +414,60 @@ UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest) } +/* + * Public function -- see UsefulBuf.h + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ +UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe, + const size_t uStart, + const size_t uLen) +{ + const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe); + if(UsefulBuf_IsNULLC(Tmp)) { + return NULLUsefulBufC; + } -/* - Public function -- see UsefulBuf.h + if(uStart > Tmp.len) { + return NULLUsefulBufC; + } - The core of UsefulInputBuf -- consume bytes without going off end of buffer. + if(Tmp.len - uStart < uLen) { + return NULLUsefulBufC; + } - Code Reviewers: THIS FUNCTION DOES POINTER MATH + UsefulBufC SubString; + SubString.ptr = (const uint8_t *)Tmp.ptr + uStart; + SubString.len = uLen; + + return SubString; +} + + +/* + * Public function -- see UsefulBuf.h + * + * The core of UsefulInputBuf -- consume bytes without going off end of buffer. + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH */ const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount) { - // Already in error state. Do nothing. + /* Already in error state. Do nothing. */ if(pMe->err) { return NULL; } if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) { - // Number of bytes asked for at current position are more than available + /* Number of bytes asked for is more than available */ pMe->err = 1; return NULL; } - // This is going to succeed + /* This is going to succeed */ const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor; - // Will not overflow because of check using UsefulInputBuf_BytesAvailable() + /* Won't overflow because of check using UsefulInputBuf_BytesAvailable() */ pMe->cursor += uAmount; return result; } - diff --git a/3rdparty/exported/QCBOR/src/ieee754.c b/3rdparty/exported/QCBOR/src/ieee754.c index a8079f8cff0c..17443680c1e2 100644 --- a/3rdparty/exported/QCBOR/src/ieee754.c +++ b/3rdparty/exported/QCBOR/src/ieee754.c @@ -1,71 +1,63 @@ -/*============================================================================== - ieee754.c -- floating-point conversion between half, double & single-precision - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 7/23/18 - =============================================================================*/ +/* ========================================================================== + * ieee754.c -- floating-point conversion between half, double & single-precision + * + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 7/23/18 + * ========================================================================== */ /* - Include before QCBOR_DISABLE_PREFERRED_FLOAT is checked as - QCBOR_DISABLE_PREFERRED_FLOAT might be defined in qcbor/qcbor_common.h + * Include before QCBOR_DISABLE_PREFERRED_FLOAT is checked as + * QCBOR_DISABLE_PREFERRED_FLOAT might be defined in qcbor/qcbor_common.h */ #include "qcbor/qcbor_common.h" #ifndef QCBOR_DISABLE_PREFERRED_FLOAT #include "ieee754.h" -#include // For memcpy() +#include /* For memcpy() */ /* - This code is written for clarity and verifiability, not for size, on - the assumption that the optimizer will do a good job. The LLVM - optimizer, -Os, does seem to do the job and the resulting object code - is smaller from combining code for the many different cases (normal, - subnormal, infinity, zero...) for the conversions. GCC is no where near - as good. - - This code has really long lines and is much easier to read because of - them. Some coding guidelines prefer 80 column lines (can they not afford - big displays?). It would make this code much worse even to wrap at 120 - columns. - - Dead stripping is also really helpful to get code size down when - floating-point encoding is not needed. (If this is put in a library - and linking is against the library, then dead stripping is automatic). - - This code works solely using shifts and masks and thus has no - dependency on any math libraries. It can even work if the CPU doesn't - have any floating-point support, though that isn't the most useful - thing to do. - - The memcpy() dependency is only for CopyFloatToUint32() and friends - which only is needed to avoid type punning when converting the actual - float bits to an unsigned value so the bit shifts and masks can work. + * This code has long lines and is easier to read because of + * them. Some coding guidelines prefer 80 column lines (can they not + * afford big displays?). + * + * This code works solely using shifts and masks and thus has no + * dependency on any math libraries. It can even work if the CPU + * doesn't have any floating-point support, though that isn't the most + * useful thing to do. + * + * The memcpy() dependency is only for CopyFloatToUint32() and friends + * which only is needed to avoid type punning when converting the + * actual float bits to an unsigned value so the bit shifts and masks + * can work. + * + * The references used to write this code: + * + * IEEE 754-2008, particularly section 3.6 and 6.2.1 + * + * https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages + * + * https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values + * + * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules + * + * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be + * + * IEEE754_FloatToDouble(uint32_t uFloat) was created but is not + * needed. It can be retrieved from github history if needed. */ -/* - The references used to write this code: - - - IEEE 754-2008, particularly section 3.6 and 6.2.1 - - - https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages - - - https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values - - https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules - - - https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be - */ -// ----- Half Precsion ----------- +/* ----- Half Precsion ----------- */ #define HALF_NUM_SIGNIFICAND_BITS (10) #define HALF_NUM_EXPONENT_BITS (5) #define HALF_NUM_SIGN_BITS (1) @@ -74,16 +66,16 @@ #define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS) #define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS) -#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits // 0x03ff +#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits #define HALF_EXPONENT_MASK (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent -#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // // 0x8000 1 bit of sign +#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // 0x8000 1 bit of sign #define HALF_QUIET_NAN_BIT (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200 /* Biased Biased Unbiased Use - 0x00 0 -15 0 and subnormal - 0x01 1 -14 Smallest normal exponent - 0x1e 30 15 Largest normal exponent - 0x1F 31 16 NaN and Infinity */ + * 0x00 0 -15 0 and subnormal + * 0x01 1 -14 Smallest normal exponent + * 0x1e 30 15 Largest normal exponent + * 0x1F 31 16 NaN and Infinity */ #define HALF_EXPONENT_BIAS (15) #define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased #define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased @@ -91,7 +83,7 @@ #define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased -// ------ Single-Precision -------- +/* ------ Single-Precision -------- */ #define SINGLE_NUM_SIGNIFICAND_BITS (23) #define SINGLE_NUM_EXPONENT_BITS (8) #define SINGLE_NUM_SIGN_BITS (1) @@ -106,19 +98,19 @@ #define SINGLE_QUIET_NAN_BIT (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1)) /* Biased Biased Unbiased Use - 0x0000 0 -127 0 and subnormal - 0x0001 1 -126 Smallest normal exponent - 0x7f 127 0 1 - 0xfe 254 127 Largest normal exponent - 0xff 255 128 NaN and Infinity */ + * 0x0000 0 -127 0 and subnormal + * 0x0001 1 -126 Smallest normal exponent + * 0x7f 127 0 1 + * 0xfe 254 127 Largest normal exponent + * 0xff 255 128 NaN and Infinity */ #define SINGLE_EXPONENT_BIAS (127) -#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased -#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased -#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) // -127 unbiased -#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased +#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) +#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) +#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) +#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) -// --------- Double-Precision ---------- +/* --------- Double-Precision ---------- */ #define DOUBLE_NUM_SIGNIFICAND_BITS (52) #define DOUBLE_NUM_EXPONENT_BITS (11) #define DOUBLE_NUM_SIGN_BITS (1) @@ -134,372 +126,518 @@ /* Biased Biased Unbiased Use - 0x00000000 0 -1023 0 and subnormal - 0x00000001 1 -1022 Smallest normal exponent - 0x000007fe 2046 1023 Largest normal exponent - 0x000007ff 2047 1024 NaN and Infinity */ + * 0x00000000 0 -1023 0 and subnormal + * 0x00000001 1 -1022 Smallest normal exponent + * 0x000007fe 2046 1023 Largest normal exponent + * 0x000007ff 2047 1024 NaN and Infinity */ #define DOUBLE_EXPONENT_BIAS (1023) -#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) // unbiased -#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) // unbiased -#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) // unbiased -#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) // unbiased +#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) +#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) +#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) +#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) -/* - Convenient functions to avoid type punning, compiler warnings and - such. The optimizer reduces them to a simple assignment. This is a - crusty corner of C. It shouldn't be this hard. - These are also in UsefulBuf.h under a different name. They are copied - here to avoid a dependency on UsefulBuf.h. There is no object code - size impact because these always optimze down to a simple assignment. +/* + * Convenient functions to avoid type punning, compiler warnings and + * such. The optimizer reduces them to a simple assignment. This is a + * crusty corner of C. It shouldn't be this hard. + * + * These are also in UsefulBuf.h under a different name. They are copied + * here to avoid a dependency on UsefulBuf.h. There is no object code + * size impact because these always optimze down to a simple assignment. */ -static inline uint32_t CopyFloatToUint32(float f) +static inline uint32_t +CopyFloatToUint32(float f) { - uint32_t u32; - memcpy(&u32, &f, sizeof(uint32_t)); - return u32; + uint32_t u32; + memcpy(&u32, &f, sizeof(uint32_t)); + return u32; } -static inline uint64_t CopyDoubleToUint64(double d) +static inline uint64_t +CopyDoubleToUint64(double d) { - uint64_t u64; - memcpy(&u64, &d, sizeof(uint64_t)); - return u64; + uint64_t u64; + memcpy(&u64, &d, sizeof(uint64_t)); + return u64; } -static inline double CopyUint64ToDouble(uint64_t u64) +static inline double +CopyUint64ToDouble(uint64_t u64) { - double d; - memcpy(&d, &u64, sizeof(uint64_t)); - return d; + double d; + memcpy(&d, &u64, sizeof(uint64_t)); + return d; } - -// Public function; see ieee754.h -uint16_t IEEE754_FloatToHalf(float f) +static inline float +CopyUint32ToSingle(uint32_t u32) { - // Pull the three parts out of the single-precision float - const uint32_t uSingle = CopyFloatToUint32(f); - const int32_t nSingleUnbiasedExponent = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - - - // Now convert the three parts to half-precision. - - // All works is done on uint32_t with conversion to uint16_t at - // the end. This avoids integer promotions that static analyzers - // complain about and reduces code size. - uint32_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; - - if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { - // +/- Infinity and NaNs -- single biased exponent is 0xff - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - if(!uSingleSignificand) { - // Infinity - uHalfSignificand = 0; - } else { - // Copy the LSBs of the NaN payload that will fit from the - // single to the half - uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); - if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) { - // It's a qNaN; copy the qNaN bit - uHalfSignificand |= HALF_QUIET_NAN_BIT; - } else { - // It's an sNaN; make sure the significand is not zero - // so it stays a NaN This is needed because not all - // significand bits are copied from single - if(!uHalfSignificand) { - // Set the LSB. This is what wikipedia shows for - // sNAN. - uHalfSignificand |= 0x01; - } - } - } - } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { - // 0 or a subnormal number -- singled biased exponent is 0 - uHalfBiasedExponent = 0; - uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision - } else if(nSingleUnbiasedExponent > HALF_EXPONENT_MAX) { - // Exponent is too large to express in half-precision; round - // up to infinity - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - } else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) { - // Exponent is too small to express in half-precision normal; - // make it a half-precision subnormal - uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - // Could convert some of these values to a half-precision - // subnormal, but the layer above this will never use it. See - // layer above. There is code to do this in github history - // for this file, but it was removed because it was never - // invoked. - } else { - // The normal case, exponent is in range for half-precision - uHalfBiasedExponent = (uint32_t)(nSingleUnbiasedExponent + HALF_EXPONENT_BIAS); - uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uHalfSign = uSingleSign; - - // Put the 3 values in the right place for a half precision - const uint32_t uHalfPrecision = uHalfSignificand | - (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); - // Cast is safe because all the masks and shifts above work to - // make a half precision value which is only 16 bits. - return (uint16_t)uHalfPrecision; + float f; + memcpy(&f, &u32, sizeof(uint32_t)); + return f; } -// Public function; see ieee754.h -uint16_t IEEE754_DoubleToHalf(double d) + + +/** + * @brief Assemble sign, significand and exponent into single precision float. + * + * @param[in] uDoubleSign 0 if positive, 1 if negative + * @pararm[in] uDoubleSignificand Bits of the significand + * @param[in] nDoubleUnBiasedExponent Exponent + * + * This returns the bits for a single-precision float, a binary64 + * as specified in IEEE754. + */ +static double +IEEE754_AssembleDouble(uint64_t uDoubleSign, + uint64_t uDoubleSignificand, + int64_t nDoubleUnBiasedExponent) { - // Pull the three parts out of the double-precision float - const uint64_t uDouble = CopyDoubleToUint64(d); - const int64_t nDoubleUnbiasedExponent = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - // Now convert the three parts to half-precision. - - // All works is done on uint64_t with conversion to uint16_t at - // the end. This avoids integer promotions that static analyzers - // complain about. Other options are for these to be unsigned int - // or fast_int16_t. Code size doesn't vary much between all these - // options for 64-bit LLVM, 64-bit GCC and 32-bit Armv7 LLVM. - uint64_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; - - if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - // +/- Infinity and NaNs -- single biased exponent is 0xff - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - if(!uDoubleSignificand) { - // Infinity - uHalfSignificand = 0; - } else { - // Copy the LSBs of the NaN payload that will fit from the - // double to the half - uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); - if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) { - // It's a qNaN; copy the qNaN bit - uHalfSignificand |= HALF_QUIET_NAN_BIT; - } else { - // It's an sNaN; make sure the significand is not zero - // so it stays a NaN This is needed because not all - // significand bits are copied from single - if(!uHalfSignificand) { - // Set the LSB. This is what wikipedia shows for - // sNAN. - uHalfSignificand |= 0x01; - } - } - } - } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { - // 0 or a subnormal number -- double biased exponent is 0 - uHalfBiasedExponent = 0; - uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision; TODO, is this really true? - } else if(nDoubleUnbiasedExponent > HALF_EXPONENT_MAX) { - // Exponent is too large to express in half-precision; round - // up to infinity; TODO, is this really true? - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - } else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) { - // Exponent is too small to express in half-precision; round - // down to zero - uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - // Could convert some of these values to a half-precision - // subnormal, but the layer above this will never use it. See - // layer above. There is code to do this in github history - // for this file, but it was removed because it was never - // invoked. - } else { - // The normal case, exponent is in range for half-precision - uHalfBiasedExponent = (uint32_t)(nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS); - uHalfSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uHalfSign = uDoubleSign; + uint64_t uDoubleBiasedExponent; + uDoubleBiasedExponent = (uint64_t)(nDoubleUnBiasedExponent + DOUBLE_EXPONENT_BIAS); - // Put the 3 values in the right place for a half precision - const uint64_t uHalfPrecision = uHalfSignificand | - (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); - // Cast is safe because all the masks and shifts above work to - // make a half precision value which is only 16 bits. - return (uint16_t)uHalfPrecision; + return CopyUint64ToDouble(uDoubleSignificand | + (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | + (uDoubleSign << DOUBLE_SIGN_SHIFT)); } -/* - EEE754_HalfToFloat() was created but is not needed. It can be retrieved from - github history if needed. - */ +double +IEEE754_HalfToDouble(uint16_t uHalfPrecision) +{ + uint64_t uDoubleSignificand; + int64_t nDoubleUnBiasedExponent; + double dResult; + + /* Pull out the three parts of the half-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. + */ + const uint64_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; + const uint64_t uHalfBiasedExponent = (uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT; + const int64_t nHalfUnBiasedExponent = (int64_t)uHalfBiasedExponent - HALF_EXPONENT_BIAS; + const uint64_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; + + if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { + /* 0 or subnormal */ + if(uHalfSignificand) { + /* --- SUBNORMAL --- */ + /* A half-precision subnormal can always be converted to a + * normal double-precision float because the ranges line up. + * The exponent of a subnormal starts out at the min exponent + * for a normal. As the sub normal significand bits are + * shifted, left to normalize, the exponent is + * decremented. Shifting continues until fully normalized. + */ + nDoubleUnBiasedExponent = HALF_EXPONENT_MIN; + uDoubleSignificand = uHalfSignificand; + do { + uDoubleSignificand <<= 1; + nDoubleUnBiasedExponent--; + } while ((uDoubleSignificand & (1ULL << HALF_NUM_SIGNIFICAND_BITS)) == 0); + /* A normal has an implied 1 in the most significant + * position that a subnormal doesn't. */ + uDoubleSignificand -= 1ULL << HALF_NUM_SIGNIFICAND_BITS; + /* Must shift into place for a double significand */ + uDoubleSignificand <<= DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; + + dResult = IEEE754_AssembleDouble(uHalfSign, + uDoubleSignificand, + nDoubleUnBiasedExponent); + } else { + /* --- ZERO --- */ + dResult = IEEE754_AssembleDouble(uHalfSign, + 0, + DOUBLE_EXPONENT_ZERO); + } + } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { + /* NaN or Inifinity */ + if(uHalfSignificand) { + /* --- NaN --- */ + /* Half-precision payloads always fit into double precision + * payloads. They are shifted left the same as a normal + * number significand. + */ + uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + dResult = IEEE754_AssembleDouble(uHalfSign, + uDoubleSignificand, + DOUBLE_EXPONENT_INF_OR_NAN); + } else { + /* --- INFINITY --- */ + dResult = IEEE754_AssembleDouble(uHalfSign, + 0, + DOUBLE_EXPONENT_INF_OR_NAN); + } + } else { + /* --- NORMAL NUMBER --- */ + uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + dResult = IEEE754_AssembleDouble(uHalfSign, + uDoubleSignificand, + nHalfUnBiasedExponent); + } + + return dResult; +} -// Public function; see ieee754.h -double IEEE754_HalfToDouble(uint16_t uHalfPrecision) +/** + * @brief Assemble sign, significand and exponent into single precision float. + * + * @param[in] uHalfSign 0 if positive, 1 if negative + * @pararm[in] uHalfSignificand Bits of the significand + * @param[in] nHalfUnBiasedExponent Exponent + * + * This returns the bits for a single-precision float, a binary32 as + * specified in IEEE754. It is returned as a uint64_t rather than a + * uint32_t or a float for convenience of usage. + */ +static uint32_t +IEEE754_AssembleHalf(uint32_t uHalfSign, + uint32_t uHalfSignificand, + int32_t nHalfUnBiasedExponent) { - // Pull out the three parts of the half-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. - const uint64_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; - const int64_t nHalfUnBiasedExponent = (int64_t)((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS; - const uint64_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; - - - // Make the three parts of hte single-precision number - uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent; - if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { - // 0 or subnormal - uDoubleBiasedExponent = DOUBLE_EXPONENT_ZERO + DOUBLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // Subnormal case - uDoubleBiasedExponent = -HALF_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS +1; - // A half-precision subnormal can always be converted to a - // normal double-precision float because the ranges line - // up - uDoubleSignificand = uHalfSignificand; - // Shift bits from right of the decimal to left, reducing - // the exponent by 1 each time - do { - uDoubleSignificand <<= 1; - uDoubleBiasedExponent--; - } while ((uDoubleSignificand & 0x400) == 0); - uDoubleSignificand &= HALF_SIGNIFICAND_MASK; - uDoubleSignificand <<= (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } else { - // Just zero - uDoubleSignificand = 0; - } - } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { - // NaN or Inifinity - uDoubleBiasedExponent = DOUBLE_EXPONENT_INF_OR_NAN + DOUBLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // NaN - // First preserve the NaN payload from half to single - uDoubleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT; - if(uHalfSignificand & HALF_QUIET_NAN_BIT) { - // Next, set qNaN if needed since half qNaN bit is not - // copied above - uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT; - } - } else { - // Infinity - uDoubleSignificand = 0; - } - } else { - // Normal number - uDoubleBiasedExponent = (uint64_t)(nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS); - uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uDoubleSign = uHalfSign; + uint32_t uHalfUnbiasedExponent; + uHalfUnbiasedExponent = (uint32_t)(nHalfUnBiasedExponent + HALF_EXPONENT_BIAS); - // Shift the 3 parts into place as a double-precision - const uint64_t uDouble = uDoubleSignificand | - (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | - (uDoubleSign << DOUBLE_SIGN_SHIFT); - return CopyUint64ToDouble(uDouble); + return uHalfSignificand | + (uHalfUnbiasedExponent << HALF_EXPONENT_SHIFT) | + (uHalfSign << HALF_SIGN_SHIFT); } +/* Public function; see ieee754.h */ +IEEE754_union +IEEE754_SingleToHalf(float f) +{ + IEEE754_union result; + uint32_t uDroppedBits; + int32_t nExponentDifference; + int32_t nShiftAmount; + uint32_t uHalfSignificand; + + /* Pull the three parts out of the double-precision float Most work + * is done with uint32_t which helps avoid integer promotions and + * static analyzer complaints. + */ + const uint32_t uSingle = CopyFloatToUint32(f); + const uint32_t uSingleBiasedExponent = (uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT; + const int32_t nSingleUnbiasedExponent = (int32_t)uSingleBiasedExponent - SINGLE_EXPONENT_BIAS; + const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; + const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; + + if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { + if(uSingleSignificand == 0) { + /* --- IS ZERO --- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + 0, + HALF_EXPONENT_ZERO); + } else { + /* --- IS SINGLE SUBNORMAL --- */ + /* The largest single subnormal is slightly less than the + * largest single normal which is 2^-149 or + * 2.2040517676619426e-38. The smallest half subnormal is + * 2^-14 or 5.9604644775390625E-8. There is no overlap so + * single subnormals can't be converted to halfs of any sort. + */ + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { + if(uSingleSignificand == 0) { + /* ---- IS INFINITY ---- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, 0, HALF_EXPONENT_INF_OR_NAN); + } else { + /* The NaN can only be converted if no payload bits are lost + * per RFC 8949 section 4.1 that defines Preferred + * Serializaton. Note that Deterministically Encode CBOR in + * section 4.2 allows for some variation of this rule, but at + * the moment this implementation is of Preferred + * Serialization, not CDE. As of December 2023, we are also + * expecting an update to CDE. This code may need to be + * updated for CDE. + */ + uDroppedBits = uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS); + if(uDroppedBits == 0) { + /* --- IS CONVERTABLE NAN --- */ + uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + uHalfSignificand, + HALF_EXPONENT_INF_OR_NAN); + + } else { + /* --- IS UNCONVERTABLE NAN --- */ + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + } + } else { + /* ---- REGULAR NUMBER ---- */ + /* A regular single can be converted to a regular half if the + * single's exponent is in the smaller range of a half and if no + * precision is lost in the significand. + */ + if(nSingleUnbiasedExponent >= HALF_EXPONENT_MIN && + nSingleUnbiasedExponent <= HALF_EXPONENT_MAX && + (uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS)) == 0) { + uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + + /* --- CONVERT TO HALF NORMAL --- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + uHalfSignificand, + nSingleUnbiasedExponent); + } else { + /* Unable to convert to a half normal. See if it can be + * converted to a half subnormal. To do that, the exponent + * must be in range and no precision can be lost in the + * signficand. + * + * This is more complicated because the number is not + * normalized. The signficand must be shifted proprotionally + * to the exponent and 1 must be added in. See + * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding + * + * Exponents -14 to -24 map to a shift of 0 to 10 of the + * significand. The largest value of a half subnormal has an + * exponent of -14. Subnormals are not normalized like + * normals meaning they lose precision as the numbers get + * smaller. Normals don't lose precision because the exponent + * allows all the bits of the significand to be significant. + */ + /* The exponent of the largest possible half-precision + * subnormal is HALF_EXPONENT_MIN (-14). Exponents larger + * than this are normal and handled above. We're going to + * shift the significand right by at least this amount. + */ + nExponentDifference = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN); + + /* In addition to the shift based on the exponent's value, + * the single significand has to be shifted right to fit into + * a half-precision significand */ + nShiftAmount = nExponentDifference + (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + + /* Must add 1 in to the possible significand because there is + * an implied 1 for normal values and not for subnormal + * values. See equations here: + * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding + */ + uHalfSignificand = (uSingleSignificand + (1 << SINGLE_NUM_SIGNIFICAND_BITS)) >> nShiftAmount; + + /* If only zero bits get shifted out, this can be converted + * to subnormal */ + if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN && + nSingleUnbiasedExponent >= HALF_EXPONENT_MIN - HALF_NUM_SIGNIFICAND_BITS && + uHalfSignificand << nShiftAmount == uSingleSignificand + (1 << SINGLE_NUM_SIGNIFICAND_BITS)) { + /* --- CONVERTABLE TO HALF SUBNORMAL --- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + uHalfSignificand, + HALF_EXPONENT_ZERO); + } else { + /* --- DO NOT CONVERT --- */ + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + } + } + + return result; +} -/* - IEEE754_FloatToDouble(uint32_t uFloat) was created but is not needed. It can be retrieved from -github history if needed. -*/ +/** + * @brief Assemble sign, significand and exponent into single precision float. + * + * @param[in] uSingleSign 0 if positive, 1 if negative + * @pararm[in] uSingleSignificand Bits of the significand + * @param[in] nSingleUnBiasedExponent Exponent + * + * This returns the bits for a single-precision float, a binary32 as + * specified in IEEE754. It is returned as a uint64_t rather than a + * uint32_t or a float for convenience of usage. + */ +static uint64_t +IEEE754_AssembleSingle(uint64_t uSingleSign, + uint64_t uSingleSignificand, + int64_t nSingleUnBiasedExponent) +{ + uint64_t uSingleBiasedExponent; + uSingleBiasedExponent = (uint64_t)(nSingleUnBiasedExponent + SINGLE_EXPONENT_BIAS); + + return uSingleSignificand | + (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) | + (uSingleSign << SINGLE_SIGN_SHIFT); +} -// Public function; see ieee754.h -IEEE754_union IEEE754_FloatToSmallest(float f) + +/** + * @brief Convert a double-precision float to single-precision. + * + * @param[in] d The value to convert. + * + * @returns Either unconverted value or value converted to single-precision. + * + * This always succeeds. If the value cannot be converted without the + * loss of precision, it is not converted. + * + * This handles all subnormals and NaN payloads. + */ +static IEEE754_union +IEEE754_DoubleToSingle(double d) { - IEEE754_union result; - - // Pull the neeed two parts out of the single-precision float - const uint32_t uSingle = CopyFloatToUint32(f); - const int32_t nSingleExponent = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - - // Bit mask that is the significand bits that would be lost when - // converting from single-precision to half-precision - const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; - - // Optimizer will re organize so there is only one call to - // IEEE754_FloatToHalf() in the final code. - if(uSingle == 0) { - // Value is 0.0000, not a a subnormal - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else if(nSingleExponent == SINGLE_EXPONENT_INF_OR_NAN) { - // NaN, +/- infinity - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else if((nSingleExponent >= HALF_EXPONENT_MIN) && nSingleExponent <= HALF_EXPONENT_MAX && (!(uSingleSignificand & uDroppedSingleBits))) { - // Normal number in exponent range and precision won't be lost - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); + IEEE754_union Result; + int64_t nExponentDifference; + int64_t nShiftAmount; + uint64_t uSingleSignificand; + uint64_t uDroppedBits; + + + /* Pull the three parts out of the double-precision float. Most + * work is done with uint64_t which helps avoid integer promotions + * and static analyzer complaints. + */ + const uint64_t uDouble = CopyDoubleToUint64(d); + const uint64_t uDoubleBiasedExponent = (uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT; + const int64_t nDoubleUnbiasedExponent = (int64_t)uDoubleBiasedExponent - DOUBLE_EXPONENT_BIAS; + const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; + const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; + + + if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { + if(uDoubleSignificand == 0) { + /* --- IS ZERO --- */ + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + 0, + SINGLE_EXPONENT_ZERO); + } else { + /* --- IS DOUBLE SUBNORMAL --- */ + /* The largest double subnormal is slightly less than the + * largest double normal which is 2^-1022 or + * 2.2250738585072014e-308. The smallest single subnormal + * is 2^-149 or 1.401298464324817e-45. There is no + * overlap so double subnormals can't be converted to + * singles of any sort. + */ + Result.uSize = IEEE754_UNION_IS_DOUBLE; + Result.uValue = uDouble; + } + } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { + if(uDoubleSignificand == 0) { + /* ---- IS INFINITY ---- */ + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + 0, + SINGLE_EXPONENT_INF_OR_NAN); + } else { + /* The NaN can only be converted if no payload bits are + * lost per RFC 8949 section 4.1 that defines Preferred + * Serializaton. Note that Deterministically Encode CBOR + * in section 4.2 allows for some variation of this rule, + * but at the moment this implementation is of Preferred + * Serialization, not CDE. As of December 2023, we are + * also expecting an update to CDE. This code may need to + * be updated for CDE. + */ + uDroppedBits = uDoubleSignificand & (DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS); + if(uDroppedBits == 0) { + /* --- IS CONVERTABLE NAN --- */ + uSingleSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + uSingleSignificand, + SINGLE_EXPONENT_INF_OR_NAN); + } else { + /* --- IS UNCONVERTABLE NAN --- */ + Result.uSize = IEEE754_UNION_IS_DOUBLE; + Result.uValue = uDouble; + } + } } else { - // Subnormal, exponent out of range, or precision will be lost - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = uSingle; + /* ---- REGULAR NUMBER ---- */ + /* A regular double can be converted to a regular single if + * the double's exponent is in the smaller range of a single + * and if no precision is lost in the significand. + */ + uDroppedBits = uDoubleSignificand & (DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS); + if(nDoubleUnbiasedExponent >= SINGLE_EXPONENT_MIN && + nDoubleUnbiasedExponent <= SINGLE_EXPONENT_MAX && + uDroppedBits == 0) { + /* --- IS CONVERTABLE TO SINGLE --- */ + uSingleSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + uSingleSignificand, + nDoubleUnbiasedExponent); + } else { + /* Unable to convert to a single normal. See if it can be + * converted to a single subnormal. To do that, the + * exponent must be in range and no precision can be lost + * in the signficand. + * + * This is more complicated because the number is not + * normalized. The signficand must be shifted + * proprotionally to the exponent and 1 must be added + * in. See + * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding + */ + nExponentDifference = -(nDoubleUnbiasedExponent - SINGLE_EXPONENT_MIN); + nShiftAmount = nExponentDifference + (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); + uSingleSignificand = (uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS)) >> nShiftAmount; + + if(nDoubleUnbiasedExponent < SINGLE_EXPONENT_MIN && + nDoubleUnbiasedExponent >= SINGLE_EXPONENT_MIN - SINGLE_NUM_SIGNIFICAND_BITS && + uSingleSignificand << nShiftAmount == uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS)) { + /* --- IS CONVERTABLE TO SINGLE SUBNORMAL --- */ + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + uSingleSignificand, + SINGLE_EXPONENT_ZERO); + } else { + /* --- CAN NOT BE CONVERTED --- */ + Result.uSize = IEEE754_UNION_IS_DOUBLE; + Result.uValue = uDouble; + } + } } - return result; + return Result; } -// Public function; see ieee754.h -IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision) + +/* Public function; see ieee754.h */ +IEEE754_union +IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision) { - IEEE754_union result; - - // Pull the needed two parts out of the double-precision float - const uint64_t uDouble = CopyDoubleToUint64(d); - const int64_t nDoubleExponent = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - // Masks to check whether dropped significand bits are zero or not - const uint64_t uDroppedHalfBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; - const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS; - - // This will not convert to half-precion or single-precision - // subnormals. Values that could be converted will be output as - // the double they are or occasionally to a normal single. This - // could be implemented, but it is more code and would rarely be - // used and rarely reduce the output size. - - // The various cases - if(d == 0.0) { // Take care of positive and negative zero - // Value is 0.0000, not a a subnormal - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if(nDoubleExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - // NaN, +/- infinity - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedHalfBits))) { - // Can convert to half without precision loss - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if((nDoubleExponent >= SINGLE_EXPONENT_MIN) && nDoubleExponent <= SINGLE_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedSingleBits))) { - // Can convert to single without precision loss - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = CopyFloatToUint32((float)d); - } else { - // Can't convert without precision loss - result.uSize = IEEE754_UNION_IS_DOUBLE; - result.uValue = uDouble; - } + IEEE754_union result; - return result; + result = IEEE754_DoubleToSingle(d); + + if(result.uSize == IEEE754_UNION_IS_SINGLE && bAllowHalfPrecision) { + /* Cast to uint32_t is OK, because value was just successfully + * converted to single. */ + float uSingle = CopyUint32ToSingle((uint32_t)result.uValue); + result = IEEE754_SingleToHalf(uSingle); + } + + return result; } -#else -int x; +#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ + +int ieee754_dummy_place_holder; #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ diff --git a/3rdparty/exported/QCBOR/src/ieee754.h b/3rdparty/exported/QCBOR/src/ieee754.h index d37532a092c6..3013dc6fd547 100644 --- a/3rdparty/exported/QCBOR/src/ieee754.h +++ b/3rdparty/exported/QCBOR/src/ieee754.h @@ -1,14 +1,14 @@ -/*============================================================================== - ieee754.c -- floating-point conversion between half, double & single-precision - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 7/23/18 - =============================================================================*/ +/* ========================================================================== + * ieee754.h -- Conversion between half, double & single-precision floats + * + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 7/23/18 + * ========================================================================== */ #ifndef QCBOR_DISABLE_PREFERRED_FLOAT @@ -18,130 +18,109 @@ #include - -/* - General comments - - This is a complete in that it handles all conversion cases including - +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN and NaN - payloads. - - This conforms to IEEE 754-2008, but note that this doesn't specify - conversions, just the encodings. - - NaN payloads are preserved with alignment on the LSB. The qNaN bit is - handled differently and explicity copied. It is always the MSB of the - significand. The NaN payload MSBs (except the qNaN bit) are truncated - when going from double or single to half. - - TODO: what does the C cast do with NaN payloads from - double to single? It probably depends entirely on the - CPU. - - */ - -/* - Most simply just explicilty encode the type you want, single or - double. This works easily everywhere since standard C supports both - these types and so does qcbor. This encoder also supports half - precision and there's a few ways to use it to encode floating-point - numbers in less space. - - Without losing precision, you can encode a single or double such that - the special values of 0, NaN and Infinity encode as half-precision. - This CBOR decodoer and most others should handle this properly. - - If you don't mind losing precision, then you can use half-precision. - One way to do this is to set up your environment to use - ___fp_16. Some compilers and CPUs support it even though it is not - standard C. What is nice about this is that your program will use - less memory and floating-point operations like multiplying, adding - and such will be faster. - - Another way to make use of half-precision is to represent the values - in your program as single or double, but encode them in CBOR as - half-precision. This cuts the size of the encoded messages by 2 or 4, - but doesn't reduce memory needs or speed because you are still using - single or double in your code. - - */ - - - -/* - Convert single-precision float to half-precision float. Precision - and NaN payload bits will be lost. Too-large values will round up to - infinity and too small to zero. +/** @file ieee754.h + * + * This implements floating-point conversion between half, single and + * double precision floating-point numbers, in particular convesion to + * smaller representation (e.g., double to single) that does not lose + * precision for CBOR preferred serialization. + * + * This implementation works entirely with shifts and masks and does + * not require any floating-point HW or library. + * + * This conforms to IEEE 754-2008, but note that it doesn't specify + * conversions, just the encodings. + * + * This is complete, supporting +/- infinity, +/- zero, subnormals and + * NaN payloads. NaN payloads are converted to smaller by dropping the + * right most bits if they are zero and shifting to the right. If the + * rightmost bits are not zero the conversion is not performed. When + * converting from smaller to larger, the payload is shifted left and + * zero-padded. This is what is specified by CBOR preferred + * serialization and what modern HW conversion instructions do. CBOR + * CDE handling for NaN is not clearly specified, but upcoming + * documents may clarify this. + * + * There is no special handling of silent and quiet NaNs. It probably + * isn't necessary to transmit these special NaNs as there purpose is + * more for propgating errors up through some calculation. In many + * cases the handlng of the NaN payload will work for silent and quiet + * NaNs. + * + * A previous version of this was usable as a general library for + * conversion. This version is reduced to what is needed for CBOR. */ -uint16_t IEEE754_FloatToHalf(float f); -/* - Convert double-precision float to half-precision float. Precision - and NaN payload bits will be lost. Too-large values will round up to - infinity and too small to zero. +/** + * @brief Convert half-precision float to double-precision float. + * + * @param[in] uHalfPrecision Half-prevision number to convert. + * + * @returns double-presion value. + * + * This is a lossless conversion because every half-precision value + * can be represented as a double. There is no error condition. + * + * There is no half-precision type in C, so it is represented here as + * a @c uint16_t. The bits of @c uHalfPrecision are as described for + * half-precision by IEEE 754. */ -uint16_t IEEE754_DoubleToHalf(double d); +double +IEEE754_HalfToDouble(uint16_t uHalfPrecision); -/* - Convert half-precision float to double-precision float. - This is a loss-less conversion. +/** Holds a floating-point value that could be half, single or + * double-precision. The value is in a @c uint64_t that may be copied + * to a float or double. Simply casting uValue will usually work but + * may generate compiler or static analyzer warnings. Using + * UsefulBufUtil_CopyUint64ToDouble() or + * UsefulBufUtil_CopyUint32ToFloat() will not (and will not generate + * any extra code). */ -double IEEE754_HalfToDouble(uint16_t uHalfPrecision); - - -// Both tags the value and gives the size -#define IEEE754_UNION_IS_HALF 2 -#define IEEE754_UNION_IS_SINGLE 4 -#define IEEE754_UNION_IS_DOUBLE 8 - typedef struct { - uint8_t uSize; // One of IEEE754_IS_xxxx - uint64_t uValue; + enum {IEEE754_UNION_IS_HALF = 2, + IEEE754_UNION_IS_SINGLE = 4, + IEEE754_UNION_IS_DOUBLE = 8, + } uSize; /* Size of uValue */ + uint64_t uValue; } IEEE754_union; -/* - Converts double-precision to single-precision or half-precision if - possible without loss of precisions. If not, leaves it as a - double. Only converts to single-precision unless bAllowHalfPrecision - is set. - */ -IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision); - -/* - Converts double-precision to single-precision if possible without - loss of precision. If not, leaves it as a double. - */ -static inline IEEE754_union IEEE754_DoubleToSmall(double d) -{ - return IEEE754_DoubleToSmallestInternal(d, 0); -} - - -/* - Converts double-precision to single-precision or half-precision if - possible without loss of precisions. If not, leaves it as a double. +/** + * @brief Convert a double to either single or half-precision. + * + * @param[in] d The value to convert. + * @param[in] bAllowHalfPrecision If true, convert to either half or + * single precision. + * + * @returns Unconverted value, or value converted to single or half-precision. + * + * This always succeeds. If the value cannot be converted without the + * loss of precision, it is not converted. + * + * This handles all subnormals and NaN payloads. */ -static inline IEEE754_union IEEE754_DoubleToSmallest(double d) -{ - return IEEE754_DoubleToSmallestInternal(d, 1); -} - - -/* - Converts single-precision to half-precision if possible without loss - of precision. If not leaves as single-precision. +IEEE754_union +IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision); + + +/** + * @brief Convert a single-precision float to half-precision. + * + * @param[in] f The value to convert. + * + * @returns Either unconverted value or value converted to half-precision. + * + * This always succeeds. If the value cannot be converted without the + * loss of precision, it is not converted. + * + * This handles all subnormals and NaN payloads. */ -IEEE754_union IEEE754_FloatToSmallest(float f); +IEEE754_union +IEEE754_SingleToHalf(float f); #endif /* ieee754_h */ - #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ - - - - diff --git a/3rdparty/exported/QCBOR/src/qcbor_decode.c b/3rdparty/exported/QCBOR/src/qcbor_decode.c index 8a547eef0a66..0f4d5c026716 100644 --- a/3rdparty/exported/QCBOR/src/qcbor_decode.c +++ b/3rdparty/exported/QCBOR/src/qcbor_decode.c @@ -1,6 +1,6 @@ /*============================================================================== Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. + Copyright (c) 2018-2024, Laurence Lundblade. Copyright (c) 2021, Arm Limited. All rights reserved. @@ -46,52 +46,150 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ +#if (defined(__GNUC__) && !defined(__clang__)) +/* + * This is how the -Wmaybe-uninitialized compiler warning is + * handled. It can’t be ignored because some version of gcc enable it + * with -Wall which is a common and useful gcc warning option. It also + * can’t be ignored because it is the goal of QCBOR to compile clean + * out of the box in all environments. + * + * The big problem with -Wmaybe-uninitialized is that it generates + * false positives. It complains things are uninitialized when they + * are not. This is because it is not a thorough static analyzer. This + * is why “maybe” is in its name. The problem is it is just not + * thorough enough to understand all the code (and someone saw fit to + * put it in gcc and worse to enable it with -Wall). + * + * One solution would be to change the code so -Wmaybe-uninitialized + * doesn’t get confused, for example adding an unnecessary extra + * initialization to zero. (If variables were truly uninitialized, the + * correct path is to understand the code thoroughly and set them to + * the correct value at the correct time; in essence this is already + * done; -Wmaybe-uninitialized just can’t tell). This path is not + * taken because it makes the code bigger and is kind of the tail + * wagging the dog. + * + * The solution here is to just use a pragma to disable it for the + * whole file. Disabling it for each line makes the code fairly ugly + * requiring #pragma to push, pop and ignore. Another reason is the + * warnings issues vary by version of gcc and which optimization + * optimizations are selected. Another reason is that compilers other + * than gcc don’t have -Wmaybe-uninitialized. + * + * One may ask how to be sure these warnings are false positives and + * not real issues. 1) The code has been read carefully to check. 2) + * Testing is pretty thorough. 3) This code has been run through + * thorough high-quality static analyzers. + * + * In particularly, most of the warnings are about + * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext() + * *always* sets this value and test case confirm + * this. -Wmaybe-uninitialized just can't tell. + * + * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable + */ +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + + + #define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type)) -static inline bool -QCBORItem_IsMapOrArray(const QCBORItem *pMe) +static bool +QCBORItem_IsMapOrArray(const QCBORItem Item) { - const uint8_t uDataType = pMe->uDataType; + const uint8_t uDataType = Item.uDataType; return uDataType == QCBOR_TYPE_MAP || - uDataType == QCBOR_TYPE_ARRAY || - uDataType == QCBOR_TYPE_MAP_AS_ARRAY; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + uDataType == QCBOR_TYPE_MAP_AS_ARRAY || +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + uDataType == QCBOR_TYPE_ARRAY; } -static inline bool -QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem *pMe) +static bool +QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item) { - if(!QCBORItem_IsMapOrArray(pMe)){ + if(!QCBORItem_IsMapOrArray(Item)){ return false; } - if(pMe->val.uCount != 0) { + if(Item.val.uCount != 0) { return false; } return true; } -static inline bool -QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem *pMe) +static bool +QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item) { #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(!QCBORItem_IsMapOrArray(pMe)){ + if(!QCBORItem_IsMapOrArray(Item)){ return false; } - if(pMe->val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { + if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { return false; } return true; #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - (void)pMe; + (void)Item; return false; #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ } +/* Return true if the labels in Item1 and Item2 are the same. + Works only for integer and string labels. Returns false + for any other type. */ +static bool +QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2) +{ + if(Item1.uLabelType == QCBOR_TYPE_INT64) { + if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) { + return true; + } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) { + if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { + return true; + } + } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) { + if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { + return true; + } + } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) { + if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) { + return true; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + } + + /* Other label types are never matched */ + return false; +} + + +/* + Returns true if Item1 and Item2 are the same type + or if either are of QCBOR_TYPE_ANY. + */ +static bool +QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2) +{ + if(Item1.uDataType == Item2.uDataType) { + return true; + } else if(Item1.uDataType == QCBOR_TYPE_ANY) { + return true; + } else if(Item2.uDataType == QCBOR_TYPE_ANY) { + return true; + } + return false; +} + /*=========================================================================== DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting @@ -103,7 +201,7 @@ QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem *pMe) */ -static inline uint8_t +static uint8_t DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting) { const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]); @@ -114,7 +212,7 @@ DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting) } -static inline uint8_t +static uint8_t DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting) { const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]); @@ -125,14 +223,14 @@ DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting) } -static inline uint32_t +static uint32_t DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting) { return pNesting->pCurrentBounded->u.ma.uStartOffset; } -static inline bool +static bool DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) { @@ -143,7 +241,7 @@ DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent == &(pNesting->pLevels[0])) { @@ -154,7 +252,7 @@ DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { @@ -174,7 +272,7 @@ DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) return true; } -static inline bool +static bool DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { @@ -185,7 +283,8 @@ DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting) } -static inline bool DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting) +static bool +DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { return true; @@ -197,7 +296,8 @@ static inline bool DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNes } -static inline void DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart) +static void +DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart) { /* Should be only called on maps and arrays */ /* @@ -213,13 +313,14 @@ static inline void DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pN } -static inline void DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting) +static void +DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting) { pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET; } -static inline bool +static bool DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrentBounded == NULL) { @@ -245,7 +346,7 @@ DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting) { /* Must only be called on map / array */ @@ -257,7 +358,7 @@ DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting } -static inline bool +static bool DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) { @@ -268,14 +369,21 @@ DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) { if(pNesting->pCurrentBounded == NULL) { return false; } - if(pNesting->pCurrentBounded->uLevelType != uType) { + uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { return false; } @@ -283,7 +391,7 @@ DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) } -static inline void +static void DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting) { /* Only call on a definite-length array / map */ @@ -291,7 +399,7 @@ DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNestin } -static inline void +static void DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) { /* Only call on a definite-length array / map */ @@ -299,7 +407,7 @@ DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_Ascend(QCBORDecodeNesting *pNesting) { pNesting->pCurrent--; @@ -323,7 +431,7 @@ DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType) } -static inline QCBORError +static QCBORError DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uOffset) @@ -351,10 +459,10 @@ DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting, } -static inline QCBORError +static QCBORError DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, - uint8_t uQCBORType, - uint64_t uCount) + const uint8_t uQCBORType, + const uint16_t uCount) { QCBORError uError = QCBOR_SUCCESS; @@ -366,21 +474,16 @@ DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, /* Empty indefinite-length maps and arrays are handled elsewhere */ } - /* Error out if arrays is too long to handle */ - if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH && - uCount > QCBOR_MAX_ITEMS_IN_ARRAY) { - uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - goto Done; - } + /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length + * arrays and maps that are too long */ uError = DecodeNesting_Descend(pNesting, uQCBORType); if(uError != QCBOR_SUCCESS) { goto Done; } - /* Fill in the new map/array level. Check above makes casts OK. */ - pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount; - pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount; + pNesting->pCurrent->u.ma.uCountCursor = uCount; + pNesting->pCurrent->u.ma.uCountTotal = uCount; DecodeNesting_ClearBoundedMode(pNesting); @@ -389,14 +492,14 @@ DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, } -static inline void +static void DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting) { pNesting->pCurrent = pNesting->pCurrentBounded - 1; } -static inline void +static void DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting) { while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) { @@ -408,14 +511,14 @@ DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting) { pNesting->pCurrent = pNesting->pCurrentBounded; } -static inline QCBORError +static QCBORError DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, uint32_t uEndOffset, uint32_t uStartOffset) @@ -439,14 +542,14 @@ DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, } -static inline void +static void DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting) { pNesting->pCurrent->u.ma.uCountCursor = 0; } -static inline void +static void DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) { @@ -455,7 +558,7 @@ DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_Init(QCBORDecodeNesting *pNesting) { /* Assumes that *pNesting has been zero'd before this call. */ @@ -464,7 +567,7 @@ DecodeNesting_Init(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave) { @@ -472,7 +575,7 @@ DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, } -static inline void +static void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, const QCBORDecodeNesting *pSave) { @@ -480,7 +583,7 @@ DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, } -static inline uint32_t +static uint32_t DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) { return pMe->pCurrentBounded->u.bs.uSavedEndOffset; @@ -498,7 +601,7 @@ DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) ===========================================================================*/ -static inline void +static void StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem) { /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings. @@ -510,7 +613,7 @@ StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem) // StringAllocator_Reallocate called with pMem NULL is // equal to StringAllocator_Allocate() -static inline UsefulBuf +static UsefulBuf StringAllocator_Reallocate(const QCBORInternalAllocator *pMe, const void *pMem, size_t uSize) @@ -519,13 +622,13 @@ StringAllocator_Reallocate(const QCBORInternalAllocator *pMe, return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize); } -static inline UsefulBuf +static UsefulBuf StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize) { return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize); } -static inline void +static void StringAllocator_Destruct(const QCBORInternalAllocator *pMe) { /* See comment in StringAllocator_Free() */ @@ -547,9 +650,10 @@ StringAllocator_Destruct(const QCBORInternalAllocator *pMe) /* * Public function, see header file */ -void QCBORDecode_Init(QCBORDecodeContext *pMe, - UsefulBufC EncodedCBOR, - QCBORDecodeMode nDecodeMode) +void +QCBORDecode_Init(QCBORDecodeContext *pMe, + UsefulBufC EncodedCBOR, + QCBORDecodeMode nDecodeMode) { memset(pMe, 0, sizeof(QCBORDecodeContext)); UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR); @@ -570,10 +674,11 @@ void QCBORDecode_Init(QCBORDecodeContext *pMe, /* * Public function, see header file */ -void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, - QCBORStringAllocate pfAllocateFunction, - void *pAllocateContext, - bool bAllStrings) +void +QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, + QCBORStringAllocate pfAllocateFunction, + void *pAllocateContext, + bool bAllStrings) { pMe->StringAllocator.pfAllocator = pfAllocateFunction; pMe->StringAllocator.pAllocateCxt = pAllocateContext; @@ -587,8 +692,9 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, /* * Deprecated public function, see header file */ -void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, - const QCBORTagListIn *pTagList) +void +QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, + const QCBORTagListIn *pTagList) { /* This does nothing now. It is retained for backwards compatibility */ (void)pMe; @@ -603,43 +709,44 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, * down. If a layer has no work to do for a particular item, it * returns quickly. * - * 1. QCBORDecode_GetNextTagContent - The top layer processes tagged - * data items, turning them into the local C representation. For the - * most simple it is just associating a QCBOR_TYPE with the data. For - * the complex ones that an aggregate of data items, there is some - * further decoding and some limited recursion. + * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes + * tagged data items, turning them into the local C representation. + * For the most simple it is just associating a QCBOR_TYPE with the + * data. For the complex ones that an aggregate of data items, there + * is some further decoding and some limited recursion. * - * 2. QCBORDecode_GetNextMapOrArray - This manages the beginnings and - * ends of maps and arrays. It tracks descending into and ascending - * out of maps/arrays. It processes breaks that terminate - * indefinite-length maps and arrays. + * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the + * beginnings and ends of maps and arrays. It tracks descending into + * and ascending out of maps/arrays. It processes breaks that + * terminate indefinite-length maps and arrays. * - * 3. QCBORDecode_GetNextMapEntry - This handles the combining of two - * items, the label and the data, that make up a map entry. It only - * does work on maps. It combines the label and data items into one - * labeled item. + * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining + * of two items, the label and the data, that make up a map entry. It + * only does work on maps. It combines the label and data items into + * one labeled item. * - * 4. QCBORDecode_GetNextTagNumber - This decodes type 6 tag + * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag * numbers. It turns the tag numbers into bit flags associated with * the data item. No actual decoding of the contents of the tag is * performed here. * - * 5. QCBORDecode_GetNextFullString - This assembles the sub-items - * that make up an indefinite-length string into one string item. It - * uses the string allocator to create contiguous space for the - * item. It processes all breaks that are part of indefinite-length - * strings. - * - * 6. DecodeAtomicDataItem - This decodes the atomic data items in - * CBOR. Each atomic data item has a "major type", an integer - * "argument" and optionally some content. For text and byte strings, - * the content is the bytes that make up the string. These are the - * smallest data items that are considered to be well-formed. The - * content may also be other data items in the case of aggregate + * 5. QCBORDecode_Private_GetNextFullString - This assembles the + * sub-items that make up an indefinite-length string into one string + * item. It uses the string allocator to create contiguous space for + * the item. It processes all breaks that are part of + * indefinite-length strings. + * + * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic + * data items in CBOR. Each atomic data item has a "major type", an + * integer "argument" and optionally some content. For text and byte + * strings, the content is the bytes that make up the string. These + * are the smallest data items that are considered to be well-formed. + * The content may also be other data items in the case of aggregate * types. They are not handled in this layer. * - * Roughly this takes 300 bytes of stack for vars. TODO: evaluate this - * more carefully and correctly. + * This uses about 350 bytes of stack. This number comes from + * instrumenting (printf address of stack variables) the code on x86 + * compiled for size optimization. */ @@ -665,8 +772,8 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, * @param[out] puArgument The decoded argument. * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte. * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features + * @retval QCBOR_ERR_HIT_END Unexpected end of input * * This decodes the CBOR "head" that every CBOR data item has. See * longer explaination of the head in documentation for @@ -680,11 +787,11 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, * avoids integer promotions, can reduce code size and makes static * analyzers happier. */ -static inline QCBORError -DecodeHead(UsefulInputBuf *pUInBuf, - int *pnMajorType, - uint64_t *puArgument, - int *pnAdditionalInfo) +static QCBORError +QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf, + int *pnMajorType, + uint64_t *puArgument, + int *pnAdditionalInfo) { QCBORError uReturn; @@ -739,11 +846,13 @@ DecodeHead(UsefulInputBuf *pUInBuf, /** * @brief Decode integer types, major types 0 and 1. * - * @param[in] nMajorType The CBOR major type (0 or 1). - * @param[in] uArgument The argument from the head. - * @param[out] pDecodedItem The filled in decoded item. + * @param[in] nMajorType The CBOR major type (0 or 1). + * @param[in] uArgument The argument from the head. + * @param[in] nAdditionalInfo So it can be error-checked. + * @param[out] pDecodedItem The filled in decoded item. * - * @retval QCBOR_ERR_INT_OVERFLOW + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered. + * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte. * * Must only be called when major type is 0 or 1. * @@ -756,11 +865,19 @@ DecodeHead(UsefulInputBuf *pUInBuf, * away from zero than positive. Stdint, as far as I can tell, uses * two's compliment to represent negative integers. */ -static inline QCBORError -DecodeInteger(int nMajorType, uint64_t uArgument, QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeInteger(const int nMajorType, + const uint64_t uArgument, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + uReturn = QCBOR_ERR_BAD_INT; + goto Done; + } + if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) { if (uArgument <= INT64_MAX) { pDecodedItem->val.int64 = (int64_t)uArgument; @@ -789,10 +906,226 @@ DecodeInteger(int nMajorType, uint64_t uArgument, QCBORItem *pDecodedItem) } } +Done: + return uReturn; +} + + +/** + * @brief Decode text and byte strings + * + * @param[in] pMe Decoder context. + * @param[in] bAllocate Whether to allocate and copy string. + * @param[in] nMajorType Whether it is a byte or text string. + * @param[in] uStrLen The length of the string. + * @param[in] nAdditionalInfo Whether it is an indefinite-length string. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_HIT_END Unexpected end of input. + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator + * + * This reads @c uStrlen bytes from the input and fills in @c + * pDecodedItem. If @c bAllocate is true, then memory for the string + * is allocated. + */ +static QCBORError +QCBOR_Private_DecodeString(QCBORDecodeContext *pMe, + const bool bAllocate, + const int nMajorType, + const uint64_t uStrLen, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) +{ + QCBORError uReturn = QCBOR_SUCCESS; + + /* ---- Figure out the major type ---- */ + #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING + #error QCBOR_TYPE_BYTE_STRING not lined up with major type + #endif + + #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING + #error QCBOR_TYPE_TEXT_STRING not lined up with major type + #endif + pDecodedItem->uDataType = (uint8_t)(nMajorType + 4); + + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + /* --- Just the head of an indefinite-length string --- */ + pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE}; + + } else { + /* --- A definite-length string --- */ + /* --- (which might be a chunk of an indefinte-length string) --- */ + + /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all + * CPUs. This check makes the casts to size_t below safe. + * + * The max is 4 bytes less than the largest sizeof() so this can be + * tested by putting a SIZE_MAX length in the CBOR test input (no + * one will care the limit on strings is 4 bytes shorter). + */ + if(uStrLen > SIZE_MAX-4) { + uReturn = QCBOR_ERR_STRING_TOO_LONG; + goto Done; + } + + const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen); + if(UsefulBuf_IsNULLC(Bytes)) { + /* Failed to get the bytes for this string item */ + uReturn = QCBOR_ERR_HIT_END; + goto Done; + } + + if(bAllocate) { +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + /* --- Put string in allocated memory --- */ + + /* Note that this is not where allocation to coalesce + * indefinite-length strings is done. This is for when the + * caller has requested all strings be allocated. Disabling + * indefinite length strings also disables this allocate-all + * option. + */ + + if(pMe->StringAllocator.pfAllocator == NULL) { + uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; + goto Done; + } + UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen); + if(UsefulBuf_IsNULL(NewMem)) { + uReturn = QCBOR_ERR_STRING_ALLOCATE; + goto Done; + } + pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); + pDecodedItem->uDataAlloc = 1; +#else + uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED; +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + } else { + /* --- Normal case with no string allocator --- */ + pDecodedItem->val.string = Bytes; + } + } + +Done: + return uReturn; +} + + +/** + * @brief Decode array or map. + * + * @param[in] uMode Decoder mode. + * @param[in] nMajorType Whether it is a byte or text string. + * @param[in] uItemCount The length of the string. + * @param[in] nAdditionalInfo Whether it is an indefinite-length. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map. + * + * Not much to do for arrays and maps. Just the type item count (but a + * little messy because of ifdefs for indefinite-lengths and + * map-as-array decoding). + * + * This also does the bulk of the work for @ref + * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle + * arbitrarily complex map labels. This ifdefs out with + * QCBOR_DISABLE_NON_INTEGER_LABELS. + */ +static QCBORError +QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode, + const int nMajorType, + uint64_t uItemCount, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) +{ + QCBORError uReturn; + + /* ------ Sort out the data type ------ */ + #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY + #error QCBOR_TYPE_ARRAY value not lined up with major type + #endif + + #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP + #error QCBOR_TYPE_MAP value not lined up with major type + #endif + pDecodedItem->uDataType = (uint8_t)nMajorType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) { + pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; + } +#else + (void)uMode; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + uReturn = QCBOR_SUCCESS; + + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + /* ------ Indefinite-length array/map ----- */ +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH; +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED; +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + } else { + /* ----- Definite-length array/map ----- */ + if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) { + uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; + + } else { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) { + /* ------ Map as array ------ */ + uItemCount *= 2; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + /* cast OK because of check above */ + pDecodedItem->val.uCount = (uint16_t)uItemCount; + } + } + return uReturn; } +/** + * @brief Decode a tag number. + * + * @param[in] uTagNumber The length of the string. + * @param[in] nAdditionalInfo So this can be error-checked. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE. + * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined. + * + * Not much to do for tags, but fill in pDecodedItem and check for + * error in nAdditionalInfo. + */ +static QCBORError +QCBOR_Private_DecodeTag(const uint64_t uTagNumber, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) +{ +#ifndef QCBOR_DISABLE_TAGS + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + return QCBOR_ERR_BAD_INT; + } else { + pDecodedItem->val.uTagV = uTagNumber; + pDecodedItem->uDataType = QCBOR_TYPE_TAG; + return QCBOR_SUCCESS; + } +#else /* QCBOR_DISABLE_TAGS */ + (void)nAdditionalInfo; + (void)uTagNumber; + (void)pDecodedItem; + return QCBOR_ERR_TAGS_DISABLED; +#endif /* QCBOR_DISABLE_TAGS */ +} + + /* Make sure #define value line up as DecodeSimple counts on this. */ #if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE #error QCBOR_TYPE_FALSE macro value wrong @@ -830,13 +1163,17 @@ DecodeInteger(int nMajorType, uint64_t uArgument, QCBORItem *pDecodedItem) * @param[in] uArgument The argument from the head. * @param[out] pDecodedItem The filled in decoded item. * - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float + * decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple + * type in input. */ - -static inline QCBORError -DecodeType7(int nAdditionalInfo, uint64_t uArgument, QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeType7(const int nAdditionalInfo, + const uint64_t uArgument, + QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; @@ -937,236 +1274,90 @@ DecodeType7(int nAdditionalInfo, uint64_t uArgument, QCBORItem *pDecodedItem) } -/** - * @brief Decode text and byte strings - * - * @param[in] pAllocator The string allocator or NULL. - * @param[in] uStrLen The length of the string. - * @param[in] pUInBuf The surce from which to read the string's bytes. - * @param[out] pDecodedItem The filled in decoded item. - * - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * - * The reads @c uStrlen bytes from @c pUInBuf and fills in @c - * pDecodedItem. If @c pAllocator is not NULL then memory for the - * string is allocated. - */ -static inline QCBORError -DecodeBytes(const QCBORInternalAllocator *pAllocator, - uint64_t uStrLen, - UsefulInputBuf *pUInBuf, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - - /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all - * CPUs. This check makes the casts to size_t below safe. - * - * The max is 4 bytes less than the largest sizeof() so this can be - * tested by putting a SIZE_MAX length in the CBOR test input (no - * one will care the limit on strings is 4 bytes shorter). - */ - if(uStrLen > SIZE_MAX-4) { - uReturn = QCBOR_ERR_STRING_TOO_LONG; - goto Done; - } - - const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen); - if(UsefulBuf_IsNULLC(Bytes)) { - /* Failed to get the bytes for this string item */ - uReturn = QCBOR_ERR_HIT_END; - goto Done; - } - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - /* Note that this is not where allocation to coalesce - * indefinite-length strings is done. This is for when the caller - * has requested all strings be allocated. Disabling indefinite - * length strings also disables this allocate-all option. - */ - if(pAllocator) { - /* request to use the string allocator to make a copy */ - UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen); - if(UsefulBuf_IsNULL(NewMem)) { - uReturn = QCBOR_ERR_STRING_ALLOCATE; - goto Done; - } - pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); - pDecodedItem->uDataAlloc = 1; - goto Done; - } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - (void)pAllocator; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - /* Normal case with no string allocator */ - pDecodedItem->val.string = Bytes; - -Done: - return uReturn; -} - - -/** - * @brief Map the CBOR major types for strings to the QCBOR types. - * - * @param[in] nCBORMajorType The CBOR major type to convert. - * @retturns QCBOR type number. - * - * This only works for the two string types. - */ -static inline uint8_t ConvertStringMajorTypes(int nCBORMajorType) -{ - #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING - #error QCBOR_TYPE_BYTE_STRING no lined up with major type - #endif - - #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING - #error QCBOR_TYPE_TEXT_STRING no lined up with major type - #endif - - return (uint8_t)(nCBORMajorType + 4); -} - - -/** - * @brief Map the CBOR major types for arrays/maps to the QCBOR types. - * - * @param[in] nCBORMajorType The CBOR major type to convert. - * @retturns QCBOR type number. - * - * This only works for the two aggregate types. - */ -static inline uint8_t ConvertArrayOrMapType(int nCBORMajorType) -{ - #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY - #error QCBOR_TYPE_ARRAY value not lined up with major type - #endif - - #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP - #error QCBOR_TYPE_MAP value not lined up with major type - #endif - - return (uint8_t)(nCBORMajorType); -} - - /** * @brief Decode a single primitive data item (decode layer 6). * - * @param[in] pUInBuf Input buffer to read data item from. - * @param[out] pDecodedItem The filled-in decoded item. - * @param[in] pAllocator The allocator to use for strings or NULL. - * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * - * This decodes the most primitive / atomic data item. It does - * no combing of data items. + * @param[in] pMe Decoder context. + * @param[in] bAllocateStrings If true, use allocator for strings. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map. + * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined. + * + * This decodes the most primitive/atomic data item. It does no + * combining of data items. */ static QCBORError -DecodeAtomicDataItem(UsefulInputBuf *pUInBuf, - QCBORItem *pDecodedItem, - const QCBORInternalAllocator *pAllocator) +QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe, + const bool bAllocateStrings, + QCBORItem *pDecodedItem) { QCBORError uReturn; - - /* Get the major type and the argument. The argument could be - * length of more bytes or the value depending on the major - * type. nAdditionalInfo is an encoding of the length of the - * uNumber and is needed to decode floats and doubles. - */ - int nMajorType = 0; - uint64_t uArgument = 0; - int nAdditionalInfo = 0; + int nMajorType = 0; + uint64_t uArgument = 0; + int nAdditionalInfo = 0; memset(pDecodedItem, 0, sizeof(QCBORItem)); - uReturn = DecodeHead(pUInBuf, &nMajorType, &uArgument, &nAdditionalInfo); - if(uReturn) { - goto Done; + /* Decode the "head" that every CBOR item has into the major type, + * argument and the additional info. + */ + uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo); + if(uReturn != QCBOR_SUCCESS) { + return uReturn; } - /* At this point the major type and the argument are valid. We've - * got the type and the argument that starts every CBOR data item. + /* All the functions below get inlined by the optimizer. This code + * is easier to read with them all being similar functions, even if + * some functions don't do much. */ switch (nMajorType) { case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */ case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */ - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - uReturn = QCBOR_ERR_BAD_INT; - } else { - uReturn = DecodeInteger(nMajorType, uArgument, pDecodedItem); - } + return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */ case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */ - pDecodedItem->uDataType = ConvertStringMajorTypes(nMajorType); - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE}; - } else { - uReturn = DecodeBytes(pAllocator, uArgument, pUInBuf, pDecodedItem); - } + return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */ case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */ - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - /* Indefinite-length string. */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH; -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED; - break; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - } else { - /* Definite-length string. */ - if(uArgument > QCBOR_MAX_ITEMS_IN_ARRAY) { - uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - goto Done; - } - /* cast OK because of check above */ - pDecodedItem->val.uCount = (uint16_t)uArgument; - } - pDecodedItem->uDataType = ConvertArrayOrMapType(nMajorType); + return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */ -#ifndef QCBOR_DISABLE_TAGS - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - uReturn = QCBOR_ERR_BAD_INT; - } else { - pDecodedItem->val.uTagV = uArgument; - pDecodedItem->uDataType = QCBOR_TYPE_TAG; - } -#else /* QCBOR_DISABLE_TAGS */ - uReturn = QCBOR_ERR_TAGS_DISABLED; -#endif /* QCBOR_DISABLE_TAGS */ + return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_SIMPLE: /* Major type 7: float, double, true, false, null... */ - uReturn = DecodeType7(nAdditionalInfo, uArgument, pDecodedItem); + return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem); break; default: /* Never happens because DecodeHead() should never return > 7 */ - uReturn = QCBOR_ERR_UNSUPPORTED; + return QCBOR_ERR_UNSUPPORTED; break; } - -Done: - return uReturn; } @@ -1176,18 +1367,27 @@ DecodeAtomicDataItem(UsefulInputBuf *pUInBuf, * @param[in] pMe Decoder context * @param[out] pDecodedItem The decoded item that work is done on. * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. * * If @c pDecodedItem is not an indefinite-length string, this does nothing. * @@ -1198,8 +1398,9 @@ DecodeAtomicDataItem(UsefulInputBuf *pUInBuf, * * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH */ -static inline QCBORError -QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +static QCBORError +QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { /* Aproximate stack usage * 64-bit 32-bit @@ -1208,57 +1409,53 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * QCBORItem 56 52 * TOTAL 120 74 */ + QCBORError uReturn; - /* The string allocator is used here for two purposes: 1) - * coalescing the chunks of an indefinite-length string, 2) - * allocating storage for every string returned when requested. - * - * The first use is below in this function. Indefinite-length - * strings cannot be processed at all without a string allocator. - * - * The second used is in DecodeBytes() which is called by - * GetNext_Item() below. This second use unneccessary for most use - * and only happens when requested in the call to - * QCBORDecode_SetMemPool(). If the second use not requested then - * NULL is passed for the string allocator to GetNext_Item(). - * - * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string - * allocator altogether and thus both of these uses. It reduced the - * decoder object code by about 400 bytes. + /* A note about string allocation -- Memory for strings is + * allocated either because 1) indefinte-length string chunks are + * being coalecsed or 2) caller has requested all strings be + * allocated. The first case is handed below here. The second case + * is handled in DecodeString if the bAllocate is true. That + * boolean originates here with pMe->bStringAllocateAll immediately + * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called + * in two different contexts here 1) main-line processing which is + * where definite-length strings need to be allocated if + * bStringAllocateAll is true and 2) processing chunks of + * indefinite-lengths strings in in which case there must be no + * allocation. */ - const QCBORInternalAllocator *pAllocatorForGetNext = NULL; -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - const QCBORInternalAllocator *pAllocator = NULL; - if(pMe->StringAllocator.pfAllocator) { - pAllocator = &(pMe->StringAllocator); - if(pMe->bStringAllocateAll) { - pAllocatorForGetNext = pAllocator; - } + uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem); + if(uReturn != QCBOR_SUCCESS) { + goto Done; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - QCBORError uReturn; - uReturn = DecodeAtomicDataItem(&(pMe->InBuf), pDecodedItem, pAllocatorForGetNext); - if(uReturn != QCBOR_SUCCESS) { + + /* This is where out-of-place break is detected for the whole + * decoding stack. Break is an error for everything that calls + * QCBORDecode_Private_GetNextFullString(), so the check is + * centralized here. + */ + if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { + uReturn = QCBOR_ERR_BAD_BREAK; goto Done; } - /* Only do indefinite-length processing on strings */ + + /* Skip out if not an indefinite-length string */ const uint8_t uStringType = pDecodedItem->uDataType; - if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) { + if(uStringType != QCBOR_TYPE_BYTE_STRING && + uStringType != QCBOR_TYPE_TEXT_STRING) { goto Done; } - - /* Is this a string with an indefinite length? */ if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) { goto Done; } #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS /* Can't decode indefinite-length strings without a string allocator */ - if(pAllocator == NULL) { + if(!pMe->StringAllocator.pfAllocator) { uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; goto Done; } @@ -1269,12 +1466,12 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) for(;;) { /* Get QCBORItem for next chunk */ QCBORItem StringChunkItem; - /* Pass a NULL string allocator to GetNext_Item() because the - * individual string chunks in an indefinite-length should not - * be allocated. They are always copied in the the contiguous - * buffer allocated here. + /* Pass false to DecodeAtomicDataItem() because the individual + * string chunks in an indefinite-length must not be + * allocated. They are always copied into the allocated + * contiguous buffer allocated here. */ - uReturn = DecodeAtomicDataItem(&(pMe->InBuf), &StringChunkItem, NULL); + uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem); if(uReturn) { break; } @@ -1303,15 +1500,14 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * equivalent to StringAllocator_Allocate(). Subsequently it is * not NULL and a reallocation happens. */ - UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator, + UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator), FullString.ptr, FullString.len + StringChunkItem.val.string.len); - if(UsefulBuf_IsNULL(NewMem)) { uReturn = QCBOR_ERR_STRING_ALLOCATE; break; } - + /* Copy new string chunk to the end of accumulated string */ FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string); } @@ -1319,7 +1515,7 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) { /* Getting the item failed, clean up the allocated memory */ - StringAllocator_Free(pAllocator, FullString.ptr); + StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr); } #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED; @@ -1349,8 +1545,10 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * * See also UnMapTagNumber() and @ref QCBORItem. */ -static inline QCBORError -MapTagNumber(QCBORDecodeContext *pMe, uint64_t uUnMappedTag, uint16_t *puMappedTagNumer) +static QCBORError +QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe, + const uint64_t uUnMappedTag, + uint16_t *puMappedTagNumer) { if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) { unsigned uTagMapIndex; @@ -1391,7 +1589,8 @@ MapTagNumber(QCBORDecodeContext *pMe, uint64_t uUnMappedTag, uint16_t *puMappedT * This is the reverse of MapTagNumber() */ static uint64_t -UnMapTagNumber(const QCBORDecodeContext *pMe, uint16_t uMappedTagNumber) +QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe, + const uint16_t uMappedTagNumber) { if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) { return uMappedTagNumber; @@ -1413,27 +1612,37 @@ UnMapTagNumber(const QCBORDecodeContext *pMe, uint16_t uMappedTagNumber) * * @param[in] pMe Decoder context * @param[out] pDecodedItem The decoded item that work is done on. - - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED - * @retval QCBOR_ERR_TOO_MANY_TAGS + * + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. + * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. * * This loops getting atomic data items until one is not a tag * number. Usually this is largely pass-through because most * item are not tag numbers. */ static QCBORError -QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { #ifndef QCBOR_DISABLE_TAGS /* Accummulate the tags from multiple items here and then copy them @@ -1452,7 +1661,7 @@ QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* Loop fetching data items until the item fetched is not a tag */ for(;;) { - QCBORError uErr = QCBORDecode_GetNextFullString(pMe, pDecodedItem); + QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem); if(uErr != QCBOR_SUCCESS) { uReturn = uErr; goto Done; @@ -1484,7 +1693,7 @@ QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* Map the tag */ uint16_t uMappedTagNumber = 0; - uReturn = MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber); + uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber); /* Continue even on error so as to consume all tags wrapping * this data item so decoding can go on. If MapTagNumber() * errors once it will continue to error. @@ -1497,119 +1706,120 @@ QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) #else /* QCBOR_DISABLE_TAGS */ - return QCBORDecode_GetNextFullString(pMe, pDecodedItem); + return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem); #endif /* QCBOR_DISABLE_TAGS */ } + /** * @brief Combine a map entry label and value into one item (decode layer 3). * * @param[in] pMe Decoder context * @param[out] pDecodedItem The decoded item that work is done on. * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED - * @retval QCBOR_ERR_TOO_MANY_TAGS - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG - * @retval QCBOR_ERR_MAP_LABEL_TYPE - * - * If a the current nesting level is a map, then this - * combines pairs of items into one data item with a label - * and value. - * - * This is passthrough if the current nesting level is - * not a map. - * - * This also implements maps-as-array mode where a map - * is treated like an array to allow caller to do their - * own label processing. - */ -static inline QCBORError -QCBORDecode_GetNextMapEntry(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBORDecode_GetNextTagNumber(pMe, pDecodedItem); - if(uReturn != QCBOR_SUCCESS) { + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. + * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array. + * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer. + * + * If the current nesting level is a map, then this combines pairs of + * items into one data item with a label and value. + * + * This is passthrough if the current nesting level is not a map. + * + * This also implements maps-as-array mode where a map is treated like + * an array to allow caller to do their own label processing. + */ + +static QCBORError +QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) +{ + QCBORItem LabelItem; + QCBORError uErr; + + uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem); + if(QCBORDecode_IsUnrecoverableError(uErr)) { goto Done; } - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - /* Break can't be a map entry */ + if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) { + /* Not decoding a map. Nothing to do. */ + /* When decoding maps-as-arrays, the type will be + * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit + * here. This is now map processing for maps-as-arrays is not + * done. */ goto Done; } - if(pMe->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) { - /* Normal decoding of maps -- combine label and value into one item. */ + /* Decoding a map entry, so the item decoded above was the label */ + LabelItem = *pDecodedItem; - if(DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) { - /* Save label in pDecodedItem and get the next which will - * be the real data item. - */ - QCBORItem LabelItem = *pDecodedItem; - uReturn = QCBORDecode_GetNextTagNumber(pMe, pDecodedItem); - if(QCBORDecode_IsUnrecoverableError(uReturn)) { - goto Done; - } + /* Get the value of the map item */ + uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem); + if(QCBORDecode_IsUnrecoverableError(uErr)) { + goto Done; + } - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; + /* Combine the label item and value item into one */ + pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; + pDecodedItem->uLabelType = LabelItem.uDataType; - if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) { - /* strings are always good labels */ - pDecodedItem->label.string = LabelItem.val.string; - pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING; - } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == pMe->uDecodeMode) { - /* It's not a string and we only want strings */ - uReturn = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) { - pDecodedItem->label.int64 = LabelItem.val.int64; - pDecodedItem->uLabelType = QCBOR_TYPE_INT64; - } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) { - pDecodedItem->label.uint64 = LabelItem.val.uint64; - pDecodedItem->uLabelType = QCBOR_TYPE_UINT64; - } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) { - pDecodedItem->label.string = LabelItem.val.string; - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; - pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING; - } else { - /* label is not an int or a string. It is an arrray - * or a float or such and this implementation doesn't handle that. - * Also, tags on labels are ignored. - */ - uReturn = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } - } - } else { - /* Decoding of maps as arrays to let the caller decide what to do - * about labels, particularly lables that are not integers or - * strings. - */ - if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) { - if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) { - uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - goto Done; - } - pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; - /* 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); - } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe + * get rid of it in QCBOR 2.0 + */ + if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY && + LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) { + uErr = QCBOR_ERR_MAP_LABEL_TYPE; + goto Done; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + switch(LabelItem.uDataType) { + case QCBOR_TYPE_INT64: + pDecodedItem->label.int64 = LabelItem.val.int64; + break; + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + case QCBOR_TYPE_UINT64: + pDecodedItem->label.uint64 = LabelItem.val.uint64; + break; + + case QCBOR_TYPE_TEXT_STRING: + case QCBOR_TYPE_BYTE_STRING: + pDecodedItem->label.string = LabelItem.val.string; + break; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + default: + uErr = QCBOR_ERR_MAP_LABEL_TYPE; + goto Done; } Done: - return uReturn; + return uErr; } @@ -1617,7 +1827,7 @@ QCBORDecode_GetNextMapEntry(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /** * @brief Peek and see if next data item is a break; * - * @param[in] pUIB UsefulInputBuf to read from. + * param[in] pUIB UsefulInputBuf to read from. * @param[out] pbNextIsBreak Indicate if next was a break or not. * * @return Any decoding error. @@ -1625,20 +1835,20 @@ QCBORDecode_GetNextMapEntry(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * See if next item is a CBOR break. If it is, it is consumed, * if not it is not consumed. */ -static inline QCBORError -NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak) +static QCBORError +QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak) { *pbNextIsBreak = false; - if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) { + if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) { QCBORItem Peek; - size_t uPeek = UsefulInputBuf_Tell(pUIB); - QCBORError uReturn = DecodeAtomicDataItem(pUIB, &Peek, NULL); + size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf)); + QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek); if(uReturn != QCBOR_SUCCESS) { return uReturn; } if(Peek.uDataType != QCBOR_TYPE_BREAK) { /* It is not a break, rewind so it can be processed normally. */ - UsefulInputBuf_Seek(pUIB, uPeek); + UsefulInputBuf_Seek(&(pMe->InBuf), uPeek); } else { *pbNextIsBreak = true; } @@ -1654,18 +1864,30 @@ NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak) * * @param[in] pMe The decode context. * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero. + * @param[out] pbBreak Set to true if extra break was consumed. * * An item was just consumed, now figure out if it was the * end of an array/map map that can be closed out. That * may in turn close out the above array/map... -*/ + * + * When ascending indefinite-length arrays and maps, this will correctly + * consume the break for the level above. This is a problem for the + * implementation of QCBORDecode_GetArray() that must not return + * that break. @c pbBreak is set to true to indicate that one + * byte should be removed. + * + * Improvement: this could reduced further if indef is disabled + */ static QCBORError -QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) +QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak) { QCBORError uReturn; /* Loop ascending nesting levels as long as there is ascending to do */ while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) { + if(pbBreak) { + *pbBreak = false; + } if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) { /* Nesting level is bstr-wrapped CBOR */ @@ -1694,7 +1916,7 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) /* Check for a break which is what ends indefinite-length arrays/maps */ bool bIsBreak = false; - uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak); + uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -1707,6 +1929,9 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) /* It was a break in an indefinitelength map / array so * it is time to ascend one level. */ + if(pbBreak) { + *pbBreak = true; + } #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ } @@ -1746,26 +1971,38 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) * @brief Ascending & Descending out of nesting levels (decode layer 2). * * @param[in] pMe Decoder context + * @param[out] pbBreak Set to true if extra break was consumed. * @param[out] pDecodedItem The decoded item that work is done on. - * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED - * @retval QCBOR_ERR_TOO_MANY_TAGS - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG - * @retval QCBOR_ERR_MAP_LABEL_TYPE - * @retval QCBOR_ERR_NO_MORE_ITEMS - * @retval QCBOR_ERR_BAD_BREAK - * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP + + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. + * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array. + * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer. + * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array. + * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong + * place. + * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR + * can handle. * * This handles the traversal descending into and asecnding out of * maps, arrays and bstr-wrapped CBOR. It figures out the ends of @@ -1774,7 +2011,9 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) * top-level sequence and of bstr-wrapped CBOR by byte count. */ static QCBORError -QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe, + bool *pbBreak, + QCBORItem *pDecodedItem) { QCBORError uReturn; /* ==== First: figure out if at the end of a traversal ==== */ @@ -1802,20 +2041,12 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) } /* ==== Next: not at the end, so get another item ==== */ - uReturn = QCBORDecode_GetNextMapEntry(pMe, pDecodedItem); + uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem); if(QCBORDecode_IsUnrecoverableError(uReturn)) { /* Error is so bad that traversal is not possible. */ goto Done; } - /* Breaks ending arrays/maps are processed later in the call to - * QCBORDecode_NestLevelAscender(). They should never show up here. - */ - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - uReturn = QCBOR_ERR_BAD_BREAK; - goto Done; - } - /* Record the nesting level for this data item before processing * any of decrementing and descending. */ @@ -1823,7 +2054,7 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* ==== Next: Process the item for descent, ascent, decrement... ==== */ - if(QCBORItem_IsMapOrArray(pDecodedItem)) { + if(QCBORItem_IsMapOrArray(*pDecodedItem)) { /* If the new item is a map or array, descend. * * Empty indefinite-length maps and arrays are descended into, @@ -1837,8 +2068,8 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) */ QCBORError uDescendErr; uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting), - pDecodedItem->uDataType, - pDecodedItem->val.uCount); + pDecodedItem->uDataType, + pDecodedItem->val.uCount); if(uDescendErr != QCBOR_SUCCESS) { /* This error is probably a traversal error and it overrides * the non-traversal error. @@ -1848,9 +2079,9 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) } } - if(!QCBORItem_IsMapOrArray(pDecodedItem) || - QCBORItem_IsEmptyDefiniteLengthMapOrArray(pDecodedItem) || - QCBORItem_IsIndefiniteLengthMapOrArray(pDecodedItem)) { + if(!QCBORItem_IsMapOrArray(*pDecodedItem) || + QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) || + QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) { /* The following cases are handled here: * - A non-aggregate item like an integer or string * - An empty definite-length map or array @@ -1863,7 +2094,7 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * to the top level. */ QCBORError uAscendErr; - uAscendErr = QCBORDecode_NestLevelAscender(pMe, true); + uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak); if(uAscendErr != QCBOR_SUCCESS) { /* This error is probably a traversal error and it overrides * the non-traversal error. @@ -1897,28 +2128,32 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * * pDecodedItem[in,out] The data item to convert. * - * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is + * The 0th tag is discarded. @ref CBOR_TAG_INVALID16 is * shifted into empty slot at the end of the tag list. */ -static inline void ShiftTags(QCBORItem *pDecodedItem) +static void +QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem) { for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) { pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1]; } pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16; } - #endif /* QCBOR_DISABLE_TAGS */ + /** * @brief Convert different epoch date formats in to the QCBOR epoch date format * * pDecodedItem[in,out] The data item to convert. * - * @retval QCBOR_ERR_DATE_OVERFLOW - * @retval QCBOR_ERR_FLOAT_DATE_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT + * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer. + * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input, + * floating-point date disabled. + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input, + * all floating-point disabled. + * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable + * error decoding date. * * The epoch date tag defined in QCBOR allows for floating-point * dates. It even allows a protocol to flop between date formats when @@ -1928,7 +2163,8 @@ static inline void ShiftTags(QCBORItem *pDecodedItem) * This converts all the date formats into one format of an unsigned * integer plus a floating-point fraction. */ -static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; @@ -2023,15 +2259,19 @@ static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem) * * pDecodedItem[in,out] The data item to convert. * - * @retval QCBOR_ERR_DATE_OVERFLOW - * @retval QCBOR_ERR_FLOAT_DATE_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT + * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer. + * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input, + * floating-point date disabled. + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input, + * all floating-point disabled. + * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable + * error decoding date. * * This is much simpler than the other epoch date format because * floating-porint is not allowed. This is mostly a simple type check. */ -static QCBORError DecodeDaysEpoch(QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; @@ -2076,7 +2316,8 @@ static QCBORError DecodeDaysEpoch(QCBORItem *pDecodedItem) * correctly and the correct error is returned. */ static QCBORError -QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); +QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem); /** @@ -2089,7 +2330,7 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); * exponent. * * @returns Decoding errors from getting primitive data items or - * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA. + * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA. * * When called pDecodedItem must be the array with two members, the * exponent and mantissa. @@ -2104,7 +2345,8 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); * the caller will process it. */ static QCBORError -QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { QCBORError uReturn; @@ -2115,7 +2357,7 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem } /* A check for pDecodedItem->val.uCount == 2 would work for - * definite-length arrays, but not for indefinite. Instead remember + * definite-length arrays, but not for indefinite. Instead remember * the nesting level the two integers must be at, which is one * deeper than that of the array. */ @@ -2123,7 +2365,7 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem /* --- Get the exponent --- */ QCBORItem exponentItem; - uReturn = QCBORDecode_GetNextMapOrArray(pMe, &exponentItem); + uReturn = QCBORDecode_GetNext(pMe, &exponentItem); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -2148,7 +2390,7 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem /* --- Get the mantissa --- */ QCBORItem mantissaItem; - uReturn = QCBORDecode_GetNextTagContent(pMe, &mantissaItem); + uReturn = QCBORDecode_GetNext(pMe, &mantissaItem); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -2211,7 +2453,8 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem * f or ProcessTaggedString() because the RFC 7049 MIME type was * incorreclty text-only. */ -static inline QCBORError DecodeMIME(QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem) { if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) { pDecodedItem->uDataType = QCBOR_TYPE_MIME; @@ -2243,7 +2486,7 @@ struct StringTagMapEntry { #define IS_BYTE_STRING_BIT 0x80 #define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT -static const struct StringTagMapEntry StringTagMap[] = { +static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = { {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING}, {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING}, {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT}, @@ -2268,8 +2511,8 @@ static const struct StringTagMapEntry StringTagMap[] = { * @param[in,out] pDecodedItem The data item. * * @returns This returns QCBOR_SUCCESS if the tag was procssed, - * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and - * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag. + * @ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and + * @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag. * * Process the CBOR tags that whose content is a byte string or a text * string and for which the string is just passed on to the caller. @@ -2279,8 +2522,8 @@ static const struct StringTagMapEntry StringTagMap[] = { * functionality, but it part of implementing as much of RFC 8949 as * possible. */ -static inline QCBORError -ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) { /* This only works on tags that were not mapped; no need for other yet */ if(uTag > QCBOR_LAST_UNMAPPED_TAG) { @@ -2288,13 +2531,13 @@ ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) } unsigned uIndex; - for(uIndex = 0; StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) { - if(StringTagMap[uIndex].uTagNumber == uTag) { + for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) { + if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) { break; } } - const uint8_t uQCBORType = StringTagMap[uIndex].uQCBORtype; + const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype; if(uQCBORType == QCBOR_TYPE_NONE) { /* repurpose this error to mean not handled here */ return QCBOR_ERR_UNSUPPORTED; @@ -2320,17 +2563,25 @@ ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA -/* - * This returns the QCBOR_TYPE for a mantissa and exponent. - -Called in one context where there is always a tag - - Called in another context where there might be a tag or the caller might say what they are expecting. - - 6 possible outputs +/** + * @brief Figures out data type for exponent mantissa tags. + * + * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or + * @ref CBOR_TAG_BIG_FLOAT. + * @param[in] pDecodedItem Item being decoded. + * + * @returns One of the 6 values between @ref QCBOR_TYPE_DECIMAL_FRACTION + * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM. + * + * Does mapping between a CBOR tag number and a QCBOR type. with a + * little bit of logic and arithmatic. + * + * Used in serveral contexts. Does the work where sometimes the data + * item is explicitly tagged and sometimes not. */ -static inline uint8_t -MantissaExponentDataType(const uint16_t uTagToProcess, const QCBORItem *pDecodedItem) +static uint8_t +QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess, + const QCBORItem *pDecodedItem) { uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ? QCBOR_TYPE_DECIMAL_FRACTION : @@ -2357,11 +2608,12 @@ MantissaExponentDataType(const uint16_t uTagToProcess, const QCBORItem *pDecoded * quick pass through for items that are not tags. */ static QCBORError -QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { QCBORError uReturn; - uReturn = QCBORDecode_GetNextMapOrArray(pMe, pDecodedItem); + uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -2387,28 +2639,28 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) break; } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) { - uReturn = DecodeDateEpoch(pDecodedItem); + uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem); } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) { - uReturn = DecodeDaysEpoch(pDecodedItem); + uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem); #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION || uTagToProcess == CBOR_TAG_BIGFLOAT) { - uReturn = QCBORDecode_MantissaAndExponent(pMe, pDecodedItem); + uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem); /* --- Which is it, decimal fraction or a bigfloat? --- */ - pDecodedItem->uDataType = MantissaExponentDataType(uTagToProcess, pDecodedItem); + pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem); #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ #ifndef QCBOR_DISABLE_UNCOMMON_TAGS } else if(uTagToProcess == CBOR_TAG_MIME || uTagToProcess == CBOR_TAG_BINARY_MIME) { - uReturn = DecodeMIME(pDecodedItem); + uReturn = QCBOR_Private_DecodeMIME(pDecodedItem); #endif /* QCBOR_DISABLE_UNCOMMON_TAGS */ } else { /* See if it is a passthrough byte/text string tag; process if so */ - uReturn = ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem); + uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem); if(uReturn == QCBOR_ERR_UNSUPPORTED) { /* It wasn't a passthrough byte/text string tag so it is @@ -2428,7 +2680,7 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* A tag was successfully processed, shift it out of the list of * tags returned. This is the loop increment. */ - ShiftTags(pDecodedItem); + QCBOR_Private_ShiftTags(pDecodedItem); } #endif /* QCBOR_DISABLE_TAGS */ @@ -2444,7 +2696,7 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { QCBORError uErr; - uErr = QCBORDecode_GetNextTagContent(pMe, pDecodedItem); + uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem); if(uErr != QCBOR_SUCCESS) { pDecodedItem->uDataType = QCBOR_TYPE_NONE; pDecodedItem->uLabelType = QCBOR_TYPE_NONE; @@ -2478,6 +2730,8 @@ void QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { if(pMe->uLastError != QCBOR_SUCCESS) { + pDecodedItem->uDataType = QCBOR_TYPE_NONE; + pDecodedItem->uLabelType = QCBOR_TYPE_NONE; return; } @@ -2485,16 +2739,31 @@ QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) } +static void +QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) +{ +#ifndef QCBOR_DISABLE_TAGS + memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags)); +#else + (void)pMe; + (void)pItem; +#endif +} + /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +void +QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { if(pMe->uLastError != QCBOR_SUCCESS) { + pDecodedItem->uDataType = QCBOR_TYPE_NONE; + pDecodedItem->uLabelType = QCBOR_TYPE_NONE; return; } pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem); + QCBORDecode_Private_CopyTags(pMe, pDecodedItem); } @@ -2525,7 +2794,7 @@ QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe, if(pTags->uNumUsed >= pTags->uNumAllocated) { return QCBOR_ERR_TOO_MANY_TAGS; } - pTags->puTags[pTags->uNumUsed] = UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]); + pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]); pTags->uNumUsed++; } } @@ -2544,16 +2813,17 @@ QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h file */ -bool QCBORDecode_IsTagged(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint64_t uTag) +bool +QCBORDecode_IsTagged(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint64_t uTag) { #ifndef QCBOR_DISABLE_TAGS for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) { if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) { break; } - if(UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) { + if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) { return true; } } @@ -2570,7 +2840,8 @@ bool QCBORDecode_IsTagged(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h file */ -QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed) +QCBORError +QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed) { if(puConsumed != NULL) { *puConsumed = pMe->InBuf.cursor; @@ -2601,7 +2872,8 @@ QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed /* * Public function, see header qcbor/qcbor_decode.h file */ -QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe) +QCBORError +QCBORDecode_Finish(QCBORDecodeContext *pMe) { #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS /* Call the destructor for the string allocator if there is one. @@ -2617,10 +2889,10 @@ QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe) /* * Public function, see header qcbor/qcbor_decode.h file */ -// Improvement: make these inline? -uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint32_t uIndex) +uint64_t +QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint32_t uIndex) { #ifndef QCBOR_DISABLE_TAGS if(pItem->uDataType == QCBOR_TYPE_NONE) { @@ -2629,7 +2901,7 @@ uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { return CBOR_TAG_INVALID64; } else { - return UnMapTagNumber(pMe, pItem->uTags[uIndex]); + return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]); } #else /* QCBOR_DISABLE_TAGS */ (void)pMe; @@ -2644,8 +2916,9 @@ uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h file */ -uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, - uint32_t uIndex) +uint64_t +QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, + uint32_t uIndex) { #ifndef QCBOR_DISABLE_TAGS @@ -2655,7 +2928,7 @@ uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { return CBOR_TAG_INVALID64; } else { - return UnMapTagNumber(pMe, pMe->uLastTags[uIndex]); + return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]); } #else /* QCBOR_DISABLE_TAGS */ (void)pMe; @@ -2697,7 +2970,7 @@ uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, ========================================================================== */ -static inline int +static int MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset) { // Use of UsefulInputBuf is overkill, but it is convenient. @@ -2712,7 +2985,7 @@ MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset) } -static inline int +static int MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset) { // Use of UsefulOutBuf is overkill, but convenient. The @@ -2817,11 +3090,12 @@ MemPool_Function(void *pPool, void *pMem, size_t uNewSize) /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, - UsefulBuf Pool, - bool bAllStrings) +QCBORError +QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, + UsefulBuf Pool, + bool bAllStrings) { // The pool size and free mem offset are packed into the beginning // of the pool memory. This compile time check makes sure the @@ -2858,17 +3132,6 @@ QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, -static inline void -CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) -{ -#ifndef QCBOR_DISABLE_TAGS - memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags)); -#else - (void)pMe; - (void)pItem; -#endif -} - /** * @brief Consume an entire map or array including its contents. @@ -2883,10 +3146,11 @@ CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) * map. In that case, this is just a pass through for @c puNextNestLevel * since there is nothing to do. */ -static inline QCBORError -ConsumeItem(QCBORDecodeContext *pMe, - const QCBORItem *pItemToConsume, - uint8_t *puNextNestLevel) +static QCBORError +QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe, + const QCBORItem *pItemToConsume, + bool *pbBreak, + uint8_t *puNextNestLevel) { QCBORError uReturn; QCBORItem Item; @@ -2894,14 +3158,14 @@ ConsumeItem(QCBORDecodeContext *pMe, /* If it is a map or array, this will tell if it is empty. */ const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel); - if(QCBORItem_IsMapOrArray(pItemToConsume) && !bIsEmpty) { + if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) { /* There is only real work to do for non-empty maps and arrays */ /* This works for definite- and indefinite-length maps and * arrays by using the nesting level */ do { - uReturn = QCBORDecode_GetNext(pMe, &Item); + uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item); if(QCBORDecode_IsUnrecoverableError(uReturn) || uReturn == QCBOR_ERR_NO_MORE_ITEMS) { goto Done; @@ -2913,7 +3177,7 @@ ConsumeItem(QCBORDecodeContext *pMe, uReturn = QCBOR_SUCCESS; } else { - /* pItemToConsume is not a map or array. Just pass the nesting + /* pItemToConsume is not a map or array. Just pass the nesting * level through. */ *puNextNestLevel = pItemToConsume->uNextNestLevel; @@ -2925,22 +3189,54 @@ ConsumeItem(QCBORDecodeContext *pMe, } -void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { QCBORDecode_VGetNext(pMe, pDecodedItem); if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)ConsumeItem(pMe, pDecodedItem, + pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL, &pDecodedItem->uNextNestLevel); } } +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +QCBORError +QCBORDecode_EndCheck(QCBORDecodeContext *pMe) +{ + size_t uCursorOffset; + QCBORError uErr; + + uErr = QCBORDecode_GetError(pMe); + if(uErr != QCBOR_SUCCESS) { + return uErr; + } + + uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); + + if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) { + return QCBOR_ERR_NO_MORE_ITEMS; + } + + return QCBOR_SUCCESS; +} + -/* Call only on maps and arrays. Rewinds the cursor - * to the start as if it was just entered. +/** + * @brief Rewind cursor to start as if map or array were just entered. + * + * @param[in] pMe The decoding context + * + * This affects the nesting tracking and the UsefulInputBuf. */ -static void RewindMapOrArray(QCBORDecodeContext *pMe) +static void +QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe) { /* Reset nesting tracking to the deepest bounded level */ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); @@ -2954,9 +3250,10 @@ static void RewindMapOrArray(QCBORDecodeContext *pMe) /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_Rewind(QCBORDecodeContext *pMe) +void +QCBORDecode_Rewind(QCBORDecodeContext *pMe) { if(pMe->nesting.pCurrentBounded != NULL) { /* In a bounded map, array or bstr-wrapped CBOR */ @@ -2971,7 +3268,7 @@ void QCBORDecode_Rewind(QCBORDecodeContext *pMe) } else { /* In a map or array */ - RewindMapOrArray(pMe); + QCBORDecode_Private_RewindMapOrArray(pMe); } } else { @@ -2988,91 +3285,56 @@ void QCBORDecode_Rewind(QCBORDecodeContext *pMe) } -/* Return true if the labels in Item1 and Item2 are the same. - Works only for integer and string labels. Returns false - for any other type. */ -static inline bool -MatchLabel(QCBORItem Item1, QCBORItem Item2) -{ - if(Item1.uLabelType == QCBOR_TYPE_INT64) { - if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) { - if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) { - if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) { - if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) { - return true; - } - } - - /* Other label types are never matched */ - return false; -} - - -/* - Returns true if Item1 and Item2 are the same type - or if either are of QCBOR_TYPE_ANY. - */ -static inline bool -MatchType(QCBORItem Item1, QCBORItem Item2) -{ - if(Item1.uDataType == Item2.uDataType) { - return true; - } else if(Item1.uDataType == QCBOR_TYPE_ANY) { - return true; - } else if(Item2.uDataType == QCBOR_TYPE_ANY) { - return true; - } - return false; -} - - -/** - @brief Search a map for a set of items. - - @param[in] pMe The decode context to search. - @param[in,out] pItemArray The items to search for and the items found. - @param[out] puOffset Byte offset of last item matched. - @param[in] pCBContext Context for the not-found item call back. - @param[in] pfCallback Function to call on items not matched in pItemArray. - - @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map - @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) - were found for one of the labels being - search for. This duplicate detection is - only performed for items in pItemArray, - not every item in the map. - @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was - wrong for the matchd label. - @retval Also errors returned by QCBORDecode_GetNext(). +typedef struct { + void *pCBContext; + QCBORItemCallback pfCallback; +} MapSearchCallBack; - On input pItemArray contains a list of labels and data types - of items to be found. +typedef struct { + size_t uStartOffset; + uint16_t uItemCount; +} MapSearchInfo; - On output the fully retrieved items are filled in with - values and such. The label was matched, so it never changes. - If an item was not found, its data type is set to QCBOR_TYPE_NONE. - - This also finds the ends of maps and arrays when they are exited. +/** + * @brief Search a map for a set of items. + * + * @param[in] pMe The decode context to search. + * @param[in,out] pItemArray The items to search for and the items found. + * @param[out] pInfo Several bits of meta-info returned by search. + * @param[in] pCallBack Callback object or @c NULL. + * + * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map. + * + * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) + * were found for one of the labels being + * search for. This duplicate detection is + * only performed for items in pItemArray, + * not every item in the map. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was + * wrong for the matchd label. + * + * @retval Also errors returned by QCBORDecode_GetNext(). + * + * On input, @c pItemArray contains a list of labels and data types of + * items to be found. + * + * On output, the fully retrieved items are filled in with values and + * such. The label was matched, so it never changes. + * + * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE. + * + * This also finds the ends of maps and arrays when they are exited. */ static QCBORError -MapSearch(QCBORDecodeContext *pMe, - QCBORItem *pItemArray, - size_t *puOffset, - void *pCBContext, - QCBORItemCallback pfCallback) +QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe, + QCBORItem *pItemArray, + MapSearchInfo *pInfo, + MapSearchCallBack *pCallBack) { QCBORError uReturn; uint64_t uFoundItemBitMap = 0; @@ -3105,10 +3367,11 @@ MapSearch(QCBORDecodeContext *pMe, } QCBORDecodeNesting SaveNesting; + size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf)); DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting); /* Reposition to search from the start of the map / array */ - RewindMapOrArray(pMe); + QCBORDecode_Private_RewindMapOrArray(pMe); /* Loop over all the items in the map or array. Each item @@ -3128,6 +3391,9 @@ MapSearch(QCBORDecodeContext *pMe, that error code is returned. */ const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting)); + if(pInfo) { + pInfo->uItemCount = 0; + } uint8_t uNextNestLevel; do { /* Remember offset of the item because sometimes it has to be returned */ @@ -3135,14 +3401,17 @@ MapSearch(QCBORDecodeContext *pMe, /* Get the item */ QCBORItem Item; - QCBORError uResult = QCBORDecode_GetNextTagContent(pMe, &Item); + /* QCBORDecode_Private_GetNextTagContent() rather than GetNext() + * because a label match is performed on recoverable errors to + * be able to return the the error code for the found item. */ + QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item); if(QCBORDecode_IsUnrecoverableError(uResult)) { - /* Unrecoverable error so map can't even be decoded. */ + /* The map/array can't be decoded when unrecoverable errors occur */ uReturn = uResult; goto Done; } if(uResult == QCBOR_ERR_NO_MORE_ITEMS) { - // Unexpected end of map or array. + /* Unexpected end of map or array. */ uReturn = uResult; goto Done; } @@ -3150,18 +3419,20 @@ MapSearch(QCBORDecodeContext *pMe, /* See if item has one of the labels that are of interest */ bool bMatched = false; for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) { - if(MatchLabel(Item, pItemArray[nIndex])) { + if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) { /* A label match has been found */ if(uFoundItemBitMap & (0x01ULL << nIndex)) { uReturn = QCBOR_ERR_DUPLICATE_LABEL; goto Done; } if(uResult != QCBOR_SUCCESS) { - /* The label matches, but the data item is in error */ + /* The label matches, but the data item is in error. + * It is OK to have recoverable errors on items that + * are not matched. */ uReturn = uResult; goto Done; } - if(!MatchType(Item, pItemArray[nIndex])) { + if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) { /* The data item is not of the type(s) requested */ uReturn = QCBOR_ERR_UNEXPECTED_TYPE; goto Done; @@ -3170,22 +3441,22 @@ MapSearch(QCBORDecodeContext *pMe, /* Successful match. Return the item. */ pItemArray[nIndex] = Item; uFoundItemBitMap |= 0x01ULL << nIndex; - if(puOffset) { - *puOffset = uOffset; + if(pInfo) { + pInfo->uStartOffset = uOffset; } bMatched = true; } } - if(!bMatched && pfCallback != NULL) { + if(!bMatched && pCallBack != NULL) { /* Call the callback on unmatched labels. (It is tempting to do duplicate detection here, but that would require dynamic memory allocation because the number of labels that might be encountered is unbounded.) */ - uReturn = (*pfCallback)(pCBContext, &Item); + uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -3198,11 +3469,15 @@ MapSearch(QCBORDecodeContext *pMe, items at the current nesting level are examined to match the labels. */ - uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel); + uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel); if(uReturn != QCBOR_SUCCESS) { goto Done; } + if(pInfo) { + pInfo->uItemCount++; + } + } while (uNextNestLevel >= uMapNestLevel); uReturn = QCBOR_SUCCESS; @@ -3222,6 +3497,7 @@ MapSearch(QCBORDecodeContext *pMe, Done: DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting); + UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos); Done2: /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */ @@ -3237,12 +3513,13 @@ MapSearch(QCBORDecodeContext *pMe, /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uQcborType, - QCBORItem *pItem) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint8_t uQcborType, + QCBORItem *pItem) { if(pMe->uLastError != QCBOR_SUCCESS) { return; @@ -3254,42 +3531,51 @@ void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, OneItemSeach[0].uDataType = uQcborType; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - QCBORError uReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL); - - *pItem = OneItemSeach[0]; + QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL); if(uReturn != QCBOR_SUCCESS) { + pItem->uDataType = QCBOR_TYPE_NONE; + pItem->uLabelType = QCBOR_TYPE_NONE; goto Done; } + if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) { uReturn = QCBOR_ERR_LABEL_NOT_FOUND; } + *pItem = OneItemSeach[0]; + QCBORDecode_Private_CopyTags(pMe, pItem); + Done: pMe->uLastError = (uint8_t)uReturn; } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uQcborType, - QCBORItem *pItem) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uQcborType, + QCBORItem *pItem) { if(pMe->uLastError != QCBOR_SUCCESS) { return; } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); OneItemSeach[0].uDataType = uQcborType; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - QCBORError uReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL); + QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL); + if(uReturn != QCBOR_SUCCESS) { + pItem->uDataType = QCBOR_TYPE_NONE; + pItem->uLabelType = QCBOR_TYPE_NONE; goto Done; } if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) { @@ -3298,56 +3584,225 @@ void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, } *pItem = OneItemSeach[0]; + QCBORDecode_Private_CopyTags(pMe, pItem); Done: +#else + (void)pMe; + (void)szLabel; + (void)uQcborType; + (void)pItem; + QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + pMe->uLastError = (uint8_t)uReturn; } -static QCBORError -CheckTypeList(int uDataType, const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES]) -{ - for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) { - if(uDataType == puTypeList[i]) { - return QCBOR_SUCCESS; - } - } - return QCBOR_ERR_UNEXPECTED_TYPE; -} - /** - * Match a tag/type specification against the type of the item. - * - * @param[in] TagSpec Specification for matching tags. - * @param[in] pItem The item to check. - * - * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec - * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec + * @brief Semi-private. Get pointer, length and item for an array or map. * - * This checks the item data type of untagged items as well as of - * tagged items against a specification to see if decoding should - * proceed. + * @param[in] pMe The decode context. + * @param[in] uType CBOR major type, either array/map. + * @param[out] pItem The item for the array/map. + * @param[out] pEncodedCBOR Pointer and length of the encoded map or array. * - * This relies on the automatic tag decoding done by QCBOR that turns - * tag numbers into particular QCBOR_TYPEs so there is no actual - * comparsion of tag numbers, just of QCBOR_TYPEs. + * The next item to be decoded must be a map or array as specified by @c uType. * - * This checks the data item type as possibly representing the tag - * number or as the tag content type. + * @c pItem will be filled in with the label and tags of the array or map + * in addition to @c pEncodedCBOR giving the pointer and length of the + * encoded CBOR. * - * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item - * data type against the allowed tag content types. It will also error out - * if the caller tries to require a tag because there is no way that can - * ever be fulfilled. + * When this is complete, the traversal cursor is at the end of the array or + * map that was retrieved. */ -static QCBORError -CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem) +void +QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe, + const uint8_t uType, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORError uErr; + uint8_t uNestLevel; + size_t uStartingCursor; + size_t uStartOfReturned; + size_t uEndOfReturned; + size_t uTempSaveCursor; + bool bInMap; + QCBORItem LabelItem; + bool EndedByBreak; + + uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); + bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting)); + + /* Could call GetNext here, but don't need to because this + * is only interested in arrays and maps. */ + uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem); + if(uErr != QCBOR_SUCCESS) { + pMe->uLastError = (uint8_t)uErr; + return; + } + + uint8_t uItemDataType = pItem->uDataType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { + pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; + return; + } + + if(bInMap) { + /* If the item is in a map, the start of the array/map + * itself, not the label, must be found. Do this by + * rewinding to the starting position and fetching + * just the label data item. QCBORDecode_Private_GetNextTagNumber() + * doesn't do any of the array/map item counting or nesting + * level tracking. Used here it will just fetech the label + * data item. + * + * Have to save the cursor and put it back to the position + * after the full item once the label as been fetched by + * itself. + */ + uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); + UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor); + + /* Item has been fetched once so safe to ignore error */ + (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem); + + uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf)); + UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor); + } else { + uStartOfReturned = uStartingCursor; + } + + /* Consume the entire array/map to find the end */ + uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel); + if(uErr != QCBOR_SUCCESS) { + pMe->uLastError = (uint8_t)uErr; + goto Done; + } + + /* Fill in returned values */ + uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf)); + if(EndedByBreak) { + /* When ascending nesting levels, a break for the level above + * was consumed. That break is not a part of what is consumed here. */ + uEndOfReturned--; + } + pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned); + pEncodedCBOR->len = uEndOfReturned - uStartOfReturned; + +Done: + return; +} + + +/** + * @brief Semi-private. Get pointer, length and item count of an array or map. + * + * @param[in] pMe The decode context. + * @param[in] pTarget The label and type of the array or map to retrieve. + * @param[out] pItem The item for the array/map. + * @param[out] pEncodedCBOR Pointer and length of the encoded map or array. + * + * The next item to be decoded must be a map or array as specified by @c uType. + * + * When this is complete, the traversal cursor is unchanged. + */void +QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe, + QCBORItem *pTarget, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) { - const int nItemType = pItem->uDataType; + MapSearchInfo Info; + QCBORDecodeNesting SaveNesting; + size_t uSaveCursor; + + pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL); + if(pMe->uLastError != QCBOR_SUCCESS) { + return; + } + + /* Save the whole position of things so they can be restored. + * so the cursor position is unchanged by this operation, like + * all the other GetXxxxInMap() operations. */ + DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting); + uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); + + DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); + UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset); + QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR); + + UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor); + DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting); +} + + + + +/** + * @brief Is a QCBOR_TYPE in the type list? + * + * @param[in] uDataType Type to check for. + * @param[in] puTypeList List to check. + * + * @retval QCBOR_SUCCESS If in the list. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list. + */ +static QCBORError +QCBOR_Private_CheckTypeList(const int uDataType, + const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES]) +{ + for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) { + if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */ + return QCBOR_SUCCESS; + } + } + return QCBOR_ERR_UNEXPECTED_TYPE; +} + + +/** + * Match a tag/type specification against the type of the item. + * + * @param[in] TagSpec Specification for matching tags. + * @param[in] pItem The item to check. + * + * @retval QCBOR_SUCCESS @c uDataType is allowed by @c TagSpec + * @retval QCBOR_ERR_UNEXPECTED_TYPE @c uDataType is not allowed by @c TagSpec + * + * This checks the item data type of untagged items as well as of + * tagged items against a specification to see if decoding should + * proceed. + * + * This relies on the automatic tag decoding done by QCBOR that turns + * tag numbers into particular QCBOR_TYPEs so there is no actual + * comparsion of tag numbers, just of QCBOR_TYPEs. + * + * This checks the data item type as possibly representing the tag + * number or as the tag content type. + * + * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item + * data type against the allowed tag content types, but also checks + * against the tagged types. The QCBOR_TYPEs checked will never be + * associated with tag numbers, but this checking is needed for the + * text and byte string use cases . + */ +static QCBORError +QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec, + const QCBORItem *pItem) +{ + const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */ const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS; #ifndef QCBOR_DISABLE_TAGS + /* -Wmaybe-uninitialized falsly warns here */ if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) && pItem->uTags[0] != CBOR_TAG_INVALID16) { /* There are tags that QCBOR couldn't process on this item and @@ -3358,10 +3813,10 @@ CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem) if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { /* Must match the tag number and only the tag */ - return CheckTypeList(nItemType, TagSpec.uTaggedTypes); + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); } - QCBORError uReturn = CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); + QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); if(uReturn == QCBOR_SUCCESS) { return QCBOR_SUCCESS; } @@ -3372,61 +3827,99 @@ CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem) return QCBOR_ERR_UNEXPECTED_TYPE; } - /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content - * and it hasn't matched the content, so the end - * result is whether it matches the tag. This is - * the tag optional case that the CBOR standard discourages. + /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either + * the tag or the content and it hasn't matched the content, so the + * end result is whether it matches the tag. This is the tag + * optional case that the CBOR standard discourages. */ - return CheckTypeList(nItemType, TagSpec.uTaggedTypes); + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); #else /* QCBOR_DISABLE_TAGS */ if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { - return QCBOR_ERR_UNEXPECTED_TYPE; + /* This is only checking base QCBOR types, not those associated + * with tag numbers since you can get here with tag numbers. + */ + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); } - return CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); #endif /* QCBOR_DISABLE_TAGS */ } -// This could be semi-private if need be -static inline -void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const TagSpecification TagSpec, - QCBORItem *pItem) +/** + * @brief Get an item by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] nLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pItem The item found. + * + * This finds the item with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +static void +QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem); + pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem); } -// This could be semi-private if need be -static inline -void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const TagSpecification TagSpec, - QCBORItem *pItem) +/** + * @brief Get an item by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] szLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pItem The item found. + * + * This finds the item with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +static void +QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem) { QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem); + pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem); } -// Semi-private -void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - TagSpecification TagSpec, - UsefulBufC *pString) + +/** + * @brief Semi-private to get an string by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] nLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pString The string found. + * + * This finds the string with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +void +QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString) { QCBORItem Item; QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item); @@ -3435,11 +3928,23 @@ void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe, } } -// Semi-private -void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - TagSpecification TagSpec, - UsefulBufC *pString) + +/** + * @brief Semi-private to get an string by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] szLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pString The string found. + * + * This finds the string with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */void +QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, + const char * szLabel, + const QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString) { QCBORItem Item; QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item); @@ -3448,24 +3953,32 @@ void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, } } + /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList) { - QCBORError uErr = MapSearch(pMe, pItemList, NULL, NULL, NULL); + QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL); pMe->uLastError = (uint8_t)uErr; } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, - QCBORItem *pItemList, - void *pCallbackCtx, - QCBORItemCallback pfCB) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, + QCBORItem *pItemList, + void *pCallbackCtx, + QCBORItemCallback pfCB) { - QCBORError uErr = MapSearch(pMe, pItemList, NULL, pCallbackCtx, pfCB); + MapSearchCallBack CallBack; + CallBack.pCBContext = pCallbackCtx; + CallBack.pfCallback = pfCB; + + QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack); + pMe->uLastError = (uint8_t)uErr; } @@ -3483,7 +3996,8 @@ void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, * If the label is not found, or the item found is not a map or array, * the error state is set. */ -static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) +static void +QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) { // The first item in pSearch is the one that is to be // entered. It should be the only one filled in. Any other @@ -3492,8 +4006,8 @@ static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) return; } - size_t uOffset; - pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL); + MapSearchInfo Info; + pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL); if(pMe->uLastError != QCBOR_SUCCESS) { return; } @@ -3523,20 +4037,21 @@ static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) * to be used to get one item and MapSearch() has already found it * confirming it exists. */ - UsefulInputBuf_Seek(&(pMe->InBuf), uOffset); + UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset); DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); - QCBORDecode_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL); + QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) { QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; @@ -3545,28 +4060,35 @@ void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; /* The map to enter was found, now finish off entering it. */ - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); OneItemSeach[0].uDataType = QCBOR_TYPE_MAP; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); +#else + (void)szLabel; + pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) { QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; @@ -3574,26 +4096,45 @@ void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); +#else + (void)szLabel; + pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ } -// Semi-private function -void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, QCBORItem *pItem) +/** + * @brief Semi-private to do the the work for EnterMap() and EnterArray(). + * + * @param[in] pMe The decode context + * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY. + * @param[out] pItem The data item for the map or array entered. + * + * The next item in the traversal must be a map or array. This + * consumes that item and does the book keeping to enter the map or + * array. + */ +void +QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, + const uint8_t uType, + QCBORItem *pItem) { QCBORError uErr; @@ -3609,12 +4150,21 @@ void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, if(uErr != QCBOR_SUCCESS) { goto Done; } - if(Item.uDataType != uType) { + + uint8_t uItemDataType = Item.uDataType; + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { uErr = QCBOR_ERR_UNEXPECTED_TYPE; goto Done; } - CopyTags(pMe, &Item); + QCBORDecode_Private_CopyTags(pMe, &Item); const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel); @@ -3643,52 +4193,60 @@ void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, } -/* - This is the common work for exiting a level that is a bounded map, - array or bstr wrapped CBOR. - - One chunk of work is to set up the pre-order traversal so it is at - the item just after the bounded map, array or bstr that is being - exited. This is somewhat complex. - - The other work is to level-up the bounded mode to next higest bounded - mode or the top level if there isn't one. +/** + * @brief Exit a bounded map, array or bstr (semi-private). + * + * @param[in] pMe Decode context. + * @param[in] uEndOffset The input buffer offset of the end of item exited. + * + * @returns QCBOR_SUCCESS or an error code. + * + * This is the common work for exiting a level that is a bounded map, + * array or bstr wrapped CBOR. + * + * One chunk of work is to set up the pre-order traversal so it is at + * the item just after the bounded map, array or bstr that is being + * exited. This is somewhat complex. + * + * The other work is to level-up the bounded mode to next higest + * bounded mode or the top level if there isn't one. */ static QCBORError -ExitBoundedLevel(QCBORDecodeContext *pMe, uint32_t uEndOffset) +QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe, + const uint32_t uEndOffset) { QCBORError uErr; /* - First the pre-order-traversal byte offset is positioned to the - item just after the bounded mode item that was just consumed. + * First the pre-order-traversal byte offset is positioned to the + * item just after the bounded mode item that was just consumed. */ UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset); /* - Next, set the current nesting level to one above the bounded level - that was just exited. - - DecodeNesting_CheckBoundedType() is always called before this and - makes sure pCurrentBounded is valid. + * Next, set the current nesting level to one above the bounded + * level that was just exited. + * + * DecodeNesting_CheckBoundedType() is always called before this + * and makes sure pCurrentBounded is valid. */ DecodeNesting_LevelUpCurrent(&(pMe->nesting)); /* - This does the complex work of leveling up the pre-order traversal - when the end of a map or array or another bounded level is - reached. It may do nothing, or ascend all the way to the top - level. + * This does the complex work of leveling up the pre-order + * traversal when the end of a map or array or another bounded + * level is reached. It may do nothing, or ascend all the way to + * the top level. */ - uErr = QCBORDecode_NestLevelAscender(pMe, false); + uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false); if(uErr != QCBOR_SUCCESS) { goto Done; } /* - This makes the next highest bounded level the current bounded - level. If there is no next highest level, then no bounded mode is - in effect. + * This makes the next highest bounded level the current bounded + * level. If there is no next highest level, then no bounded mode + * is in effect. */ DecodeNesting_LevelUpBounded(&(pMe->nesting)); @@ -3699,8 +4257,19 @@ ExitBoundedLevel(QCBORDecodeContext *pMe, uint32_t uEndOffset) } -// Semi-private function -void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType) +/** + * @brief Get started exiting a map or array (semi-private) + * + * @param[in] pMe The decode context + * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP + * + * This does some work for map and array exiting (but not + * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel() + * is called to do the rest. + */ +void +QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, + const uint8_t uType) { if(pMe->uLastError != QCBOR_SUCCESS) { /* Already in error state; do nothing. */ @@ -3722,25 +4291,38 @@ void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType) if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) { QCBORItem Dummy; Dummy.uLabelType = QCBOR_TYPE_NONE; - uErr = MapSearch(pMe, &Dummy, NULL, NULL, NULL); + uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL); if(uErr != QCBOR_SUCCESS) { goto Done; } } - uErr = ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache); + uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache); Done: pMe->uLastError = (uint8_t)uErr; } - +/** + * @brief The main work of entering some byte-string wrapped CBOR. + * + * @param[in] pMe The decode context. + * @param[in] pItem The byte string item. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX + * @param[out] pBstr Pointer and length of byte string entered. + * + * This is called once the byte string item has been decoded to do all + * the book keeping work for descending a nesting level into the + * nested CBOR. + * + * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement. + */ static QCBORError -InternalEnterBstrWrapped(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) +QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { if(pBstr) { *pBstr = NULLUsefulBufC; @@ -3753,14 +4335,14 @@ InternalEnterBstrWrapped(QCBORDecodeContext *pMe, QCBORError uError; - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - uError = CheckTagRequirement(TagSpec, pItem); + uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uError != QCBOR_SUCCESS) { goto Done; } @@ -3817,11 +4399,12 @@ InternalEnterBstrWrapped(QCBORDecodeContext *pMe, /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pBstr) +void +QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { if(pMe->uLastError != QCBOR_SUCCESS) { // Already in error state; do nothing. @@ -3835,53 +4418,61 @@ void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); + if(Item.uDataAlloc) { + pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING; + return; + } + + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + pBstr); } /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr) +void +QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + pBstr); } /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr) +void +QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + pBstr); } /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) +void +QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) { if(pMe->uLastError != QCBOR_SUCCESS) { // Already in error state; do nothing. @@ -3903,15 +4494,26 @@ void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting))); - QCBORError uErr = ExitBoundedLevel(pMe, uEndOfBstr); + QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr); pMe->uLastError = (uint8_t)uErr; } - -static inline void -ProcessBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool) +/** + * @brief Process simple type true and false, a boolean + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with either true or false. + * @param[out] pBool The boolean value output. + * + * Sets the internal error if the item isn't a true or a false. Also + * records any tag numbers as the tag numbers of the last item. + */ +static void +QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + bool *pBool) { if(pMe->uLastError != QCBOR_SUCCESS) { /* Already in error state, do nothing */ @@ -3931,58 +4533,154 @@ ProcessBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool) pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; break; } - CopyTags(pMe, pItem); } /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue) +void +QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue) +{ + QCBORItem Item; + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); +} + + +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + bool *pValue) +{ + QCBORItem Item; + QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); + QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); +} + + +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + bool *pValue) +{ + QCBORItem Item; + QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); + QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); +} + + +/** + * @brief Process simple values. + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with the simple value. + * @param[out] puSimple The simple value output. + * + * Sets the internal error if the item isn't a true or a false. Also + * records any tag numbers as the tag numbers of the last item. + */ +static void +QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint8_t *puSimple) { if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ return; } - QCBORItem Item; + /* It's kind of lame to remap true...undef back to simple values, but + * this function isn't used much and to not do it would require + * changing GetNext() behavior in an incompatible way. + */ + switch(pItem->uDataType) { + case QCBOR_TYPE_UKNOWN_SIMPLE: + *puSimple = pItem->val.uSimple; + break; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); + case QCBOR_TYPE_TRUE: + *puSimple = CBOR_SIMPLEV_TRUE; + break; + + case QCBOR_TYPE_FALSE: + *puSimple = CBOR_SIMPLEV_FALSE; + break; - ProcessBool(pMe, &Item, pValue); + case QCBOR_TYPE_NULL: + *puSimple = CBOR_SIMPLEV_NULL; + break; + + case QCBOR_TYPE_UNDEF: + *puSimple = CBOR_SIMPLEV_UNDEF; + break; + + default: + pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; + return; + } } +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple) +{ + QCBORItem Item; + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple); +} /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue) +void +QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint8_t *puSimpleValue) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - ProcessBool(pMe, &Item, pValue); + QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue); } - /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue) +void +QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t *puSimpleValue) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - ProcessBool(pMe, &Item, pValue); + QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue); } - -static void ProcessEpochDate(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - int64_t *pnTime) +/** + * @brief Common processing for an epoch date. + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with the date. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnTime The returned date. + * + * Common processing for the date tag. Mostly make sure the tag + * content is correct and copy forward any further other tag numbers. + */ +static void +QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe, + QCBORItem *pItem, + const uint8_t uTagRequirement, + int64_t *pnTime) { if(pMe->uLastError != QCBOR_SUCCESS) { // Already in error state, do nothing @@ -3991,29 +4689,25 @@ static void ProcessEpochDate(QCBORDecodeContext *pMe, QCBORError uErr; - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64} }; - uErr = CheckTagRequirement(TagSpec, pItem); + uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) { - uErr = DecodeDateEpoch(pItem); + uErr = QCBOR_Private_DecodeDateEpoch(pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } } - // Save the tags in the last item's tags in the decode context - // for QCBORDecode_GetNthTagOfLast() - CopyTags(pMe, pItem); - *pnTime = pItem->val.epochDate.nSeconds; Done: @@ -4021,22 +4715,24 @@ static void ProcessEpochDate(QCBORDecodeContext *pMe, } -void QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing - return; - } +/* + * Public function, see header qcbor/qcbor_spiffy_decode.h file + */ +void +QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + int64_t *pnTime) +{ QCBORItem Item; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); - - ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); } +/* + * Public function, see header qcbor/qcbor_spiffy_decode.h file + */ void QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, int64_t nLabel, @@ -4045,10 +4741,13 @@ QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); + QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); } +/* + * Public function, see header qcbor/qcbor_spiffy_decode.h file + */ void QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, @@ -4057,20 +4756,28 @@ QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); + QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); } -/* - * Common processing for the RFC 8943 day-count tag. Mostly - * make sure the tag content is correct and copy forward any - * further other tag numbers. +/** + * @brief Common processing for an epoch date. + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with the date. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnDays The returned day count. + * + * Common processing for the RFC 8943 day-count tag. Mostly make sure + * the tag content is correct and copy forward any further other tag + * numbers. */ -static void ProcessEpochDays(QCBORDecodeContext *pMe, - QCBORItem *pItem, - uint8_t uTagRequirement, - int64_t *pnDays) +static void +QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe, + QCBORItem *pItem, + uint8_t uTagRequirement, + int64_t *pnDays) { if(pMe->uLastError != QCBOR_SUCCESS) { /* Already in error state, do nothing */ @@ -4079,30 +4786,25 @@ static void ProcessEpochDays(QCBORDecodeContext *pMe, QCBORError uErr; - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - uErr = CheckTagRequirement(TagSpec, pItem); + uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) { - uErr = DecodeDaysEpoch(pItem); + uErr = QCBOR_Private_DecodeDaysEpoch(pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } } - /* Save the tags in the last item's tags in the decode context - * for QCBORDecode_GetNthTagOfLast() - */ - CopyTags(pMe, pItem); - *pnDays = pItem->val.epochDays; Done: @@ -4113,19 +4815,14 @@ static void ProcessEpochDays(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h */ -void QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnDays) +void +QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + int64_t *pnDays) { - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - QCBORItem Item; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); - - ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); } @@ -4140,7 +4837,7 @@ QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); + QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); } @@ -4155,7 +4852,7 @@ QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); + QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); } @@ -4164,25 +4861,18 @@ QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, * @brief Get a string that matches the type/tag specification. */ void -QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, - const TagSpecification TagSpec, - UsefulBufC *pBstr) +QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pBstr) { - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - - QCBORError uError; QCBORItem Item; - uError = QCBORDecode_GetNext(pMe, &Item); - if(uError != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uError; + QCBORDecode_VGetNext(pMe, &Item); + if(pMe->uLastError) { return; } - pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, &Item); + pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { *pBstr = Item.val.string; @@ -4194,20 +4884,32 @@ QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, +/** + * @brief Common processing for a big number tag. + * + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] pItem The item with the date. + * @param[out] pValue The returned big number + * @param[out] pbIsNegative The returned sign of the big number. + * + * Common processing for the big number tag. Mostly make sure + * the tag content is correct and copy forward any further other tag + * numbers. + */ static QCBORError -ProcessBigNum(const uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pValue, - bool *pbIsNegative) +QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement, + const QCBORItem *pItem, + UsefulBufC *pValue, + bool *pbIsNegative) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORError uErr = CheckTagRequirement(TagSpec, pItem); + QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { return uErr; } @@ -4225,37 +4927,36 @@ ProcessBigNum(const uint8_t uTagRequirement, /* - Public function, see header qcbor/qcbor_decode.h + * Public function, see header qcbor/qcbor_spiffy_decode.h */ -void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) +void +QCBORDecode_GetBignum(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative) { - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uError; + QCBORDecode_VGetNext(pMe, &Item); + if(pMe->uLastError) { return; } - pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative); + pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, + &Item, + pValue, + pbIsNegative); } /* - Public function, see header qcbor/qcbor_decode.h -*/ -void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) + * Public function, see header qcbor/qcbor_spiffy_decode.h + */ +void +QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); @@ -4263,18 +4964,22 @@ void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative); + pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, + &Item, + pValue, + pbIsNegative); } /* - Public function, see header qcbor/qcbor_decode.h -*/ -void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) + * Public function, see header qcbor/qcbor_spiffy_decode.h + */ +void +QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); @@ -4282,26 +4987,39 @@ void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative); + pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, + &Item, + pValue, + pbIsNegative); } - -// Semi private +/** + * @brief Common processing for MIME tag (semi-private). + * + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] pItem The item with the date. + * @param[out] pMessage The returned MIME message. + * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME. + * + * Common processing for the MIME tag. Mostly make sure the tag + * content is correct and copy forward any further other tag + * numbers. See QCBORDecode_GetMIMEMessage(). + */ QCBORError -QCBORDecode_GetMIMEInternal(const uint8_t uTagRequirement, +QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsTag257) { - const TagSpecification TagSpecText = + const QCBOR_Private_TagSpec TagSpecText = { uTagRequirement, {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - const TagSpecification TagSpecBinary = + const QCBOR_Private_TagSpec TagSpecBinary = { uTagRequirement, {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, @@ -4310,13 +5028,13 @@ QCBORDecode_GetMIMEInternal(const uint8_t uTagRequirement, QCBORError uReturn; - if(CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) { + if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) { *pMessage = pItem->val.string; if(pbIsTag257 != NULL) { *pbIsTag257 = false; } uReturn = QCBOR_SUCCESS; - } else if(CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) { + } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) { *pMessage = pItem->val.string; if(pbIsTag257 != NULL) { *pbIsTag257 = true; @@ -4338,6 +5056,16 @@ QCBORDecode_GetMIMEInternal(const uint8_t uTagRequirement, #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA +/** + * @brief Prototype for conversion of exponent and mantissa to unsigned integer. + * + * @param[in] uMantissa The mantissa. + * @param[in] nExponent The exponent. + * @param[out] puResult The resulting integer. + * + * Concrete implementations of this are for exponent base 10 and 2 supporting + * decimal fractions and big floats. + */ typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult); @@ -4352,11 +5080,13 @@ typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint * unsigned integer. * * There are many inputs for which the result will not fit in the - * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will + * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will * be returned. */ static QCBORError -Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) +QCBOR_Private_Exponentitate10(const uint64_t uMantissa, + int64_t nExponent, + uint64_t *puResult) { uint64_t uResult = uMantissa; @@ -4398,11 +5128,13 @@ Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) * output is a 64-bit unsigned integer. * * There are many inputs for which the result will not fit in the - * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will + * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will * be returned. */ static QCBORError -Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) +QCBOR_Private_Exponentitate2(const uint64_t uMantissa, + int64_t nExponent, + uint64_t *puResult) { uint64_t uResult; @@ -4443,16 +5175,16 @@ Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) * * @returns Error code * - * \c pfExp performs exponentiation on and unsigned mantissa and + * @c pfExp performs exponentiation on and unsigned mantissa and * produces an unsigned result. This converts the mantissa from signed * and converts the result to signed. The exponentiation function is * either for base 2 or base 10 (and could be other if needed). */ static QCBORError -ExponentiateNN(int64_t nMantissa, - int64_t nExponent, - int64_t *pnResult, - fExponentiator pfExp) +QCBOR_Private_ExponentiateNN(const int64_t nMantissa, + const int64_t nExponent, + int64_t *pnResult, + fExponentiator pfExp) { uint64_t uResult; uint64_t uMantissa; @@ -4531,15 +5263,15 @@ ExponentiateNN(int64_t nMantissa, * * @returns Error code * - * \c pfExp performs exponentiation on and unsigned mantissa and + * @c pfExp performs exponentiation on and unsigned mantissa and * produces an unsigned result. This errors out if the mantissa * is negative because the output is unsigned. */ static QCBORError -ExponentitateNU(int64_t nMantissa, - int64_t nExponent, - uint64_t *puResult, - fExponentiator pfExp) +QCBOR_Private_ExponentitateNU(const int64_t nMantissa, + const int64_t nExponent, + uint64_t *puResult, + fExponentiator pfExp) { if(nMantissa < 0) { return QCBOR_ERR_NUMBER_SIGN_CONVERSION; @@ -4563,15 +5295,15 @@ ExponentitateNU(int64_t nMantissa, * * @returns Error code * - * \c pfExp performs exponentiation on and unsigned mantissa and + * @c pfExp performs exponentiation on and unsigned mantissa and * produces an unsigned result so this is just a wrapper that does * nothing (and is likely inlined). */ static QCBORError -ExponentitateUU(uint64_t uMantissa, - int64_t nExponent, - uint64_t *puResult, - fExponentiator pfExp) +QCBOR_Private_ExponentitateUU(const uint64_t uMantissa, + const int64_t nExponent, + uint64_t *puResult, + fExponentiator pfExp) { return (*pfExp)(uMantissa, nExponent, puResult); } @@ -4594,7 +5326,9 @@ ExponentitateUU(uint64_t uMantissa, * larger range than uint64_t. */ static QCBORError -ConvertBigNumToUnsigned(const UsefulBufC BigNum, const uint64_t uMax, uint64_t *pResult) +QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum, + const uint64_t uMax, + uint64_t *pResult) { uint64_t uResult; @@ -4625,9 +5359,10 @@ ConvertBigNumToUnsigned(const UsefulBufC BigNum, const uint64_t uMax, uint64_t * * larger range than uint64_t. */ static QCBORError -ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult) +QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, + uint64_t *pResult) { - return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult); + return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult); } @@ -4643,14 +5378,17 @@ ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult) * larger range than int64_t. */ static QCBORError -ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult) +QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, + int64_t *pResult) { uint64_t uResult; - QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult); + QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, + INT64_MAX, + &uResult); if(uError) { return uError; } - /* Cast is safe because ConvertBigNumToUnsigned is told to limit to INT64_MAX */ + /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */ *pResult = (int64_t)uResult; return QCBOR_SUCCESS; } @@ -4668,7 +5406,8 @@ ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult) * larger range than int64_t. */ static QCBORError -ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult) +QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, + int64_t *pnResult) { uint64_t uResult; /* The negative integer furthest from zero for a C int64_t is @@ -4683,7 +5422,9 @@ ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult) * -n - 1 <= -INT64_MAX - 1 * n <= INT64_MAX. */ - QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult); + QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, + INT64_MAX, + &uResult); if(uError != QCBOR_SUCCESS) { return uError; } @@ -4700,22 +5441,23 @@ ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult) - -/* -Convert integers and floats to an int64_t. - -\param[in] uConvertTypes Bit mask list of conversion options. - -\retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - in uConvertTypes. - -\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - -\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - or too small. -*/ +/** + * @brief Convert integers and floats to an int64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ static QCBORError -ConvertInt64(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue) +QCBOR_Private_ConvertInt64(const QCBORItem *pItem, + const uint32_t uConvertTypes, + int64_t *pnValue) { switch(pItem->uDataType) { case QCBOR_TYPE_FLOAT: @@ -4774,81 +5516,112 @@ ConvertInt64(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue) } -void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to int64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetInt64Convert(). + */ +void +QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { + QCBORDecode_VGetNext(pMe, pItem); + if(pMe->uLastError) { return; } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } - - if(pItem) { - *pItem = Item; - } - - pMe->uLastError = (uint8_t)ConvertInt64(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, + uConvertTypes, + pnValue); } - -void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to int64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetInt64ConvertInMapN(). + */ +void +QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertInt64(pItem, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, + uConvertTypes, + pnValue); } - -void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to int64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetInt64ConvertInMapSZ(). + */ +void +QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe, + const char * szLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertInt64(pItem, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, + uConvertTypes, + pnValue); } -/* - Convert a large variety of integer types to an int64_t. - - \param[in] uConvertTypes Bit mask list of conversion options. - - \retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - in uConvertTypes. - - \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - - \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - or too small. +/** + * @brief Convert many number types to an int64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. */ static QCBORError -Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue) +QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem, + const uint32_t uConvertTypes, + int64_t *pnValue) { switch(pItem->uDataType) { case QCBOR_TYPE_POSBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue); + return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4856,7 +5629,7 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue case QCBOR_TYPE_NEGBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue); + return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4865,10 +5638,10 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA case QCBOR_TYPE_DECIMAL_FRACTION: if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, pnValue, - &Exponentitate10); + &QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4876,10 +5649,10 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue case QCBOR_TYPE_BIGFLOAT: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4889,14 +5662,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate10); + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4906,14 +5679,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate10); + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4923,14 +5696,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4940,14 +5713,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4961,13 +5734,16 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTypes, int64_t *pnValue) +void +QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternal(pMe, uConvertTypes, pnValue, &Item); + QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -4979,21 +5755,24 @@ void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTy return; } - pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, + uConvertTypes, + pnValue); } /* -Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetInt64ConvertInMapN(pMe, nLabel, uConvertTypes, pnValue, @@ -5009,20 +5788,23 @@ void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, + uConvertTypes, + pnValue); } /* -Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, pnValue, @@ -5038,11 +5820,29 @@ void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, + uConvertTypes, + pnValue); } -static QCBORError ConvertUInt64(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puValue) +/** + * @brief Convert many number types to an uint64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ +static QCBORError +QCBOR_Private_ConvertUInt64(const QCBORItem *pItem, + const uint32_t uConvertTypes, + uint64_t *puValue) { switch(pItem->uDataType) { case QCBOR_TYPE_DOUBLE: @@ -5126,74 +5926,114 @@ static QCBORError ConvertUInt64(const QCBORItem *pItem, uint32_t uConvertTypes, } -void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetUInt64Convert(). + */ +void +QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { + QCBORDecode_VGetNext(pMe, pItem); + if(pMe->uLastError) { return; } - QCBORItem Item; - - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } - - if(pItem) { - *pItem = Item; - } - - pMe->uLastError = (uint8_t)ConvertUInt64(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, + uConvertTypes, + puValue); } -void QCBORDecode_GetUInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetUInt64ConvertInMapN(). + */ +void +QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertUInt64(pItem, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, + uConvertTypes, + puValue); } -void QCBORDecode_GetUInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetUInt64ConvertInMapSZ(). + */ +void +QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertUInt64(pItem, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, + uConvertTypes, + puValue); } - +/** + * @brief Convert many number types to an unt64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ static QCBORError -UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puValue) +QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem, + const uint32_t uConvertTypes, + uint64_t *puValue) { - switch(pItem->uDataType) { + switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */ case QCBOR_TYPE_POSBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue); + return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5211,10 +6051,10 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal case QCBOR_TYPE_DECIMAL_FRACTION: if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, puValue, - Exponentitate10); + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5222,10 +6062,10 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal case QCBOR_TYPE_BIGFLOAT: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, puValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5235,14 +6075,14 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { uint64_t uMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); if(uErr != QCBOR_SUCCESS) { return uErr; } - return ExponentitateUU(uMantissa, - pItem->val.expAndMantissa.nExponent, - puValue, - Exponentitate10); + return QCBOR_Private_ExponentitateUU(uMantissa, + pItem->val.expAndMantissa.nExponent, + puValue, + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5260,14 +6100,15 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { uint64_t uMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, + &uMantissa); if(uErr != QCBOR_SUCCESS) { return uErr; } - return ExponentitateUU(uMantissa, - pItem->val.expAndMantissa.nExponent, - puValue, - Exponentitate2); + return QCBOR_Private_ExponentitateUU(uMantissa, + pItem->val.expAndMantissa.nExponent, + puValue, + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5288,13 +6129,16 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTypes, uint64_t *puValue) +void +QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternal(pMe, uConvertTypes, puValue, &Item); + QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5306,21 +6150,24 @@ void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertT return; } - pMe->uLastError = (uint8_t)UInt64ConvertAll(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, + uConvertTypes, + puValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapN(pMe, nLabel, uConvertTypes, puValue, @@ -5336,20 +6183,23 @@ void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)UInt64ConvertAll(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, + uConvertTypes, + puValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, puValue, @@ -5365,16 +6215,32 @@ void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)UInt64ConvertAll(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, + uConvertTypes, + puValue); } #ifndef USEFULBUF_DISABLE_ALL_FLOAT -static QCBORError ConvertDouble(const QCBORItem *pItem, - uint32_t uConvertTypes, - double *pdValue) +/** + * @brief Basic conversions to a double. + * + * @param[in] pItem The item to convert + * @param[in] uConvertTypes Bit flags indicating source types for conversion + * @param[out] pdValue The value converted to a double + * + * This does the conversions that don't need much object code, + * the conversions from int, uint and float to double. + * + * See QCBOR_Private_DoubleConvertAll() for the full set + * of conversions. + */ +static QCBORError +QCBOR_Private_ConvertDouble(const QCBORItem *pItem, + const uint32_t uConvertTypes, + double *pdValue) { switch(pItem->uDataType) { case QCBOR_TYPE_FLOAT: @@ -5439,67 +6305,106 @@ static QCBORError ConvertDouble(const QCBORItem *pItem, } -void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to double (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] uConvertTypes Bit mask list of conversion options + * @param[out] pdValue The output of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetDoubleConvert(). + */ +void +QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + double *pdValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - QCBORItem Item; - - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; + QCBORDecode_VGetNext(pMe, pItem); + if(pMe->uLastError) { return; } - if(pItem) { - *pItem = Item; - } - - pMe->uLastError = (uint8_t)ConvertDouble(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, + uConvertTypes, + pdValue); } -void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to double (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options + * @param[out] pdValue The output of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetDoubleConvertInMapN(). + */ +void +QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + double *pdValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertDouble(pItem, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, + uConvertTypes, + pdValue); } -void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to double (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options + * @param[out] pdValue The output of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetDoubleConvertInMapSZ(). + */ +void +QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + double *pdValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertDouble(pItem, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, + uConvertTypes, + pdValue); } #ifndef QCBOR_DISABLE_FLOAT_HW_USE -static double ConvertBigNumToDouble(const UsefulBufC BigNum) +/** + * @brief Convert a big number to double-precision float. + * + * @param[in] BigNum The big number to convert + * + * @returns The double value. + * + * This will always succeed. It will lose precision for larger + * numbers. If the big number is too large to fit (more than + * 1.7976931348623157E+308) infinity will be returned. NaN is never + * returned. + */ +static double +QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum) { double dResult; @@ -5507,7 +6412,7 @@ static double ConvertBigNumToDouble(const UsefulBufC BigNum) const uint8_t *pByte = BigNum.ptr; size_t uLen = BigNum.len; /* This will overflow and become the float value INFINITY if the number - is too large to fit. */ + * is too large to fit. */ while(uLen--) { dResult = (dResult * 256.0) + (double)*pByte++; } @@ -5517,8 +6422,25 @@ static double ConvertBigNumToDouble(const UsefulBufC BigNum) #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ + + +/** + * @brief Convert many number types to a double. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pdValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ static QCBORError -DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue) +QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem, + const uint32_t uConvertTypes, + double *pdValue) { #ifndef QCBOR_DISABLE_FLOAT_HW_USE /* @@ -5547,11 +6469,11 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue return QCBOR_ERR_UNEXPECTED_TYPE; } break; -#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ case QCBOR_TYPE_POSBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - *pdValue = ConvertBigNumToDouble(pItem->val.bigNum); + *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5559,7 +6481,7 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue case QCBOR_TYPE_NEGBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum); + *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5568,7 +6490,7 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; @@ -5576,32 +6498,33 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue break; case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); + if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { + /* Must subtract 1 for CBOR negative integer offset */ + double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } break; case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); + if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { + double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } break; case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); + if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { + double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } break; -#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ default: return QCBOR_ERR_UNEXPECTED_TYPE; @@ -5620,16 +6543,17 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - double *pdValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternal(pMe, uConvertTypes, pdValue, &Item); + QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5641,21 +6565,28 @@ void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, + uConvertTypes, + pdValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uConvertTypes, pdValue, &Item); + QCBORDecode_Private_GetDoubleConvertInMapN(pMe, + nLabel, + uConvertTypes, + pdValue, + &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5667,20 +6598,27 @@ void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, + uConvertTypes, + pdValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uConvertTypes, pdValue, &Item); + QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe, + szLabel, + uConvertTypes, + pdValue, + &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5692,7 +6630,9 @@ void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, + uConvertTypes, + pdValue); } #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ @@ -5700,7 +6640,18 @@ void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer) +/** + * @brief Convert an integer to a big number + * + * @param[in] uInt The integer to convert. + * @param[in] Buffer The buffer to output the big number to. + * + * @returns The big number or NULLUsefulBufC is the buffer is to small. + * + * This always succeeds unless the buffer is too small. + */ +static UsefulBufC +QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer) { while((uInt & 0xff00000000000000UL) == 0) { uInt = uInt << 8; @@ -5711,10 +6662,8 @@ static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer) UsefulOutBuf_Init(&UOB, Buffer); while(uInt) { - const uint64_t xx = uInt & 0xff00000000000000UL; UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56)); uInt = uInt << 8; - (void)xx; } return UsefulOutBuf_OutUBuf(&UOB); @@ -5722,48 +6671,50 @@ static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer) /** - * @brief Check and/or complete mantissa and exponent item. + * @brief Check and/or complete exponent and mantissa item. * - * @param[in] pMe The decoder context - * @param[in] TagSpec Expected type(s) - * @param[in,out] pItem See below + * @param[in] pMe The decoder context. + * @param[in] TagSpec Expected type(s). + * @param[in,out] pItem See below. * - * This is for decimal fractions and big floats, both of which are a - * mantissa and exponent. + * This is for decimal fractions and big floats, both of which are an + * exponent and mantissa. * - * The input item is either a fully decoded decimal faction or big - * float, or a just the decoded first item of a decimal fraction or - * big float. + * If the item item had a tag number indicating it was a + * decimal fraction or big float, then the input @c pItem will + * have been decoded as exponent and mantissa. If there was + * no tag number, the caller is asking this be decoded as a + * big float or decimal fraction and @c pItem just has the + * first item in an exponent and mantissa. * * On output, the item is always a fully decoded decimal fraction or * big float. * * This errors out if the input type does not meet the TagSpec. */ -// TODO: document and see tests for the bug that was fixed by this rewrite static QCBORError -MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe, - const TagSpecification TagSpec, - QCBORItem *pItem) +QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem) { QCBORError uErr; - /* pItem could either be an auto-decoded mantissa and exponent or - * the opening array of an undecoded mantissa and exponent. This + /* pItem could either be a decoded exponent and mantissa or + * the opening array of an undecoded exponent and mantissa. This * check will succeed on either, but doesn't say which it was. */ - uErr = CheckTagRequirement(TagSpec, pItem); + uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } if(pItem->uDataType == QCBOR_TYPE_ARRAY) { - /* The item is an array, which means is is an undecoded mantissa - * and exponent. This call consumes the items in the array and - * results in a decoded mantissa and exponent in pItem. This is + /* The item is an array, which means is is an undecoded exponent + * and mantissa. This call consumes the items in the array and + * results in a decoded exponent and mantissa in pItem. This is * the case where there was no tag. */ - uErr = QCBORDecode_MantissaAndExponent(pMe, pItem); + uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } @@ -5772,10 +6723,10 @@ MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe, * fraction or big num. Which of these two depends on what the * caller wants it decoded as since there is no tag, so fish the * type out of the TagSpec. */ - pItem->uDataType = MantissaExponentDataType(TagSpec.uTaggedTypes[0], pItem); + pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem); /* No need to check the type again. All that we need to know was - * that it decoded correctly as a mantissa and exponent. The + * that it decoded correctly as a exponent and mantissa. The * QCBOR type is set out by what was requested. */ } @@ -5820,15 +6771,34 @@ MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe, * first tier part of the public API. Some functions only * vary by a TagSpec. */ -static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe, - TagSpecification TagSpec, - QCBORItem *pItem, - int64_t *pnMantissa, - int64_t *pnExponent) + +/** + * @brief Common processor for exponent and mantissa. + * + * @param[in] pMe The decode context. + * @param[in] TagSpec The expected/allowed tags. + * @param[in] pItem The data item to process. + * @param[out] pnMantissa The returned mantissa as an int64_t. + * @param[out] pnExponent The returned exponent as an int64_t. + * + * This handles exponent and mantissa for base 2 and 10. This + * is limited to a mantissa that is an int64_t. See also + * QCBORDecode_Private_ProcessExpMantissaBig(). + */ +static void +QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem, + int64_t *pnMantissa, + int64_t *pnExponent) { QCBORError uErr; - uErr = MantissaAndExponentTypeHandler(pMe, TagSpec, pItem); + if(pMe->uLastError) { + return; + } + + uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } @@ -5846,13 +6816,13 @@ static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe, case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: *pnExponent = pItem->val.expAndMantissa.nExponent; - uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); break; case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: *pnExponent = pItem->val.expAndMantissa.nExponent; - uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); + uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); break; #endif /* QCBOR_DISABLE_TAGS */ @@ -5865,39 +6835,65 @@ static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe, } -static void ProcessMantissaAndExponentBig(QCBORDecodeContext *pMe, - TagSpecification TagSpec, - QCBORItem *pItem, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) +/** + * @brief Decode exponent and mantissa into a big number. + * + * @param[in] pMe The decode context. + * @param[in] TagSpec The expected/allowed tags. + * @param[in] pItem Item to decode and convert. + * @param[in] BufferForMantissa Buffer to output mantissa into. + * @param[out] pMantissa The output mantissa. + * @param[out] pbIsNegative The sign of the output. + * @param[out] pnExponent The mantissa of the output. + * + * This is the common processing of a decimal fraction or a big float + * into a big number. This will decode and consume all the CBOR items + * that make up the decimal fraction or big float. + */ +static void +QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { QCBORError uErr; + uint64_t uMantissa; + + if(pMe->uLastError != QCBOR_SUCCESS) { + return; + } - uErr = MantissaAndExponentTypeHandler(pMe, TagSpec, pItem); + uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } - uint64_t uMantissa; - switch (pItem->uDataType) { case QCBOR_TYPE_DECIMAL_FRACTION: case QCBOR_TYPE_BIGFLOAT: - /* See comments in ExponentiateNN() on handling INT64_MIN */ if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) { uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt; *pbIsNegative = false; - } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) { - uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt; - *pbIsNegative = true; } else { - uMantissa = (uint64_t)INT64_MAX+1; + if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) { + uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt; + } else { + /* Can't negate like above when int64_t is INT64_MIN because it + * will overflow. See ExponentNN() */ + uMantissa = (uint64_t)INT64_MAX+1; + } *pbIsNegative = true; } - *pMantissa = ConvertIntToBigNum(uMantissa, BufferForMantissa); + /* Reverse the offset by 1 for type 1 negative value to be consistent + * with big num case below which don't offset because it requires + * big number arithmetic. This is a bug fix for QCBOR v1.5. + */ + uMantissa--; + *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa, BufferForMantissa); *pnExponent = pItem->val.expAndMantissa.nExponent; break; @@ -5928,25 +6924,18 @@ static void ProcessMantissaAndExponentBig(QCBORDecodeContext *pMe, /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } + QCBORDecode_VGetNext(pMe, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -5954,27 +6943,28 @@ void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -5982,27 +6972,28 @@ void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6010,32 +7001,29 @@ void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } + QCBORDecode_VGetNext(pMe, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6043,38 +7031,33 @@ void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - MantissaBuffer, - pMantissa, - pbMantissaIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + MantissaBuffer, + pMantissa, + pbMantissaIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6082,38 +7065,32 @@ void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6121,29 +7098,29 @@ void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, BufferForMantissa, pMantissa, pbIsNegative, pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } - const TagSpecification TagSpec = + QCBORDecode_VGetNext(pMe, &Item); + + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6151,30 +7128,28 @@ void QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6182,30 +7157,28 @@ void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6213,32 +7186,29 @@ void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } + QCBORDecode_VGetNext(pMe, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6246,32 +7216,32 @@ void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + MantissaBuffer, + pMantissa, + pbMantissaIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6279,38 +7249,32 @@ void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6318,13 +7282,13 @@ void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ diff --git a/3rdparty/exported/QCBOR/src/qcbor_encode.c b/3rdparty/exported/QCBOR/src/qcbor_encode.c index 53df657cfbb7..c30cbce11691 100644 --- a/3rdparty/exported/QCBOR/src/qcbor_encode.c +++ b/3rdparty/exported/QCBOR/src/qcbor_encode.c @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - =============================================================================*/ +/* =========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #include "qcbor/qcbor_encode.h" @@ -72,7 +72,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * with the type CBOR_MAJOR_TYPE_BYTE_STRING and is tracked here. Byte * string wrapped CBOR is used by COSE for data that is to be hashed. */ -static inline void +static void Nesting_Init(QCBORTrackNesting *pNesting) { /* Assumes pNesting has been zeroed. */ @@ -83,10 +83,10 @@ Nesting_Init(QCBORTrackNesting *pNesting) pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY; } -static inline uint8_t +static uint8_t Nesting_Increase(QCBORTrackNesting *pNesting, - uint8_t uMajorType, - uint32_t uPos) + const uint8_t uMajorType, + const uint32_t uPos) { if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) { return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; @@ -99,7 +99,7 @@ Nesting_Increase(QCBORTrackNesting *pNesting, } } -static inline void +static void Nesting_Decrease(QCBORTrackNesting *pNesting) { if(pNesting->pCurrentNesting > &pNesting->pArrays[0]) { @@ -107,21 +107,21 @@ Nesting_Decrease(QCBORTrackNesting *pNesting) } } -static inline uint8_t +static uint8_t Nesting_Increment(QCBORTrackNesting *pNesting) { #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) { + if(pNesting->pCurrentNesting->uCount >= QCBOR_MAX_ITEMS_IN_ARRAY) { return QCBOR_ERR_ARRAY_TOO_LONG; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ pNesting->pCurrentNesting->uCount++; return QCBOR_SUCCESS; } -static inline void +static void Nesting_Decrement(QCBORTrackNesting *pNesting) { /* No error check for going below 0 here needed because this @@ -130,7 +130,7 @@ Nesting_Decrement(QCBORTrackNesting *pNesting) pNesting->pCurrentNesting->uCount--; } -static inline uint16_t +static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting) { /* The nesting count recorded is always the actual number of @@ -148,25 +148,25 @@ Nesting_GetCount(QCBORTrackNesting *pNesting) } } -static inline uint32_t +static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting) { return pNesting->pCurrentNesting->uStart; } #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS -static inline uint8_t +static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting) { return pNesting->pCurrentNesting->uMajorType; } -static inline bool +static bool Nesting_IsInNest(QCBORTrackNesting *pNesting) { return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ @@ -223,7 +223,7 @@ Nesting_IsInNest(QCBORTrackNesting *pNesting) * * QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more * than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since - * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,535) it is very unlikely + * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,534) it is very unlikely * to be reached. If it is reached, the count will wrap around to zero * and CBOR that is not well formed will be produced, but there will * be no buffers overrun and new security issues in the code. @@ -249,23 +249,25 @@ Nesting_IsInNest(QCBORTrackNesting *pNesting) /* - Public function for initialization. See qcbor/qcbor_encode.h + * Public function for initialization. See qcbor/qcbor_encode.h */ -void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage) +void +QCBOREncode_Init(QCBOREncodeContext *pMe, UsefulBuf Storage) { - memset(me, 0, sizeof(QCBOREncodeContext)); - UsefulOutBuf_Init(&(me->OutBuf), Storage); - Nesting_Init(&(me->nesting)); + memset(pMe, 0, sizeof(QCBOREncodeContext)); + UsefulOutBuf_Init(&(pMe->OutBuf), Storage); + Nesting_Init(&(pMe->nesting)); } /* * Public function to encode a CBOR head. See qcbor/qcbor_encode.h */ -UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, - uint8_t uMajorType, - uint8_t uMinLen, - uint64_t uArgument) +UsefulBufC +QCBOREncode_EncodeHead(UsefulBuf Buffer, + uint8_t uMajorType, + uint8_t uMinLen, + uint64_t uArgument) { /* * == Description of the CBOR Head == @@ -412,18 +414,19 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, * extra. The one extra is needed for this code to work as it does * a pre-decrement. */ - if(buffer.len < QCBOR_HEAD_BUFFER_SIZE) { + if(Buffer.len < QCBOR_HEAD_BUFFER_SIZE) { return NULLUsefulBufC; } /* Pointer to last valid byte in the buffer */ - uint8_t * const pBufferEnd = &((uint8_t *)buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1]; + uint8_t * const pBufferEnd = &((uint8_t *)Buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1]; /* Point to the last byte and work backwards */ uint8_t *pByte = pBufferEnd; /* The 5 bits in the initial byte that are not the major type */ int nAdditionalInfo; +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) { /* Special case for start & end of indefinite length */ uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER; @@ -436,7 +439,9 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, #endif nAdditionalInfo = CBOR_SIMPLE_BREAK; - } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) { + } else +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) { /* Simple case where argument is < 24 */ nAdditionalInfo = (int)uArgument; @@ -472,7 +477,7 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, /* This expression integer-promotes to type int. The code above in * function guarantees that nAdditionalInfo will never be larger * than 0x1f. The caller may pass in a too-large uMajor type. The - * conversion to unint8_t will cause an integer wrap around and + * conversion to uint8_t will cause an integer wrap around and * incorrect CBOR will be generated, but no security issue will * occur. */ @@ -498,161 +503,77 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, /** - * @brief Append the CBOR head, the major type and argument - * - * @param me Encoder context. - * @param uMajorType Major type to insert. - * @param uArgument The argument (an integer value or a length). - * @param uMinLen The minimum number of bytes for encoding the CBOR argument. - * - * This formats the CBOR "head" and appends it to the output. - */ -static void AppendCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uArgument, uint8_t uMinLen) -{ - /* A stack buffer large enough for a CBOR head */ - UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); - - UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, - uMajorType, - uMinLen, - uArgument); - - /* No check for EncodedHead == NULLUsefulBufC is performed here to - * save object code. It is very clear that pBufferForEncodedHead is - * the correct size. If EncodedHead == NULLUsefulBufC then - * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no - * security hole introduced. - */ - - UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), EncodedHead); -} - - -/** - * @brief Check for errors when decreasing nesting. + * @brief Increment item counter for maps and arrays. * * @param pMe QCBOR encoding context. - * @param uMajorType The major type of the nesting. - * - * Check that there is no previous error, that there is actually some - * nesting and that the major type of the opening of the nesting - * matches the major type of the nesting being closed. * - * This is called when closing maps, arrays, byte string wrapping and - * open/close of byte strings. + * This is mostly a separate function to make code more readable and + * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ -bool -CheckDecreaseNesting(QCBOREncodeContext *pMe, uint8_t uMajorType) +static void +QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe) { #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pMe->uError != QCBOR_SUCCESS) { - return true; - } - - if(!Nesting_IsInNest(&(pMe->nesting))) { - pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES; - return true; - } - - if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) { - pMe->uError = QCBOR_ERR_CLOSE_MISMATCH; - return true; + if(pMe->uError == QCBOR_SUCCESS) { + pMe->uError = Nesting_Increment(&(pMe->nesting)); } - #else - /* None of these checks are performed if the encode guards are - * turned off as they all relate to correct calling. - * - * Turning off all these checks does not turn off any checking for - * buffer overflows or pointer issues. - */ - - (void)uMajorType; - (void)pMe; -#endif - - return false; + (void)Nesting_Increment(&(pMe->nesting)); +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ } /** - * @brief Insert the CBOR head for a map, array or wrapped bstr + * @brief Append the CBOR head, the major type and argument * - * @param me QCBOR encoding context. - * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX. - * @param uLen The length of the data item. + * @param pMe Encoder context. + * @param uMajorType Major type to insert. + * @param uArgument The argument (an integer value or a length). + * @param uMinLen The minimum number of bytes for encoding the CBOR argument. * - * When an array, map or bstr was opened, nothing was done but note - * the position. This function goes back to that position and inserts - * the CBOR Head with the major type and length. + * This formats the CBOR "head" and appends it to the output. + * + * This also increments the array/map item counter in most cases. */ -static void InsertCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, size_t uLen) +void +QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe, + const uint8_t uMajorType, + const uint64_t uArgument, + const uint8_t uMinLen) { - if(CheckDecreaseNesting(me, uMajorType)) { - return; - } - - if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { - uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; - } - - /* A stack buffer large enough for a CBOR head (9 bytes) */ - UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); + /* A stack buffer large enough for a CBOR head */ + UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, - uMajorType, - 0, - uLen); + uMajorType, + uMinLen, + uArgument); /* No check for EncodedHead == NULLUsefulBufC is performed here to * save object code. It is very clear that pBufferForEncodedHead is * the correct size. If EncodedHead == NULLUsefulBufC then - * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no + * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no * security hole introduced. */ - UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), - EncodedHead, - Nesting_GetStartPos(&(me->nesting))); - - Nesting_Decrease(&(me->nesting)); -} + UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead); -/** - * @brief Increment item counter for maps and arrays. - * - * @param pMe QCBOR encoding context. - * - * This is mostly a separate function to make code more readable and - * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - */ -static inline void IncrementMapOrArrayCount(QCBOREncodeContext *pMe) -{ -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pMe->uError == QCBOR_SUCCESS) { - pMe->uError = Nesting_Increment(&(pMe->nesting)); + if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) { + /* Don't increment the map count for tag or break because that is + * not needed. Don't do it for indefinite-length arrays and maps + * because it is done elsewhere. This is never called for definite-length + * arrays and maps. + */ + QCBOREncode_Private_IncrementMapOrArrayCount(pMe); } -#else - (void)Nesting_Increment(&(pMe->nesting)); -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ -} - - -/* - * Public functions for adding unsigned integers. See qcbor/qcbor_encode.h - */ -void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue) -{ - AppendCBORHead(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0); - - IncrementMapOrArrayCount(me); } /* - * Public functions for adding signed integers. See qcbor/qcbor_encode.h + * Public function for adding signed integers. See qcbor/qcbor_encode.h */ -void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum) +void +QCBOREncode_AddInt64(QCBOREncodeContext *pMe, const int64_t nNum) { uint8_t uMajorType; uint64_t uValue; @@ -670,158 +591,119 @@ void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum) uValue = (uint64_t)nNum; uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT; } - AppendCBORHead(me, uMajorType, uValue, 0); - - IncrementMapOrArrayCount(me); + QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0); } -/* - * Semi-private function. It is exposed to user of the interface, but - * one of its inline wrappers will usually be called instead of this. - * - * See qcbor/qcbor_encode.h +/** + * @brief Semi-private method to add a buffer full of bytes to encoded output. * - * This does the work of adding actual strings bytes to the CBOR - * output (as opposed to adding numbers and opening / closing - * aggregate types). - - * There are four use cases: - * CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings - * CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings - * CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR - * CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case + * @param[in] pMe The encoding context to add the string to. + * @param[in] uMajorType The CBOR major type of the bytes. + * @param[in] Bytes The bytes to add. * - * The first two add the head plus the actual bytes. The third just - * adds the bytes as the heas is presumed to be in the bytes. The - * fourth just adds the head for the very special case of - * QCBOREncode_AddBytesLenOnly(). - */ -void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes) -{ - /* If it is not Raw CBOR, add the type and the length */ - if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) { - uint8_t uRealMajorType = uMajorType; - if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) { - uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; - } - AppendCBORHead(me, uRealMajorType, Bytes.len, 0); - } - - if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) { - /* Actually add the bytes */ - UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes); - } - - IncrementMapOrArrayCount(me); -} - - -/* - * Public functions for adding a tag. See qcbor/qcbor_encode.h - */ -void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag) -{ - AppendCBORHead(me, CBOR_MAJOR_TYPE_TAG, uTag, 0); -} - - -/* - * Semi-private function. It is exposed to user of the interface, but - * one of its inline wrappers will usually be called instead of this. + * Called by inline functions to add text and byte strings. * - * See header qcbor/qcbor_encode.h + * (This used to support QCBOREncode_AddEncoded() and + * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this + * smaller. This is one of the most used methods and they are some of + * the least used). */ -void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum) +void +QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe, + const uint8_t uMajorType, + const UsefulBufC Bytes) { -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(me->uError == QCBOR_SUCCESS) { - if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) { - me->uError = QCBOR_ERR_ENCODE_UNSUPPORTED; - return; - } - } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - /* AppendCBORHead() does endian swapping for the float / double */ - AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen); - - IncrementMapOrArrayCount(me); + QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0); + UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes); } -#ifndef USEFULBUF_DISABLE_ALL_FLOAT /* - * Public functions for adding a double. See qcbor/qcbor_encode.h + * Public function for adding raw encoded CBOR. See qcbor/qcbor_encode.h */ -void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *me, double dNum) +void +QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded) { - QCBOREncode_AddType7(me, - sizeof(uint64_t), - UsefulBufUtil_CopyDoubleToUint64(dNum)); + UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded); + QCBOREncode_Private_IncrementMapOrArrayCount(pMe); } -/* - * Public functions for adding a double. See qcbor/qcbor_encode.h - */ -void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum) -{ #ifndef QCBOR_DISABLE_PREFERRED_FLOAT - const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum); - - QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue); -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - QCBOREncode_AddDoubleNoPreferred(me, dNum); -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -} - - -/* - * Public functions for adding a float. See qcbor/qcbor_encode.h +/** + * @brief Semi-private method to add a double using preferred encoding. + * + * @param[in] pMe The encode context. + * @param[in] dNum The double to add. + * + * This converts the double to a float or half-precision if it can be done + * without a loss of precision. See QCBOREncode_AddDouble(). */ -void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *me, float fNum) +void +QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum) { - QCBOREncode_AddType7(me, - sizeof(uint32_t), - UsefulBufUtil_CopyFloatToUint32(fNum)); + const IEEE754_union uNum = IEEE754_DoubleToSmaller(dNum, true); + QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue); } -/* - * Public functions for adding a float. See qcbor/qcbor_encode.h +/** + * @brief Semi-private method to add a float using preferred encoding. + * + * @param[in] pMe The encode context. + * @param[in] fNum The float to add. + * + * This converts the float to a half-precision if it can be done + * without a loss of precision. See QCBOREncode_AddFloat(). */ -void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum) +void +QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum) { -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum); - - QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue); -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - QCBOREncode_AddFloatNoPreferred(me, fNum); -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ + const IEEE754_union uNum = IEEE754_SingleToHalf(fNum); + QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue); } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/* - * 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. +/** + * @brief Semi-private method to add bigfloats and decimal fractions. + * + * @param[in] pMe The encoding context to add the value to. + * @param[in] uTag The type 6 tag indicating what this is to be. + * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an + * @c int64_t or the actual big number mantissa + * if not. + * @param[in] bBigNumIsNegative This is @c true if the big number is negative. + * @param[in] nMantissa The @c int64_t mantissa if it is not a big number. + * @param[in] nExponent The exponent. + * + * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or + * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64, + * then this outputs the "borrowed" content format. + * + * The tag content output by this is an array with two members, the + * exponent and then the mantissa. The mantissa can be either a big + * number or an @c int64_t. * - * See qcbor/qcbor_encode.h + * This implementation cannot output an exponent further from 0 than + * @c INT64_MAX. * - * Improvement: create another version of this that only takes a big - * number mantissa and converts the output to a type 0 or 1 integer - * when mantissa is small enough. + * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0, + * it must be as a big number. + * + * Typically, QCBOREncode_AddTDecimalFraction(), QCBOREncode_AddTBigFloat(), + * QCBOREncode_AddTDecimalFractionBigNum() or QCBOREncode_AddTBigFloatBigNum() + * is called instead of this. */ -void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe, - uint64_t uTag, - UsefulBufC BigNumMantissa, - bool bBigNumIsNegative, - int64_t nMantissa, - int64_t nExponent) +void +QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe, + const uint64_t uTag, + const UsefulBufC BigNumMantissa, + const bool bBigNumIsNegative, + const int64_t nMantissa, + const int64_t nExponent) { /* This is for encoding either a big float or a decimal fraction, * both of which are an array of two items, an exponent and a @@ -836,29 +718,33 @@ void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe, QCBOREncode_AddInt64(pMe, nExponent); if(!UsefulBuf_IsNULLC(BigNumMantissa)) { if(bBigNumIsNegative) { - QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa); + QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa); } else { - QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa); + QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa); } } else { QCBOREncode_AddInt64(pMe, nMantissa); } QCBOREncode_CloseArray(pMe); } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ -/* - * 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. +/** + * @brief Semi-private method to open a map, array or bstr-wrapped CBOR + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close * - * See qcbor/qcbor_encode.h + * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or + * QCBOREncode_BstrWrap() instead of this. */ -void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) +void +QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { /* Add one item to the nesting level we are in for the new map or array */ - IncrementMapOrArrayCount(me); + QCBOREncode_Private_IncrementMapOrArrayCount(pMe); /* The offset where the length of an array or map will get written * is stored in a uint32_t, not a size_t to keep stack usage @@ -868,7 +754,7 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) * past the 4GB mark, but the public interface says that the * maximum is 4GB to keep the discussion simpler. */ - size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this * code can run on a 32-bit machine and tests can pass on a 32-bit @@ -877,53 +763,163 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) * size detection would be needed reducing portability. */ if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) { - me->uError = QCBOR_ERR_BUFFER_TOO_LARGE; + pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE; } else { /* Increase nesting level because this is a map or array. Cast * from size_t to uin32_t is safe because of check above. */ - me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition); + pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition); } } -/* - * 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. +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/** + * @brief Semi-private method to open a map, array with indefinite length + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close * - * See qcbor/qcbor_encode.h + * Call QCBOREncode_OpenArrayIndefiniteLength() or + * QCBOREncode_OpenMapIndefiniteLength() instead of this. */ -void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType) +void +QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */ - AppendCBORHead(me, uMajorType, 0, 0); + QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0); /* Call the definite-length opener just to do the bookkeeping for * nesting. It will record the position of the opening item in the * encoded output but this is not used when closing this open. */ - QCBOREncode_OpenMapOrArray(me, uMajorType); + QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType); } +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ -/* - * Public functions for closing arrays and maps. See qcbor/qcbor_encode.h +/** + * @brief Check for errors when decreasing nesting. + * + * @param pMe QCBOR encoding context. + * @param uMajorType The major type of the nesting. + * + * Check that there is no previous error, that there is actually some + * nesting and that the major type of the opening of the nesting + * matches the major type of the nesting being closed. + * + * This is called when closing maps, arrays, byte string wrapping and + * open/close of byte strings. */ -void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) +static bool +QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { - InsertCBORHead(me, uMajorType, Nesting_GetCount(&(me->nesting))); +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + if(pMe->uError != QCBOR_SUCCESS) { + return true; + } + + if(!Nesting_IsInNest(&(pMe->nesting))) { + pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES; + return true; + } + + if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) { + pMe->uError = QCBOR_ERR_CLOSE_MISMATCH; + return true; + } + +#else /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + /* None of these checks are performed if the encode guards are + * turned off as they all relate to correct calling. + * + * Turning off all these checks does not turn off any checking for + * buffer overflows or pointer issues. + */ + + (void)uMajorType; + (void)pMe; +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + return false; +} + + +/** + * @brief Insert the CBOR head for a map, array or wrapped bstr. + * + * @param pMe QCBOR encoding context. + * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX. + * @param uLen The length of the data item. + * + * When an array, map or bstr was opened, nothing was done but note + * the position. This function goes back to that position and inserts + * the CBOR Head with the major type and length. + */ +static void +QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe, + uint8_t uMajorType, + size_t uLen) +{ + if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) { + return; + } + + if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { + uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; + } + + /* A stack buffer large enough for a CBOR head (9 bytes) */ + UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); + + UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, + uMajorType, + 0, + uLen); + + /* No check for EncodedHead == NULLUsefulBufC is performed here to + * save object code. It is very clear that pBufferForEncodedHead is + * the correct size. If EncodedHead == NULLUsefulBufC then + * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no + * security hole introduced. + */ + UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf), + EncodedHead, + Nesting_GetStartPos(&(pMe->nesting))); + + Nesting_Decrease(&(pMe->nesting)); +} + + +/** + * @brief Semi-private method to close a map, array or bstr wrapped CBOR + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close. + * + * Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this. + */ +void +QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe, + const uint8_t uMajorType) +{ + QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting))); } /* - * Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h + * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h */ -void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR) +void +QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe, + const bool bIncludeCBORHead, + UsefulBufC *pWrappedCBOR) { - const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting)); - const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting)); + const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); /* This subtraction can't go negative because the UsefulOutBuf * always only grows and never shrinks. UsefulOutBut itself also @@ -933,7 +929,7 @@ void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, U const size_t uBstrLen = uEndPosition - uInsertPosition; /* Actually insert */ - InsertCBORHead(me, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen); + QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen); if(pWrappedCBOR) { /* Return pointer and length to the enclosed encoded CBOR. The @@ -946,10 +942,10 @@ void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, U size_t uStartOfNew = uInsertPosition; if(!bIncludeCBORHead) { /* Skip over the CBOR head to just get the inserted bstr */ - const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); uStartOfNew += uNewEndPosition - uEndPosition; } - const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf)); + const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf)); *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew); } } @@ -958,9 +954,10 @@ void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, U /* * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h */ -void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) +void +QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) { - if(CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) { + if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) { return; } @@ -971,14 +968,14 @@ void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) return; } /* QCBOREncode_CancelBstrWrap() can't correctly undo - * QCBOREncode_BstrWrapInMap() or QCBOREncode_BstrWrapInMapN(). It + * QCBOREncode_BstrWrapInMapSZ() or QCBOREncode_BstrWrapInMapN(). It * can't undo the labels they add. It also doesn't catch the error * of using it this way. QCBOREncode_CancelBstrWrap() is used * infrequently and the the result is incorrect CBOR, not a * security hole, so no extra code or state is added to handle this * condition. */ -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ Nesting_Decrease(&(pMe->nesting)); Nesting_Decrement(&(pMe->nesting)); @@ -988,26 +985,29 @@ void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) /* * Public function for opening a byte string. See qcbor/qcbor_encode.h */ -void QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace) +void +QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace) { *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf)); #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - // TODO: is this right? uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting)); if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { + /* It's OK to nest a byte string in any type but + * another open byte string. */ pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING; return; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR); } /* * Public function for closing a byte string. See qcbor/qcbor_encode.h */ -void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) +void +QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) { UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount); if(UsefulOutBuf_GetError(&(pMe->OutBuf))) { @@ -1015,58 +1015,68 @@ void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) return; } - InsertCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount); + QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount); } -/* - * Public function for closing arrays and maps. See qcbor/qcbor_encode.h +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/** + * @brief Semi-private method to close a map, array with indefinite length + * + * @param[in] pMe 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 *pMe, uint8_t uMajorType) +void +QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { - if(CheckDecreaseNesting(pMe, uMajorType)) { + if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) { return; } /* Append the break marker (0xff for both arrays and maps) */ - AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0); + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0); Nesting_Decrease(&(pMe->nesting)); } +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ /* * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h */ -QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR) +QCBORError +QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR) { - QCBORError uReturn = QCBOREncode_GetErrorState(me); - - if(uReturn != QCBOR_SUCCESS) { + if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) { goto Done; } #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(Nesting_IsInNest(&(me->nesting))) { - uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; + if(Nesting_IsInNest(&(pMe->nesting))) { + pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; goto Done; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf)); + *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf)); Done: - return uReturn; + return pMe->uError; } /* - * Public functions to get size of the encoded result. See qcbor/qcbor_encode.h + * Public function to get size of the encoded result. See qcbor/qcbor_encode.h */ -QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen) +QCBORError +QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen) { UsefulBufC Enc; - QCBORError nReturn = QCBOREncode_Finish(me, &Enc); + QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc); if(nReturn == QCBOR_SUCCESS) { *puEncodedLen = Enc.len; @@ -1074,3 +1084,28 @@ QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLe return nReturn; } + + +/* + * Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h + */ +UsefulBufC +QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart) +{ + if(pMe->uError) { + return NULLUsefulBufC; + } + + /* An attempt was made to detect usage errors by comparing uStart + * to offsets of open arrays and maps in pMe->nesting, but it is + * not possible because there's not enough information in just + * the offset. It's not possible to known if Tell() was called before + * or after an Open(). To detect this error, the nesting level + * would also need to be known. This is not frequently used, so + * it is not worth adding this complexity. + */ + + const size_t uEnd = QCBOREncode_Tell(pMe); + + return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart); +} diff --git a/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c b/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c index 4879f91d5b60..f9588e5c01a3 100644 --- a/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c +++ b/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c @@ -1,69 +1,92 @@ -/*============================================================================== - err_to_str.c -- strings names for errors +/* ========================================================================== + * err_to_str.c -- strings names for errors + * + * Copyright (c) 2020, Patrick Uiterwijk. All rights reserved. + * Copyright (c) 2020,2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 3/21/20 + * ========================================================================== */ - Copyright (c) 2020, Patrick Uiterwijk. All rights reserved. - Copyright (c) 2020, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md +#include "qcbor/qcbor_common.h" +#include - Created on 3/21/20 - =============================================================================*/ +#define ERR_TO_STR_CASE(errpart) case errpart: return #errpart; -#include "qcbor/qcbor_common.h" -#define _ERR_TO_STR(errpart) case QCBOR_##errpart: return "QCBOR_" #errpart; +const char * +qcbor_err_to_str(const QCBORError uErr) { + switch (uErr) { + ERR_TO_STR_CASE(QCBOR_SUCCESS) + ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_SMALL) + ERR_TO_STR_CASE(QCBOR_ERR_ENCODE_UNSUPPORTED) + ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_LARGE) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) + ERR_TO_STR_CASE(QCBOR_ERR_CLOSE_MISMATCH) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_TOO_LONG) + ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_CLOSES) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) + ERR_TO_STR_CASE(QCBOR_ERR_OPEN_BYTE_STRING) + ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_CANCEL) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_TYPE_7) + ERR_TO_STR_CASE(QCBOR_ERR_EXTRA_BYTES) + ERR_TO_STR_CASE(QCBOR_ERR_UNSUPPORTED) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_INT) + ERR_TO_STR_CASE(QCBOR_ERR_INDEFINITE_STRING_CHUNK) + ERR_TO_STR_CASE(QCBOR_ERR_HIT_END) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_BREAK) + ERR_TO_STR_CASE(QCBOR_ERR_INPUT_TOO_LARGE) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_TOO_LONG) + ERR_TO_STR_CASE(QCBOR_ERR_STRING_TOO_LONG) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_EXP_AND_MANTISSA) + ERR_TO_STR_CASE(QCBOR_ERR_NO_STRING_ALLOCATOR) + ERR_TO_STR_CASE(QCBOR_ERR_STRING_ALLOCATE) + ERR_TO_STR_CASE(QCBOR_ERR_MAP_LABEL_TYPE) + ERR_TO_STR_CASE(QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) + ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_TAGS_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_TAGS) + ERR_TO_STR_CASE(QCBOR_ERR_UNEXPECTED_TYPE) + ERR_TO_STR_CASE(QCBOR_ERR_DUPLICATE_LABEL) + ERR_TO_STR_CASE(QCBOR_ERR_MEM_POOL_SIZE) + ERR_TO_STR_CASE(QCBOR_ERR_INT_OVERFLOW) + ERR_TO_STR_CASE(QCBOR_ERR_DATE_OVERFLOW) + ERR_TO_STR_CASE(QCBOR_ERR_EXIT_MISMATCH) + ERR_TO_STR_CASE(QCBOR_ERR_NO_MORE_ITEMS) + ERR_TO_STR_CASE(QCBOR_ERR_LABEL_NOT_FOUND) + ERR_TO_STR_CASE(QCBOR_ERR_NUMBER_SIGN_CONVERSION) + ERR_TO_STR_CASE(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) + ERR_TO_STR_CASE(QCBOR_ERR_MAP_NOT_ENTERED) + ERR_TO_STR_CASE(QCBOR_ERR_CALLBACK_FAIL) + ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_DATE_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_HALF_PRECISION_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_HW_FLOAT_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_EXCEPTION) + ERR_TO_STR_CASE(QCBOR_ERR_ALL_FLOAT_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT) + ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) -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_ENCODE_UNSUPPORTED) - _ERR_TO_STR(ERR_BUFFER_TOO_LARGE) - _ERR_TO_STR(ERR_ARRAY_NESTING_TOO_DEEP) - _ERR_TO_STR(ERR_CLOSE_MISMATCH) - _ERR_TO_STR(ERR_ARRAY_TOO_LONG) - _ERR_TO_STR(ERR_TOO_MANY_CLOSES) - _ERR_TO_STR(ERR_ARRAY_OR_MAP_STILL_OPEN) - _ERR_TO_STR(ERR_BAD_TYPE_7) - _ERR_TO_STR(ERR_EXTRA_BYTES) - _ERR_TO_STR(ERR_UNSUPPORTED) - _ERR_TO_STR(ERR_ARRAY_OR_MAP_UNCONSUMED) - _ERR_TO_STR(ERR_BAD_INT) - _ERR_TO_STR(ERR_INDEFINITE_STRING_CHUNK) - _ERR_TO_STR(ERR_HIT_END) - _ERR_TO_STR(ERR_BAD_BREAK) - _ERR_TO_STR(ERR_INPUT_TOO_LARGE) - _ERR_TO_STR(ERR_ARRAY_DECODE_NESTING_TOO_DEEP) - _ERR_TO_STR(ERR_ARRAY_DECODE_TOO_LONG) - _ERR_TO_STR(ERR_STRING_TOO_LONG) - _ERR_TO_STR(ERR_BAD_EXP_AND_MANTISSA) - _ERR_TO_STR(ERR_NO_STRING_ALLOCATOR) - _ERR_TO_STR(ERR_STRING_ALLOCATE) - _ERR_TO_STR(ERR_TOO_MANY_TAGS) - _ERR_TO_STR(ERR_MAP_LABEL_TYPE) - _ERR_TO_STR(ERR_UNEXPECTED_TYPE) - _ERR_TO_STR(ERR_BAD_OPT_TAG) - _ERR_TO_STR(ERR_DUPLICATE_LABEL) - _ERR_TO_STR(ERR_MEM_POOL_SIZE) - _ERR_TO_STR(ERR_INT_OVERFLOW) - _ERR_TO_STR(ERR_DATE_OVERFLOW) - _ERR_TO_STR(ERR_EXIT_MISMATCH) - _ERR_TO_STR(ERR_NO_MORE_ITEMS) - _ERR_TO_STR(ERR_LABEL_NOT_FOUND) - _ERR_TO_STR(ERR_NUMBER_SIGN_CONVERSION) - _ERR_TO_STR(ERR_CONVERSION_UNDER_OVER_FLOW) - _ERR_TO_STR(ERR_MAP_NOT_ENTERED) - _ERR_TO_STR(ERR_CALLBACK_FAIL) - _ERR_TO_STR(ERR_FLOAT_DATE_DISABLED) - _ERR_TO_STR(ERR_HALF_PRECISION_DISABLED) - _ERR_TO_STR(ERR_HW_FLOAT_DISABLED) - _ERR_TO_STR(ERR_FLOAT_EXCEPTION) - _ERR_TO_STR(ERR_ALL_FLOAT_DISABLED) + default: + if(uErr >= QCBOR_ERR_FIRST_USER_DEFINED && uErr <= QCBOR_ERR_LAST_USER_DEFINED) { + /* Static buffer is not thread safe, but this is only a diagnostic */ + static char buf[20]; + strcpy(buf, "USER_DEFINED_"); + size_t uEndOffset = strlen(buf); + buf[uEndOffset] = (char)(uErr/100 + '0'); + buf[uEndOffset+1] = (char)(((uErr/10) % 10) + '0'); + buf[uEndOffset+2] = (char)((uErr % 10 )+ '0'); + buf[uEndOffset+3] = '\0'; + return buf; - default: - return "Unidentified error"; - } + } else { + return "Unidentified QCBOR error"; + } + } } diff --git a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c index e93a011b86f6..83e9a686dba8 100644 --- a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c +++ b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - =============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #include "UsefulBuf.h" @@ -127,6 +127,30 @@ const char * UOBTest_NonAdversarial(void) goto Done; } + Out = UsefulOutBuf_SubString(&UOB, 10, 8); + if(UsefulBuf_IsNULLC(Out) || + UsefulBuf_Compare(UsefulBuf_FROM_SZ_LITERAL("unbounce"), Out) || + UsefulOutBuf_GetError(&UOB)) { + szReturn = "SubString substring"; + goto Done; + } + + Out = UsefulOutBuf_SubString(&UOB, 0, Expected.len); + if(UsefulBuf_IsNULLC(Out) || + UsefulBuf_Compare(Expected, Out) || + UsefulOutBuf_GetError(&UOB)) { + szReturn = "SubString all"; + goto Done; + } + + Out = UsefulOutBuf_SubString(&UOB, Expected.len, 0); + if(UsefulBuf_IsNULLC(Out) || + UsefulBuf_Compare(UsefulBuf_FROM_SZ_LITERAL(""), Out) || + UsefulOutBuf_GetError(&UOB)) { + szReturn = "SubString empty"; + goto Done; + } + /* Now test the size calculation mode */ UsefulOutBuf_Init(&UOB, SizeCalculateUsefulBuf); @@ -146,13 +170,12 @@ const char * UOBTest_NonAdversarial(void) /* - Append test utility. - pUOB is the buffer to append too - num is the amount to append - expected is the expected return code, 0 or 1 - - returns 0 if test passed - + * Append test utility. + * pUOB is the buffer to append too + * num is the amount to append + * expected is the expected return code, 0 or 1 + * + * returns 0 if test passed */ static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected) { @@ -175,7 +198,7 @@ static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected) /* - Same as append, but takes a position param too + * Same as append, but takes a position param too */ static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected) { @@ -196,15 +219,14 @@ static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected) /* - Boundary conditions to test - - around 0 - - around the buffer size - - around MAX size_t - - - Test these for the buffer size and the cursor, the insert amount, the - append amount and the insert position - + * Boundary conditions to test + * - around 0 + * - around the buffer size + * - around MAX size_t + * + * + * Test these for the buffer size and the cursor, the insert amount, the + * append amount and the insert position */ const char *UOBTest_BoundaryConditionsTest(void) @@ -248,7 +270,7 @@ const char *UOBTest_BoundaryConditionsTest(void) return "Bad insertion point not caught"; - UsefulBuf_MAKE_STACK_UB(outBuf2,10); + UsefulBuf_MAKE_STACK_UB(outBuf2, 10); UsefulOutBuf_Init(&UOB, outBuf2); @@ -262,6 +284,29 @@ const char *UOBTest_BoundaryConditionsTest(void) return "insert with data should have failed"; } + UsefulOutBuf_Init(&UOB, outBuf2); + UsefulOutBuf_AppendString(&UOB, "abc123"); + + UsefulBufC Out = UsefulOutBuf_SubString(&UOB, 7, 1); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString start should fail off end 1"; + } + Out = UsefulOutBuf_SubString(&UOB, 5, 3); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 2"; + } + Out = UsefulOutBuf_SubString(&UOB, 0, 7); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 3"; + } + Out = UsefulOutBuf_SubString(&UOB, 7, 0); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 4"; + } + Out = UsefulOutBuf_SubString(&UOB, 6, 1); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 5"; + } UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6); @@ -280,16 +325,31 @@ const char *UOBTest_BoundaryConditionsTest(void) if(!UsefulOutBuf_GetError(&UOB)) { return "lengths near max size"; } + UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB); + if(!UsefulBuf_IsNULLC(O)) { + return "OutUBuf in error should have returned NULL"; + } UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, 100}); if(!UsefulOutBuf_IsBufferNULL(&UOB)) { return "NULL check failed"; } - return NULL; -} + UsefulOutBuf_Init(&UOB, outbuf); + UOB.magic = 99; // corrupt the UOB + O = UsefulOutBuf_OutUBuf(&UOB); + if(!UsefulBuf_IsNULLC(O)) { + return "OutUBuf on corrupted should have returned NULL"; + } + MakeUsefulBufOnStack(Tmp, 20); + O = UsefulOutBuf_CopyOut(&UOB, Tmp); + if(!UsefulBuf_IsNULLC(O)) { + return "CopyOut on corrupted should have returned NULL"; + } + return NULL; +} @@ -640,6 +700,10 @@ const char *UBUtilTests(void) return "Failed to find 3"; } + if(SIZE_MAX != UsefulBuf_FindBytes(Expected, ExpectedLonger)) { + return "Failed to find 4"; + } + const uint8_t pB[] = {0x01, 0x02, 0x03}; UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB); @@ -673,6 +737,22 @@ const char *UBUtilTests(void) return "Incorrect pointer offset for start"; } + if(UsefulBuf_OffsetToPointer(Boo, 0) != &pB[0]) { + return "Wrong OffsetToPointer"; + } + + if(UsefulBuf_OffsetToPointer(Boo, 3) != NULL) { + return "Didn't validate offset correctly"; + } + + if(UsefulBuf_OffsetToPointer(Boo, 2) != &pB[2]) { + return "Wrong OffsetToPointer 2"; + } + + if(UsefulBuf_OffsetToPointer(NULLUsefulBufC, 2) != NULL) { + return "Failed OffsetToPtr on NULLUsefulBufC"; + } + return NULL; } @@ -688,7 +768,7 @@ const char * UIBTest_IntegerFormat(void) #ifndef USEFULBUF_DISABLE_ALL_FLOAT const float f = (float)314.15; const double d = 2.1e10; -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition @@ -698,7 +778,7 @@ const char * UIBTest_IntegerFormat(void) #ifndef USEFULBUF_DISABLE_ALL_FLOAT UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB); if(UsefulBuf_IsNULLC(O)) @@ -739,6 +819,16 @@ const char * UIBTest_IntegerFormat(void) } #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + if(UsefulInputBuf_GetUint16(&UIB) != 0) { + return "Didn't catch off end with GetUint16"; + } + if(UsefulInputBuf_GetUint32(&UIB) !=0 ) { + return "Didn't catch off end with GetUint32"; + } + if(UsefulInputBuf_GetUint64(&UIB) !=0 ) { + return "Didn't catch off end with GetUint64"; + } + // Reset and go again for a few more tests UsefulInputBuf_Init(&UIB, O); @@ -773,7 +863,7 @@ const char * UIBTest_IntegerFormat(void) if(UsefulInputBuf_BytesAvailable(&UIB, 12)){ return "Wrong number of bytes available II"; } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ UsefulInputBuf_Seek(&UIB, 0); @@ -800,6 +890,51 @@ const char * UIBTest_IntegerFormat(void) return "PointerToOffset not working"; } + + const uint8_t pB[] = {0x01, 0x02, 0x03}; + UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB); + + UsefulInputBuf_Init(&UIB, Boo); + + if(UsefulInputBuf_OffsetToPointer(&UIB, 0) != &pB[0]) { + return "OffsetToPointer fail"; + } + + if(UsefulInputBuf_OffsetToPointer(&UIB, SIZE_MAX) != NULL) { + return "OffsetToPointer SIZE_MAX fail"; + } + + UsefulInputBuf_Init(&UIB, Boo); + UIB.magic = 88; + size_t uUnc = UsefulInputBuf_BytesUnconsumed(&UIB); + if(uUnc != 0) { + return "Didn't detect corrupted UsefulInputBuf"; + } + + UsefulInputBuf_Init(&UIB, Boo); + UIB.cursor = 500; + uUnc = UsefulInputBuf_BytesUnconsumed(&UIB); + if(uUnc != 0) { + return "Didn't detect bad UsefulInputBuf cursor"; + } + + if(!UsefulBuf_IsNULLC(UsefulInputBuf_GetUsefulBuf(&UIB, 5000))) { + return "Didn't detect off-end request of UsefulInputBuf"; + } + + if(!UsefulInputBuf_GetError(&UIB)) { + return "UIB Error state not reported"; + } + + UsefulInputBuf_Init(&UIB, Boo); + if(UsefulInputBuf_GetBufferLength(&UIB) != Boo.len) { + return "UIB length wrong"; + } + UsefulInputBuf_SetBufferLength(&UIB, 1); + if(UsefulInputBuf_GetBufferLength(&UIB) != 1) { + return "UIB SetBufferLength failed"; + } + return NULL; } @@ -825,7 +960,7 @@ const char *UBUTest_CopyUtil(void) return NULL; } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ const char *UBAdvanceTest(void) @@ -871,5 +1006,33 @@ const char *UBAdvanceTest(void) return "Advance off end didn't set error"; } + // Try to advance in error state + UsefulOutBuf_Reset(&UOB); + UsefulOutBuf_Advance(&UOB, 1); + Place = UsefulOutBuf_GetOutPlace(&UOB); + UsefulOutBuf_Advance(&UOB, 1000); + UsefulOutBuf_Advance(&UOB, 1); + UsefulBuf Place2; + Place2 = UsefulOutBuf_GetOutPlace(&UOB); + if(memcmp(&Place, &Place2, sizeof(Place))) { + return "Advance didn't noop in error state"; + } + + UsefulOutBuf_Reset(&UOB); + UOB.data_len = UOB.UB.len + 1; // React in and corrupt + UsefulOutBuf_Advance(&UOB, 1); + if(!UsefulOutBuf_GetError(&UOB)) { + return "didn't detect corrupted UOB"; + } + + UsefulOutBuf BadUOB; + memset(&BadUOB, 'x', sizeof(BadUOB)); + BadUOB.err = 0; + UsefulOutBuf_Advance(&BadUOB, 1); + if(!UsefulOutBuf_GetError(&BadUOB)) { + return "didn't detect bad UOB"; + } + + return NULL; } diff --git a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h index 235358e82c8f..828f3f422287 100644 --- a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h +++ b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - 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. - ==============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #ifndef UsefulBuf_UsefulBuf_Tests_h #define UsefulBuf_UsefulBuf_Tests_h @@ -48,7 +48,7 @@ const char * UIBTest_IntegerFormat(void); #ifndef USEFULBUF_DISABLE_ALL_FLOAT const char * UBUTest_CopyUtil(void); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ const char * UBAdvanceTest(void); diff --git a/3rdparty/exported/QCBOR/test/float_tests.c b/3rdparty/exported/QCBOR/test/float_tests.c index 2bf5fad311b7..6e00472a0032 100644 --- a/3rdparty/exported/QCBOR/test/float_tests.c +++ b/3rdparty/exported/QCBOR/test/float_tests.c @@ -1,32 +1,33 @@ -/*============================================================================== - float_tests.c -- tests for float and conversion to/from half-precision - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/19/18 - =============================================================================*/ +/* ========================================================================== + * float_tests.c -- tests for float and conversion to/from half-precision + * + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 9/19/18 + * ========================================================================= */ #include "float_tests.h" #include "qcbor/qcbor_encode.h" #include "qcbor/qcbor_decode.h" #include "qcbor/qcbor_spiffy_decode.h" -#include // For INFINITY and NAN and isnan() +#include /* For INFINITY and NAN and isnan() */ -/* Make a test results code that includes three components - * Return code is - * xxxyyyzzz where zz is the error code, yy is the test number and zz is - * check being performed + +/* Make a test results code that includes three components. Return code + * is xxxyyyzzz where zz is the error code, yy is the test number and + * zz is check being performed */ -static inline int32_t MakeTestResultCode(uint32_t uTestCase, - uint32_t uTestNumber, - QCBORError uErrorCode) +static inline int32_t +MakeTestResultCode(uint32_t uTestCase, + uint32_t uTestNumber, + QCBORError uErrorCode) { uint32_t uCode = (uTestCase * 1000000) + (uTestNumber * 1000) + @@ -40,205 +41,508 @@ static inline int32_t MakeTestResultCode(uint32_t uTestCase, #include "half_to_double_from_rfc7049.h" -/* - Half-precision values that are input to test half-precision decoding - - As decoded by http://cbor.me - {"zero": 0.0, - "infinitity": Infinity, - "negative infinitity": -Infinity, - "NaN": NaN, - "one": 1.0, - "one third": 0.333251953125, - "largest half-precision": 65504.0, - "too-large half-precision": Infinity, - "smallest subnormal": 5.960464477539063e-8, - "smallest normal": 0.00006097555160522461, - "biggest subnormal": 0.00006103515625, - "subnormal single": 0.0, - 3: -2.0, - 4: NaN, - 5: NaN, - 6: NaN, - 7: NaN} - */ -static const uint8_t spExpectedHalf[] = { - 0xB1, - 0x64, - 0x7A, 0x65, 0x72, 0x6F, - 0xF9, 0x00, 0x00, // half-precision 0.000 - 0x6A, - 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0x7C, 0x00, // Infinity - 0x73, - 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, - 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0xFC, 0x00, // -Inifinity - 0x63, - 0x4E, 0x61, 0x4E, - 0xF9, 0x7E, 0x00, // NaN - 0x63, - 0x6F, 0x6E, 0x65, - 0xF9, 0x3C, 0x00, // 1.0 - 0x69, - 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, - 0xF9, 0x35, 0x55, // half-precsion one third 0.333251953125 - 0x76, - 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, - 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xF9, 0x7B, 0xFF, // largest half-precision 65504.0 - 0x78, 0x18, - 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6F, 0x6E, - 0xF9, 0x7C, 0x00, // Infinity - 0x72, - 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, - 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x00, 0x01, // Smallest half-precision subnormal 0.000000059604645 - 0x71, - 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, - 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x03, 0xFF, // Largest half-precision subnormal 0.0000609755516 - 0x6F, - 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, - 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x04, 0x00, // Smallest half-precision normal 0.000061988 - 0x70, - 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, - 0xF9, 0x00, 0x00, - 0x03, - 0xF9, 0xC0, 0x00, // -2 - 0x04, - 0xF9, 0x7E, 0x00, // qNaN - 0x05, - 0xF9, 0x7C, 0x01, // sNaN - 0x06, - 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f - 0x07, - 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f +struct DoubleTestCase { + double dNumber; + double fNumber; + UsefulBufC Preferred; + UsefulBufC NotPreferred; + UsefulBufC CDE; + UsefulBufC DCBOR; }; +/* Boundaries for all destination conversions to test at. + * + * smallest subnormal single 1.401298464324817e-45 2^^-149 + * largest subnormal single 1.1754942106924411e-38 2^^-126 + * smallest normal single 1.1754943508222875e-38 + * largest single 3.4028234663852886E+38 + * + * smallest subnormal half 5.9604644775390625E-8 + * largest subnormal half 6.097555160522461E-5 + * smallest normal half 6.103515625E-5 + * largest half 65504.0 + * + * Boundaries for origin conversions + * smallest subnormal double 5.0e-324 2^^-1074 + * largest subnormal double + * smallest normal double 2.2250738585072014e-308 2^^-1022 + * largest normal double 1.7976931348623157e308 2^^-1023 + */ -inline static bool CheckDouble(double d, uint64_t u) -{ - return UsefulBufUtil_CopyDoubleToUint64(d) != u; -} - - -int32_t HalfPrecisionDecodeBasicTests(void) -{ - UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf); - - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, HalfPrecision, 0); - - QCBORItem Item; - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -1; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { - return -3; - } +/* Always four lines per test case so shell scripts can process into + * other formats. CDE and DCBOR standards are not complete yet, + * encodings are a guess. C string literals are used because they + * are the shortest notation. They are used __with a length__ . Null + * termination doesn't work because there are zero bytes. + */ +static const struct DoubleTestCase DoubleTestCases[] = { + /* Zero */ + {0.0, 0.0f, + {"\xF9\x00\x00", 3}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x00\x00", 3}, {"\xF9\x00\x00", 3}}, + + /* Negative Zero */ + {-0.0, -0.0f, + {"\xF9\x80\x00", 3}, {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x80\x00", 3}, {"\xF9\x80\x00", 3}}, + + /* NaN */ + {NAN, NAN, + {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Infinity */ + {INFINITY, INFINITY, + {"\xF9\x7C\x00", 3}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7C\x00", 3}, {"\xF9\x7C\x00", 3}}, + + /* Negative Infinity */ + {-INFINITY, -INFINITY, + {"\xF9\xFC\x00", 3}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\xFC\x00", 3}, {"\xF9\xFC\x00", 3}}, + + /* 1.0 */ + {1.0, 1.0f, + {"\xF9\x3C\x00", 3}, {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x3C\x00", 3}, {"\xF9\x3C\x00", 3}}, + + /* -2.0 -- a negative number that is not zero */ + {-2.0, -2.0f, + {"\xF9\xC0\x00", 3}, {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\xC0\x00", 3}, {"\xF9\x3C\x00", 3}}, + + /* 1/3 */ + {0.333251953125, 0.333251953125f, + {"\xF9\x35\x55", 3}, {"\xFB\x3F\xD5\x54\x00\x00\x00\x00\x00", 9}, + {"\xF9\x35\x55", 3}, {"\xF9\x35\x55", 3}}, + + /* 5.9604644775390625E-8 -- smallest half-precision subnormal */ + {5.9604644775390625E-8, 0.0f, + {"\xF9\x00\x01", 3}, {"\xFB\x3E\x70\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x00\x01", 3}, {"\xF9\x00\x01", 3}}, + + /* 3.0517578125E-5 -- a half-precision subnormal */ + {3.0517578125E-5, 0.0f, + {"\xF9\x02\x00", 3}, {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x02\x00", 3}, {"\xF9\x02\x00", 3}}, + + /* 6.097555160522461E-5 -- largest half-precision subnormal */ + {6.097555160522461E-5, 0.0f, + {"\xF9\x03\xFF", 3}, {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9}, + {"\xF9\x03\xFF", 3}, {"\xF9\04\00", 3}}, + + /* 6.103515625E-5 -- smallest possible half-precision normal */ + {6.103515625E-5, 0.0f, + {"\xF9\04\00", 3}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\04\00", 3}, {"\xF9\04\00", 3}}, + + /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */ + {6.1035156250000014E-5, 6.1035156250000014E-5f, + {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, + {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}}, + + /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */ + {6.1035156249999993E-5, 0.0f, + {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* 65504.0 -- largest possible half-precision */ + {65504.0, 0.0f, + {"\xF9\x7B\xFF", 3}, {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7B\xFF", 3}, {"\xF9\x7B\xFF", 3}}, + + /* 65504.1 -- exponent too large and too much precision to convert */ + {65504.1, 0.0f, + {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, + {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}}, + + /* 65536.0 -- exponent too large but not too much precision for single */ + {65536.0, 65536.0f, + {"\xFA\x47\x80\x00\x00", 5}, {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x47\x80\x00\x00", 5}, {"\xFA\x47\x80\x00\x00", 5}}, + + /* 1.401298464324817e-45 -- smallest single subnormal */ + {1.401298464324817e-45, 1.40129846E-45f, + {"\xFA\x00\x00\x00\x01", 5}, {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x00\x00\x00\x01", 5}, {"\xFA\x00\x00\x00\x01", 5}}, + + /* 5.8774717541114375E-39 -- slightly smaller than the smallest + // single normal */ + {5.8774717541114375E-39, 5.87747175E-39f, + {"\xFA\x00\x40\x00\x00", 5}, {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x00\x40\x00\x00", 5}, {"\xFA\x00\x40\x00\x00", 5}}, + + /* 1.1754942106924411e-38 -- largest single subnormal */ + {1.1754942106924411E-38, 1.17549421E-38f, + {"\xFA\x00\x7f\xff\xff", 5}, {"\xFB\x38\x0f\xff\xff\xC0\x00\x00\x00", 9}, + {"\xFA\x00\x7f\xff\xff", 5}, {"\xFA\x00\x7f\xff\xff", 5} }, + + /* 1.1754943508222874E-38 -- slightly bigger than smallest single normal */ + {1.1754943508222874E-38, 0.0f, + {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, + {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}}, + + /* 1.1754943508222875e-38 -- smallest single normal */ + {1.1754943508222875e-38, 1.17549435E-38f, + {"\xFA\x00\x80\x00\x00", 5}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x00\x80\x00\x00", 5}, {"\xFA\x00\x80\x00\x00", 5}}, + + /* 1.1754943508222875e-38 -- slightly bigger than smallest single normal */ + {1.1754943508222878e-38, 0.0f, + {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, + {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}}, + + /* 16777216 -- converts to single without loss */ + {16777216, 16777216, + {"\xFA\x4B\x80\x00\x00", 5}, {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x4B\x80\x00\x00", 5}, {"\xFA\x4B\x80\x00\x00", 5}}, + + /* 16777217 -- one more than above and fails conversion to single */ + {16777217, 16777216, + {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, + {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}}, + + /* 3.4028234663852886E+38 -- largest possible single normal */ + {3.4028234663852886E+38, 3.40282347E+38f, + {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9}, + {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFA\x7F\x7F\xFF\xFF", 5}}, + + /* 3.402823466385289E+38 -- slightly larger than largest possible single */ + {3.402823466385289E+38, 0.0f, + {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, + {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}}, + + /* 3.402823669209385e+38 -- exponent larger by one than largest possible single */ + {3.402823669209385e+38, 0.0f, + {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}}, + + /* 5.0e-324 -- smallest double subnormal normal */ + {5.0e-324, 0.0f, + {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, + {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}}, + + /* 2.2250738585072009E−308 -- largest double subnormal */ + {2.2250738585072009e-308, 0.0f, + {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* 2.2250738585072014e-308 -- smallest double normal */ + {2.2250738585072014e-308, 0.0f, + {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, + {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}}, + + /* 1.7976931348623157E308 -- largest double normal */ + {1.7976931348623157e308, 0.0f, + {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* List terminator */ + {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} } +}; - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) { - return -4; - } - // TODO: NAN-related is this really converting right? It is carrying - // payload, but this confuses things. - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) { - return -5; - } +struct NaNTestCase { + uint64_t uDouble; + uint32_t uSingle; + UsefulBufC Preferred; + UsefulBufC NotPreferred; + UsefulBufC CDE; + UsefulBufC DCBOR; +}; - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0) { - return -6; - } +/* Always four lines per test case so shell scripts can process into + * other formats. CDE and DCBOR standards are not complete yet, + * encodings are a guess. C string literals are used because they + * are the shortest notation. They are used __with a length__ . Null + * termination doesn't work because there are zero bytes. + */ +static const struct NaNTestCase NaNTestCases[] = { + + /* Payload with most significant bit set, a qNaN by most implementations */ + {0x7ff8000000000000, 0x00000000, + {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with single rightmost set */ + {0x7ff8000000000001, 0x00000000, + {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 10 leftmost bits set -- converts to half */ + {0x7ffffc0000000000, 0x00000000, + {"\xF9\x7F\xFF", 3}, {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 10 rightmost bits set -- cannot convert to half */ + {0x7ff80000000003ff, 0x00000000, + {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 23 leftmost bits set -- converts to a single */ + {0x7ffFFFFFE0000000, 0x7fffffff, + {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 24 leftmost bits set -- fails to convert to a single */ + {0x7ffFFFFFF0000000, 0x00000000, + {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with all bits set */ + {0x7fffffffffffffff, 0x00000000, + {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* List terminator */ + {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} } +}; - // Approximately 1/3 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125) { - return -7; - } - // Largest half-precision - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0) { - return -8; - } - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { - return -9; - } +/* Public function. See float_tests.h + * + * This is the main test of floating-point encoding / decoding. It is + * data-driven by the above tables. It works better than tests below that + * it mostly replaces because it tests one number at a time, rather than + * putting them all in a map. It is much easier to debug test failures + * and to add new tests. */ +int32_t +FloatValuesTests(void) +{ + unsigned int uTestIndex; + const struct DoubleTestCase *pTestCase; + const struct NaNTestCase *pNaNTestCase; + MakeUsefulBufOnStack( TestOutBuffer, 20); + UsefulBufC TestOutput; + QCBOREncodeContext EnCtx; + QCBORError uErr; + QCBORDecodeContext DCtx; + QCBORItem Item; + uint64_t uDecoded; +#ifdef QCBOR_DISABLE_FLOAT_HW_USE + uint32_t uDecoded2; +#endif - // Smallest half-precision subnormal - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00000005960464477539063) { - return -10; - } + /* Test a variety of doubles */ + for(uTestIndex = 0; DoubleTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) { + pTestCase = &DoubleTestCases[uTestIndex]; + + // if(pTestCase->dNumber == 1.1754943508222874E-38) { + if(uTestIndex == 19) { + uErr = 99; /* For setting break points for particular tests */ + } + + /* Number Encode of Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 1, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) { + return MakeTestResultCode(uTestIndex, 1, 200); + } + + /* Number Encode of Not Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 2, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) { + return MakeTestResultCode(uTestIndex, 2, 200); + } + + /* Number Decode of Preferred */ + QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 3, uErr);; + } +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.dfnum)) { + return MakeTestResultCode(uTestIndex, 5, 0); + } + } else { + if(Item.val.dfnum != pTestCase->dNumber) { + return MakeTestResultCode(uTestIndex, 6, 0); + } + } +#else /* QCBOR_DISABLE_FLOAT_HW_USE */ + /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not + * converted to double when decoding, so test differently. len == 5 + * indicates single-precision in the encoded CBOR. */ + if(pTestCase->Preferred.len == 5) { + if(Item.uDataType != QCBOR_TYPE_FLOAT) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.fnum)) { + return MakeTestResultCode(uTestIndex, 5, 0); + } + } else { + if(Item.val.fnum != pTestCase->fNumber) { + return MakeTestResultCode(uTestIndex, 6, 0); + } + } + } else { + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.dfnum)) { + return MakeTestResultCode(uTestIndex, 5, 0); + } + } else { + if(Item.val.dfnum != pTestCase->dNumber) { + return MakeTestResultCode(uTestIndex, 6, 0); + } + } + } +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - // Largest half-precision subnormal - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006097555160522461) { - return -11; - } + /* Number Decode of Not Preferred */ + QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 7, uErr);; + } + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 8, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.dfnum)) { + return MakeTestResultCode(uTestIndex, 9, 0); + } + } else { + if(Item.val.dfnum != pTestCase->dNumber) { + return MakeTestResultCode(uTestIndex, 10, 0); + } + } - // Smallest half-precision normal - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006103515625) { - return -12; } - // half-precision zero - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) { - return -13; - } + /* Test a variety of NaNs with payloads */ + for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) { + pNaNTestCase = &NaNTestCases[uTestIndex]; + + + if(uTestIndex == 4) { + uErr = 99; /* For setting break points for particular tests */ + } + + /* NaN Encode of Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble)); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 10, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) { + return MakeTestResultCode(uTestIndex+100, 10, 200); + } + +#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION + { + /* This test is off by default. It's purpose is to check + * QCBOR's mask-n-shift implementation against the HW/CPU + * instructions that do conversion between double and single. + * It is off because it is only used on occasion to verify + * QCBOR and because it is suspected that some HW/CPU does + * implement this correctly. NaN payloads are an obscure + * feature. */ + float f; + double d, d2; + + d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber); + + /* Cast the double to a single and then back to a double and + * see if they are equal. If so, then the NaN payload doesn't + * have any bits that are lost when converting to single and + * it can be safely converted. + * + * This test can't be done for half-precision because it is + * not widely supported. + */ + f = (float)d; + d2 = (double)f; + + /* The length of encoded doubles is 9, singles 5 and halves + * 3. If there are NaN payload bits that can't be converted, + * then the length must be 9. + */ + if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) { + /* QCBOR conversion not the same as HW conversion */ + return MakeTestResultCode(uTestIndex, 9, 200); + } + } +#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */ + + + /* NaN Encode of Not Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble)); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 11, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) { + return MakeTestResultCode(uTestIndex+100, 11, 200); + } + + /* NaN Decode of Preferred */ + QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 12, uErr); + } - // negative 2 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0) { - return -14; - } +#ifndef QCBOR_DISABLE_FLOAT_HW_USE - // TODO: NAN-related double check these four tests - QCBORDecode_GetNext(&DC, &Item); // qNaN - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff8000000000000ULL)) { - return -15; - } - QCBORDecode_GetNext(&DC, &Item); // sNaN - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff0000000000001ULL)) { - return -16; - } - QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff800000000000fULL)) { - return -17; - } - QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff000000000000fULL)) { - return -18; - } + uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum); + if(uDecoded != pNaNTestCase->uDouble) { + return MakeTestResultCode(uTestIndex+100, 12, 200); + } +#else /* QCBOR_DISABLE_FLOAT_HW_USE */ + if(pNaNTestCase->Preferred.len == 5) { + if(Item.uDataType != QCBOR_TYPE_FLOAT) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + + uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum); + + if(uDecoded2 != pNaNTestCase->uSingle) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + } else { + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum); + if(uDecoded != pNaNTestCase->uDouble) { + return MakeTestResultCode(uTestIndex+100, 12, 200); + } + } +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - if(QCBORDecode_Finish(&DC)) { - return -19; + /* NaN Decode of Not Preferred */ + QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 13, uErr); + } + uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum); + if(uDecoded != pNaNTestCase->uDouble) { + return MakeTestResultCode(uTestIndex+100, 13, 200); + } } return 0; @@ -246,379 +550,58 @@ int32_t HalfPrecisionDecodeBasicTests(void) - -int32_t HalfPrecisionAgainstRFCCodeTest(void) +/* Public function. See float_tests.h */ +int32_t +HalfPrecisionAgainstRFCCodeTest(void) { - for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) { - unsigned char x[2]; - x[1] = (uint8_t)(uHalfP & 0xff); - x[0] = (uint8_t)(uHalfP >> 8); // uHalfP is always less than 0xffff - double d = decode_half(x); - - // Contruct the CBOR for the half-precision float by hand - UsefulBuf_MAKE_STACK_UB(__xx, 3); - UsefulOutBuf UOB; - UsefulOutBuf_Init(&UOB, __xx); - - const uint8_t uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); // 0xf9 - UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float - UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); - - // Now parse the hand-constructed CBOR. This will invoke the - // conversion to a float - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0); - - QCBORItem Item; - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE) { - return -1; - } - - //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", - // uHalfP, Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d)); - - if(isnan(d)) { - // The RFC code uses the native instructions which may or may not - // handle sNaN, qNaN and NaN payloads correctly. This test just - // makes sure it is a NaN and doesn't worry about the type of NaN - if(!isnan(Item.val.dfnum)) { - return -3; - } - } else { - if(Item.val.dfnum != d) { - return -2; - } - } - } - return 0; -} - - -/* - Expected output from preferred serialization of some of floating-point numbers -{"zero": 0.0, - "negative zero": -0.0, - "infinitity": Infinity, - "negative infinitity": -Infinity, - "NaN": NaN, - "one": 1.0, - "one third": 0.333251953125, - "largest half-precision": 65504.0, - "largest half-precision point one": 65504.1, - "too-large half-precision": 65536.0, - "smallest half subnormal": 5.960464477539063e-8, - "smallest half normal": 0.00006103515625, - "smallest half normal plus": 0.00006103515625000001, - "smallest normal minus": 0.000030517578125, - "largest single": 3.4028234663852886e+38, - "largest single plus": 6.805646932770577e+38, - "smallest single": 1.1754943508222875e-38, - "smallest single plus": 1.1754943508222878e-38, - "smallest single minus": 1.1754943508222874e-38, - "smallest single minus more": 5.877471754111438e-39, - 3: -2.0, "single precision": 16777216.0, - "single with precision loss": 16777217.0, - 1: "fin"} - */ -static const uint8_t spExpectedSmallest[] = { - 0xB8, 0x1A, - 0x64, 0x7A, 0x65, 0x72, 0x6F, - 0xF9, 0x00, 0x00, - - 0x6D, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A, - 0x65, 0x72, 0x6F, - 0xF9, 0x80, 0x00, - - 0x6A, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0x7C, 0x00, - - 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, - 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0xFC, 0x00, - - 0x63, 0x4E, 0x61, 0x4E, - 0xF9, 0x7E, 0x00, - - 0x63, 0x6F, 0x6E, 0x65, - 0xF9, 0x3C, 0x00, - - 0x69, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, - 0xF9, 0x35, 0x55, - - 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, - 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6F, 0x6E, - 0xF9, 0x7B, 0xFF, - - 0x78, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, - 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, - 0x6F, 0x6E, 0x65, - 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, - - 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, - 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xFA, 0x47, 0x80, 0x00, 0x00, - - 0x77, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, - 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xFA, 0x33, 0x80, 0x00, 0x00, - - 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x04, 0x00, - - 0x78, 0x19, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, - 0x68, 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, - 0x6C, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - - 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E, - 0x75, 0x73, - 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - - 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E, 0x75, - 0x73, - 0xFA, 0x38, 0x00, 0x00, 0x00, - - 0x6E, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, - 0x6E, 0x67, 0x6C, 0x65, - 0xFA, 0x7F, 0x7F, 0xFF, 0xFF, - - 0x73, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, - 0x6E,0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, - - 0x73, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, - 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - - 0x6F, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, - 0xFA, 0x00, 0x80, 0x00, 0x00, - - 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - - 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75, - 0x73, - 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - - 0x78, 0x1A, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, - 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, - 0x75, 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x65, - 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x03, - 0xF9, 0xC0, 0x00, - - 0x70, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x72, 0x65, - 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xFA, 0x4B, 0x80, 0x00, 0x00, - - 0x78, 0x1A, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x73, 0x73, - 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - - 0x01, - 0x63, 0x66, 0x69, 0x6E -}; - - -/* - Makes a double from a uint64_t by copying the bits, not - by converting the value. - */ -#define MAKE_DOUBLE(x) UsefulBufUtil_CopyUint64ToDouble(x) - - -int32_t DoubleAsSmallestTest(void) -{ - UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, sizeof(spExpectedSmallest)); - - QCBOREncodeContext EC; - QCBOREncode_Init(&EC, EncodedHalfsMem); - QCBOREncode_OpenMap(&EC); - - // Many of these are from - // https://en.wikipedia.org/wiki/Half-precision_floating-point_format - // and - // https://en.wikipedia.org/wiki/Single-precision_floating-point_format - - // F9 0000 # primitive(0) - QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00); - - // F9 8000 # primitive(0) - QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00); - - // F9 7C00 # primitive(31744) - QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY); - - // F9 FC00 # primitive(64512) - QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY); - - // F9 7E00 # primitive(32256) - QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN); - - // TODO: test a few NaN variants - - // F9 3C00 # primitive(15360) - QCBOREncode_AddDoubleToMap(&EC, "one", 1.0); - - // F9 3555 # primitive(13653) - QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125); - - // 65504.0, converts to the large possible half-precision. - // 0xF9, 0x7B, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, "largest half-precision", 65504.0); - - // 65504.1, the double that has both to large an exponent and too - // much precision, so no conversion. - // 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, - QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one", 65504.1); - - // 65536.0 has an exponent of 16, which is larger than 15, the - // largest half-precision exponent. It is the exponent, not - // precision loss that prevents conversion to half. It does convert - // to single precision. - // 0xFA, 0x47, 0x80, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0); - - // 5.9604644775390625E-8, the smallest possible half-precision - // subnormal, digitis are lost converting to half, but not - // when converting to a single - // 0xFA, 0x33, 0x80, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest half subnormal", - MAKE_DOUBLE(0x3e70000000000000)); - - // 0.00006103515625, the double value that converts to the smallest - // possible half-precision normal. which is what should appear in - // the output. - // 0xF9, 0x04, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest half normal", - MAKE_DOUBLE(0x3f10000000000000)); - - // 0.000061035156250000014 ,the double value that is a tiny bit - // greater than smallest possible half-precision normal. It will be - // output as a double because converting it will reduce precision. - // 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - QCBOREncode_AddDoubleToMap(&EC, - "smallest half normal plus", - MAKE_DOUBLE(0x3f10000000000001)); - - // 0.000061035156249999993, the double value that is a tiny bit - // smaller than the smallest half-precision normal. This will fail - // to convert to a half-precision because both the exponent is too - // small and the precision is too large for a half-precision. - // 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, - "smallest normal minus", - MAKE_DOUBLE(0x3f0fffffffffffff)); - - // 0.000030517578125, the double value that is too small to fit - // into a half-precision because the exponent won't fit, not - // because precision would be lost. (This would fit into a - // half-precision subnormal, but there is no converstion to - // that). This ends up encoded as a single-precision. - // 0xFA, 0x38, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest normal minus", - MAKE_DOUBLE(0x3f00000000000000)); - - // 3.4028234664e38, the value that converts to the largest possible - // single-precision. - // 0xFA, 0x7F, 0x7F, 0xFF, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, - "largest single", - MAKE_DOUBLE(0x47efffffe0000000)); - - // 3.402823466385289E38, sightly larger than the largest possible - // possible precision. Conversion fails because precision would be - // lost. - // 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, - QCBOREncode_AddDoubleToMap(&EC, - "largest single plus", - MAKE_DOUBLE(0x47efffffe0000001)); - - // 6.8056469327705772E38, slightly more larger than the largers - // possible single precision. Conversion fails because exponent is - // too large. - // 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "largest single plus", - MAKE_DOUBLE(0x47ffffffe0000000)); - - // 1.1754943508222875E-38, The double value that converts to the - // smallest possible single-precision normal - // 0xFA, 0x00, 0x80, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single", - MAKE_DOUBLE(0x3810000000000000)); - - // 1.1754943508222878E-38, double value that is slightly larger - // than the smallest single-precision normal. Conversion fails - // because of precision - // 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single plus", - MAKE_DOUBLE(0x3810000000000001)); - - // 1.1754943508222874E-38, slightly smaller than the smallest - // single-precision normal. Conversion fails because of precision - // 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single minus", - MAKE_DOUBLE(0x380fffffffffffff)); - - // 5.8774717541114375E-39, slightly smaller than the smallest - // single-precision normal. Conversion fails because the exponent - // is too small. - // 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single minus more", - MAKE_DOUBLE(0x3800000000000000)); - - // Just -2, which converts to a negative half-precision - // F9 C000 # primitive(49152) - QCBOREncode_AddDoubleToMapN(&EC, 3, -2.0); - - // 16777216, No precision loss converting to single - // FA 4B800000 # primitive(1266679808) - QCBOREncode_AddDoubleToMap(&EC, "single precision", 16777216); - - // 16777217, One more than above. Too much precision for a single - // so no conversion. - // 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, "single with precision loss", 16777217); - - // Just a convenient marker when cutting and pasting encoded CBOR - QCBOREncode_AddSZStringToMapN(&EC, 1, "fin"); - - QCBOREncode_CloseMap(&EC); - - UsefulBufC EncodedHalfs; - QCBORError uErr = QCBOREncode_Finish(&EC, &EncodedHalfs); - if(uErr) { - return -1; - } - - if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) { - return -3; + QCBORItem Item; + QCBORDecodeContext DC; + unsigned char pbHalfBytes[2]; + uint8_t uHalfPrecInitialByte; + double d; + UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3); + UsefulOutBuf UOB; + uint32_t uHalfP; + + + for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) { + pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff); + pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */ + d = decode_half(pbHalfBytes); + + /* Construct the CBOR for the half-precision float by hand */ + UsefulOutBuf_Init(&UOB, EncodedBytes); + + uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */ + UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */ + UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */ + + /* Now parse the hand-constructed CBOR. This will invoke the + * conversion to a float + */ + QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return -1; + } + + if(isnan(d)) { + /* The RFC code uses the native instructions which may or may not + * handle sNaN, qNaN and NaN payloads correctly. This test just + * makes sure it is a NaN and doesn't worry about the type of NaN + */ + if(!isnan(Item.val.dfnum)) { + return -3; + } + } else { + if(Item.val.dfnum != d) { + return -2; + } + } } - return 0; } + #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ @@ -700,17 +683,27 @@ static const uint8_t spExpectedFloatsNoHalf[] = { 0x18, 0x6A, 0xFA, 0x00, 0x00, 0x00, 0x00}; -int32_t GeneralFloatEncodeTests(void) + +/* Public function. See float_tests.h */ +int32_t +GeneralFloatEncodeTests(void) { + /* See FloatNumberTests() for tests that really cover lots of float values. + * Add new tests for new values or decode modes there. + * This test is primarily to cover all the float encode methods. */ + + UsefulBufC Encoded; UsefulBufC ExpectedFloats; + QCBORError uErr; + #ifndef QCBOR_DISABLE_PREFERRED_FLOAT UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats)); ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats); - (void)spExpectedFloatsNoHalf; // Avoid unused variable error + (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */ #else UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf)); ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf); - (void)spExpectedFloats; // Avoid unused variable error + (void)spExpectedFloats; /* Avoid unused variable error */ #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ QCBOREncodeContext EC; @@ -744,8 +737,7 @@ int32_t GeneralFloatEncodeTests(void) QCBOREncode_CloseMap(&EC); QCBOREncode_CloseArray(&EC); - UsefulBufC Encoded; - QCBORError uErr = QCBOREncode_Finish(&EC, &Encoded); + uErr = QCBOREncode_Finish(&EC, &Encoded); if(uErr) { return -1; } @@ -757,25 +749,15 @@ int32_t GeneralFloatEncodeTests(void) return 0; } - -/* returns 0 if equivalent, non-zero if not equivalent */ -static int CHECK_EXPECTED_DOUBLE(double val, double expected) -{ - double diff = val - expected; - - diff = fabs(diff); - - if(diff > 0.000001) { - return 1; - } else { - return 0; - } -} #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ -int32_t GeneralFloatDecodeTests(void) +/* Public function. See float_tests.h */ +int32_t +GeneralFloatDecodeTests(void) { + /* See FloatNumberTests() for tests that really cover lots of float values */ + QCBORItem Item; QCBORError uErr; QCBORDecodeContext DC; @@ -872,10 +854,10 @@ int32_t GeneralFloatDecodeTests(void) #ifndef USEFULBUF_DISABLE_ALL_FLOAT #ifndef QCBOR_DISABLE_FLOAT_HW_USE || Item.uDataType != QCBOR_TYPE_DOUBLE - || CHECK_EXPECTED_DOUBLE(3.14, Item.val.dfnum) + || 3.1400001049041748 != Item.val.dfnum #else /* QCBOR_DISABLE_FLOAT_HW_USE */ || Item.uDataType != QCBOR_TYPE_FLOAT - || CHECK_EXPECTED_DOUBLE(3.14, Item.val.fnum) + || 3.140000f != Item.val.fnum #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ #else /* USEFULBUF_DISABLE_ALL_FLOAT */ || Item.uDataType != QCBOR_TYPE_NONE @@ -893,7 +875,7 @@ int32_t GeneralFloatDecodeTests(void) || Item.val.dfnum != 0.0 #else /* QCBOR_DISABLE_FLOAT_HW_USE */ || Item.uDataType != QCBOR_TYPE_FLOAT - || Item.val.fnum != 0.0 + || Item.val.fnum != 0.0f #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ #else /* USEFULBUF_DISABLE_ALL_FLOAT */ || Item.uDataType != QCBOR_TYPE_NONE diff --git a/3rdparty/exported/QCBOR/test/float_tests.h b/3rdparty/exported/QCBOR/test/float_tests.h index 54daa3fdd3a9..cfc2e6ecd6ab 100644 --- a/3rdparty/exported/QCBOR/test/float_tests.h +++ b/3rdparty/exported/QCBOR/test/float_tests.h @@ -1,11 +1,11 @@ /*============================================================================== - float_tests.h -- tests for float and conversion to/from half-precision + float_tests.h -- tests for floats and conversion to/from half-precision - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. + Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/19/18 =============================================================================*/ @@ -17,22 +17,35 @@ #ifndef QCBOR_DISABLE_PREFERRED_FLOAT -int32_t HalfPrecisionDecodeBasicTests(void); - -int32_t DoubleAsSmallestTest(void); - +/* This tests a large number half-precision values + * in the conversion to/from half/double against + * the sample code in the CBOR RFC. */ int32_t HalfPrecisionAgainstRFCCodeTest(void); #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ + +/* + * This tests floating point encoding, decoding + * and conversion for lots of different values. + * It covers Preferred Serialization processing + * of floating point. It's focus is on the numbers + * not the encode/decode functions. + */ +int32_t FloatValuesTests(void); + + /* - This calls each and every method for encoding - floating-point numbers. + * This calls each and every method for encoding + * floating-point numbers. */ int32_t GeneralFloatEncodeTests(void); + /* - Tests basic float decoding. + * Tests float decoding, including error codes in scenarios + * where various float features are disabled. This also + * tests decoding using spiffy decode methods. */ int32_t GeneralFloatDecodeTests(void); diff --git a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c index d4fded63c440..9b7aeaabf832 100644 --- a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c +++ b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c @@ -36,7 +36,7 @@ #include #ifndef USEFULBUF_DISABLE_ALL_FLOAT -double decode_half(unsigned char *halfp) { +double decode_half(const unsigned char *halfp) { int half = (halfp[0] << 8) + halfp[1]; int exp = (half >> 10) & 0x1f; int mant = half & 0x3ff; diff --git a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h index 6318f8027c6a..aa3b4c35b0ca 100644 --- a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h +++ b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h @@ -6,7 +6,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/23/18 ============================================================================*/ @@ -15,7 +15,7 @@ #define half_to_double_from_rfc7049_h #ifndef USEFULBUF_DISABLE_ALL_FLOAT -double decode_half(unsigned char *halfp); +double decode_half(const unsigned char *halfp); #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ #endif /* half_to_double_from_rfc7049_h */ diff --git a/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h b/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h index e50588716720..c3257686854f 100644 --- a/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h +++ b/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h @@ -7,7 +7,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 7/27/19 ==============================================================================*/ @@ -159,9 +159,10 @@ static const struct someBinaryBytes paNotWellFormedCBOR[] = { {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, // Array of length 1 with 2nd member value replaced by a break {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, - // Map of length 2 with 2nd member replaced by a break - {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4}, - + // Map of length 2 with 2nd entry label replaced by a break + {(uint8_t[]){0xa2, 0x00, 0x00, 0xff, 0x00}, 5}, + // Map of length 2 with 2nd entry value replaced by a break + {(uint8_t[]){0xa2, 0x00, 0x00, 0x00, 0xff}, 5}, // Breaks must not occur on their own out of an indefinite length // data item diff --git a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c index e913854d7a3d..910d43af7efc 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c +++ b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c @@ -1,12 +1,12 @@ /*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * 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 @@ -63,6 +63,22 @@ static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf) } #endif /* PRINT_FUNCTIONS_FOR_DEBUGGING */ + +/* Make a test results code that includes three components. Return code + * is xxxyyyzzz where zz is the error code, yy is the test number and + * zz is check being performed + */ +static int32_t +MakeTestResultCode(uint32_t uTestCase, + uint32_t uTestNumber, + QCBORError uErrorCode) +{ + uint32_t uCode = (uTestCase * 1000000) + + (uTestNumber * 1000) + + (uint32_t)uErrorCode; + return (int32_t)uCode; +} + /* [ -9223372036854775808, @@ -1011,7 +1027,7 @@ int32_t ParseTooDeepArrayTest(void) UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL); - for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) { + for(i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) { if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY || @@ -1081,6 +1097,49 @@ int32_t ShortBufferParseTest2(void) return(nReturn); } + +/* This test requires indef strings, HW float and preferred float,... */ +#if !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) && \ + !defined(QCBOR_DISABLE_FLOAT_HW_USE) && \ + !defined(QCBOR_DISABLE_PREFERRED_FLOAT) && \ + !defined(QCBOR_DISABLE_TAGS) && \ + !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) + +static const uint8_t pPerverseLabels[] = { + 0xae, + + 0xf5, 0x61, 0x61, + + 0xf6, 0x61, 0x62, + + 0xf8, 0xff, 0x61, 0x63, + + 0xf9, 0x7e, 0x00, 0x61, 0x64, + + 0xfa, 0x7f, 0x7f, 0xff, 0xff, 0x61, 0x65, + + 0xfb, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x66, + + 0xa1, 0x19, 0x03, 0xe8, 0x10, 0x61, 0x67, + + 0x81, 0x81, 0x81, 0x80, 0x61, 0x68, + + 0xc1, 0x09, 0x61, 0x69, + + 0x82, 0x05, 0xa2, 0x01, 0x02, 0x03, 0x04, 0x61, 0x6a, + + 0xbf, 0xff, 0x61, 0x6b, + + 0x9f, 0x11, 0x12, 0x13, 0xff, 0x61, 0x6c, + + 0x7f, 0x62, 0x41, 0x42, 0x62, 0x43, 0x44, 0xff, 0x61, 0x6d, + + 0xd9, 0x01, 0x02, 0xbf, 0x7f, 0x61, 0x4a, 0x61, 0x4b, 0xff, 0x00, 0xf4, 0xd7, 0x80 ,0xff, 0x61, 0x6e +}; +#endif + + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS /* Decode and thoroughly check a moderately complex set of maps. Can be run in QCBOR_DECODE_MODE_NORMAL or in @@ -1208,6 +1267,39 @@ static int32_t ParseMapTest1(QCBORDecodeMode nMode) return 0; } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + +/* This test requires indef strings, HW float and preferred float,... */ +#if !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) && \ + !defined(QCBOR_DISABLE_FLOAT_HW_USE) && \ + !defined(QCBOR_DISABLE_PREFERRED_FLOAT) && \ + !defined(QCBOR_DISABLE_TAGS) && \ + !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) + +/* Utility to decode a one byte string and match to letter. */ +static QCBORError +CheckOneLetterString(QCBORDecodeContext *pDecode, uint8_t letter) +{ + UsefulBufC Text; + QCBORError uErr; + + QCBORDecode_GetTextString(pDecode, &Text); + uErr = QCBORDecode_GetError(pDecode); + if(uErr) { + return uErr; + } + + if(Text.len != 1) { + return QCBOR_ERR_FIRST_USER_DEFINED; + } + + if(*(const uint8_t *)Text.ptr != letter) { + return QCBOR_ERR_FIRST_USER_DEFINED; + } + + return QCBOR_SUCCESS; +} +#endif /* @@ -1217,23 +1309,23 @@ static int32_t ParseMapTest1(QCBORDecodeMode nMode) int32_t ParseMapAsArrayTest(void) { QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + QCBORItem Item; + QCBORError uErr; QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return MakeTestResultCode(1, 1, uErr); } if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || Item.val.uCount != 6) { return -1; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || Item.uDataAlloc || @@ -1243,8 +1335,8 @@ int32_t ParseMapAsArrayTest(void) return -2; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_INT64 || @@ -1254,8 +1346,8 @@ int32_t ParseMapAsArrayTest(void) return -3; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1265,8 +1357,8 @@ int32_t ParseMapAsArrayTest(void) return -4; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1276,8 +1368,8 @@ int32_t ParseMapAsArrayTest(void) return -5; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || Item.val.string.len != 7 || @@ -1287,8 +1379,8 @@ int32_t ParseMapAsArrayTest(void) return -6; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || Item.uDataAlloc || @@ -1298,8 +1390,8 @@ int32_t ParseMapAsArrayTest(void) } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1308,8 +1400,8 @@ int32_t ParseMapAsArrayTest(void) return -8; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1319,8 +1411,8 @@ int32_t ParseMapAsArrayTest(void) return -9; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || UsefulBufCompareToSZ(Item.val.string, "bytes 1") || @@ -1330,8 +1422,8 @@ int32_t ParseMapAsArrayTest(void) return -10; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_BYTE_STRING || @@ -1341,8 +1433,8 @@ int32_t ParseMapAsArrayTest(void) return -11; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || UsefulBufCompareToSZ(Item.val.string, "bytes 2") || @@ -1352,8 +1444,8 @@ int32_t ParseMapAsArrayTest(void) return -12; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_BYTE_STRING || @@ -1363,8 +1455,8 @@ int32_t ParseMapAsArrayTest(void) return -13; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1374,8 +1466,8 @@ int32_t ParseMapAsArrayTest(void) return -14; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1385,8 +1477,8 @@ int32_t ParseMapAsArrayTest(void) return -15; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || UsefulBufCompareToSZ(Item.val.string, "text 2") || @@ -1396,8 +1488,8 @@ int32_t ParseMapAsArrayTest(void) return -16; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_TEXT_STRING || @@ -1423,7088 +1515,9115 @@ int32_t ParseMapAsArrayTest(void) return -50; } - // TODO: test decoding of labels that are arrays or such - // TODO: test spiffy decoding of QCBOR_DECODE_MODE_MAP_AS_ARRAY - - return 0; -} - + /* This test requires indef strings, HW float and preferred float,... */ +#if !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) && \ + !defined(QCBOR_DISABLE_FLOAT_HW_USE) && \ + !defined(QCBOR_DISABLE_PREFERRED_FLOAT) && \ + !defined(QCBOR_DISABLE_TAGS) && \ + !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) -/* - Fully or partially decode pValidMapEncoded. When - partially decoding check for the right error code. - How much partial decoding depends on nLevel. - - The partial decodes test error conditions of - incomplete encoded input. - - This could be combined with the above test - and made prettier and maybe a little more - thorough. - */ -static int32_t ExtraBytesTest(int nLevel) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + UsefulBufC Encoded; + /* Big decode of a map with a wide variety or labels */ QCBORDecode_Init(&DCtx, - (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, - QCBOR_DECODE_MODE_NORMAL); + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pPerverseLabels), + QCBOR_DECODE_MODE_MAP_AS_ARRAY); + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); - if(nLevel < 1) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { - return -1; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 1, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY) { + return MakeTestResultCode(10, 2, 0); } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 3, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TRUE) { + return MakeTestResultCode(10, 4, 0); } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) - return -2; - if(nLevel < 2) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -3; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 5, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'a') { + return MakeTestResultCode(10, 6, 0); } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 7, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_NULL) { + return MakeTestResultCode(10, 8, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 9, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.uCount != 42 || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return -4; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'b') { + return MakeTestResultCode(10, 10, 0); } - if(nLevel < 3) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -5; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 11, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || + Item.val.int64 != 255) { + return MakeTestResultCode(10, 12, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 13, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return -6; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'c') { + return MakeTestResultCode(10, 14, 0); } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 15, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DOUBLE || + !isnan(Item.val.dfnum)) { + return MakeTestResultCode(10, 16, 0); + } - if(nLevel < 4) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -7; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 17, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'd') { + return MakeTestResultCode(10, 18, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 19, uErr); } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return -8; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DOUBLE || + Item.val.dfnum != 3.4028234663852886E+38) { + return MakeTestResultCode(10, 20, 0); } - if(nLevel < 5) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -9; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 21, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'e') { + return MakeTestResultCode(10, 22, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 23, uErr); } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return -10; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DOUBLE || + Item.val.dfnum != -INFINITY) { + return MakeTestResultCode(10, 24, 0); } - if(nLevel < 6) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -11; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 25, uErr); } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'f') { + return MakeTestResultCode(10, 26, 0); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "map in a map") || - Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 4) - return -12; - if(nLevel < 7) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -13; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 26, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != 2) { + return MakeTestResultCode(10, 27, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 28, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 1") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - UsefulBufCompareToSZ(Item.val.string, "xxxx")) { - return -14; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 1000) { + return MakeTestResultCode(10, 29, 0); } - if(nLevel < 8) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -15; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 30, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 16) { + return MakeTestResultCode(10, 31, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 32, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 2") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - UsefulBufCompareToSZ(Item.val.string, "yyyy")) { - return -16; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'g') { + return MakeTestResultCode(10, 33, 0); } - if(nLevel < 9) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -17; - } else { - return 0; + for(int i = 0 ; i < 4; i++) { + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 34, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY) { + return MakeTestResultCode(10, 35, 0); + } + if(i != 3) { + if(Item.val.uCount != 1) { + return MakeTestResultCode(10, 35, 0); + } } } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 36, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'h') { + return MakeTestResultCode(10, 37, 0); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "another int") || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) - return -18; - if(nLevel < 10) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -19; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 38, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DATE_EPOCH) { + return MakeTestResultCode(10, 39, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 40, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { - return -20; + ((const char *)Item.val.string.ptr)[0] != 'i') { + return MakeTestResultCode(10, 41, 0); } - if(QCBORDecode_Finish(&DCtx)) { - return -21; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 42, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return MakeTestResultCode(10, 31, 0); } - return 0; -} + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 43, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64) { + return MakeTestResultCode(10, 31, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 44, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != 4) { + return MakeTestResultCode(10, 45, 0); + } + for(int i = 0 ; i < 4; i++) { + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 46, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64) { + return MakeTestResultCode(10, 47, 0); + } + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 48, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'j') { + return MakeTestResultCode(10, 49, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 50, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(10, 51, 0); + } -int32_t ParseMapTest(void) -{ - // Parse a moderatly complex map structure very thoroughly - int32_t nResult = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); - if(nResult) { - return nResult; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 52, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'k') { + return MakeTestResultCode(10, 53, 0); } - // Again, but in strings-only mode. It should succeed since the input - // map has only string labels. - nResult = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); - if(nResult) { - return nResult; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 54, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(10, 55, 0); } - // Again, but try to finish the decoding before the end of the - // input at 10 different place and see that the right error code - // is returned. - for(int i = 0; i < 10; i++) { - nResult = ExtraBytesTest(i); - if(nResult) { - break; + for(int i = 0 ; i < 3; i++) { + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 56, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64) { + return MakeTestResultCode(10, 57, 0); } } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 58, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'l') { + return MakeTestResultCode(10, 59, 0); + } - return nResult; -} - + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 60, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.len != 4) { + return MakeTestResultCode(10, 61, 0); + } -/* The simple-values including some not well formed */ -static const uint8_t spSimpleValues[] = { - 0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, - 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, - 0xf8, 0xff}; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 62, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'm') { + return MakeTestResultCode(10, 63, 0); + } -int32_t ParseSimpleTest(void) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 64, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 258) || + Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(10, 65, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 66, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.len != 2) { + return MakeTestResultCode(10, 67, 0); + } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), - QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 68, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 0) { + return MakeTestResultCode(10, 69, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 70, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_FALSE) { + return MakeTestResultCode(10, 71, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 10) - return -1; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 72, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 23) || + Item.val.uCount != 0) { + return MakeTestResultCode(10, 73, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_FALSE) - return -1; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 74, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'n') { + return MakeTestResultCode(10, 75, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_TRUE) - return -1; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_NULL) - return -1; + /* Big decode of a map with a wide variety or labels */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pPerverseLabels), + QCBOR_DECODE_MODE_MAP_AS_ARRAY); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UNDEF) - return -1; + QCBORDecode_EnterArray(&DCtx, &Item); + bool b; + QCBORDecode_GetBool(&DCtx, &b); - // A break - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) - return -1; + uErr = CheckOneLetterString(&DCtx, 'a'); + if(uErr) { + return MakeTestResultCode(11, 1, uErr); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) - return -1; + QCBORDecode_GetNull(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'b'); + if(uErr) { + return MakeTestResultCode(11, 2, uErr); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) - return -1; + QCBORDecode_VGetNext(&DCtx, &Item); + uErr = CheckOneLetterString(&DCtx, 'c'); + if(uErr) { + return MakeTestResultCode(11, 3, uErr); + } - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) - return -1; + double dNum; + QCBORDecode_GetDouble(&DCtx, &dNum); + if(!isnan(dNum)) { + return MakeTestResultCode(11, 4, 0); + } + uErr = CheckOneLetterString(&DCtx, 'd'); + if(uErr) { + return MakeTestResultCode(11, 5, uErr); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) - return -1; + QCBORDecode_GetDouble(&DCtx, &dNum); + if( dNum != 3.4028234663852886E+38 ) { + return MakeTestResultCode(11, 6, 0); + } + uErr = CheckOneLetterString(&DCtx, 'e'); + if(uErr) { + return MakeTestResultCode(11, 7, uErr); + } - return 0; + QCBORDecode_GetDouble(&DCtx, &dNum); + if(dNum != -INFINITY) { + return MakeTestResultCode(11, 8, 0); + } + uErr = CheckOneLetterString(&DCtx, 'f'); + if(uErr) { + return MakeTestResultCode(11, 9, uErr); + } -} + int64_t nInt; + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'g'); + if(uErr) { + return MakeTestResultCode(11, 10, uErr); + } + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'h'); + if(uErr) { + return MakeTestResultCode(11, 11, uErr); + } + QCBORDecode_GetEpochDate(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &nInt); + uErr = CheckOneLetterString(&DCtx, 'i'); + if(uErr) { + return MakeTestResultCode(11, 12, uErr); + } -int32_t NotWellFormedTests(void) -{ - // Loop over all the not-well-formed instance of CBOR - // that are test vectors in not_well_formed_cbor.h - const uint16_t nArraySize = C_ARRAY_COUNT(paNotWellFormedCBOR, - struct someBinaryBytes); - for(uint16_t nIterate = 0; nIterate < nArraySize; nIterate++) { - const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate]; - const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n}; + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'j'); + if(uErr) { + return MakeTestResultCode(11, 13, uErr); + } - if(nIterate == 86) { - nIterate = 86; - } + QCBORDecode_GetArray(&DCtx, &Item, &Encoded); + uErr = CheckOneLetterString(&DCtx, 'k'); + if(uErr) { + return MakeTestResultCode(11, 14, uErr); + } - // Set up decoder context. String allocator needed for indefinite - // string test cases - QCBORDecodeContext DCtx; - QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORDecode_SetMemPool(&DCtx, Pool, 0); -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'l'); + if(uErr) { + return MakeTestResultCode(11, 15, uErr); + } - // Loop getting items until no more to get - QCBORError uCBORError; - do { - QCBORItem Item; + QCBORDecode_GetTextString(&DCtx, &Encoded); + uErr = CheckOneLetterString(&DCtx, 'm'); + if(uErr) { + return MakeTestResultCode(11, 16, uErr); + } - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - } while(uCBORError == QCBOR_SUCCESS); + QCBORDecode_EnterArray(&DCtx, &Item); + if(!QCBORDecode_IsTagged(&DCtx, &Item, 258)) { + return MakeTestResultCode(11, 17, 0); + } + if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY) { + return MakeTestResultCode(11, 18, 0); + } + if(Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(11, 19, 0); + } + QCBORDecode_GetTextString(&DCtx, &Encoded); + if(Encoded.len != 2) { + return MakeTestResultCode(11, 20, 0); + } QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetBool(&DCtx, &b); + if(b != false) { + return MakeTestResultCode(11, 21, 0); + } + QCBORDecode_EnterArray(&DCtx, &Item); + if(!QCBORDecode_IsTagged(&DCtx, &Item, 23)) { + return MakeTestResultCode(11, 22, 0); + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return MakeTestResultCode(11, 23, 0); + } + if(Item.val.uCount != 0) { + return MakeTestResultCode(11, 24, 0); + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'n'); + if(uErr) { + return MakeTestResultCode(11, 25, uErr); + } - // Every test vector must fail with - // a not-well-formed error. If not - // this test fails. - if(!QCBORDecode_IsNotWellFormedError(uCBORError) && - uCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - /* Return index of failure and QCBOR error in the result */ - return (int32_t)(nIterate * 100 + uCBORError); - } + QCBORDecode_ExitArray(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr) { + return MakeTestResultCode(11, 26, uErr); } +#endif /* QCBOR_DISABLE_... */ + return 0; } -// TODO: add a test index and report it so it is eaier to figure out which test failed. -struct FailInput { - UsefulBufC Input; - QCBORError nError; -}; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS -static int32_t ProcessFailures(const struct FailInput *pFailInputs, size_t nNumFails) -{ - for(const struct FailInput *pF = pFailInputs; pF < pFailInputs + nNumFails; pF++) { - QCBORDecodeContext DCtx; - QCBORError uCBORError; +/* + Fully or partially decode pValidMapEncoded. When + partially decoding check for the right error code. + How much partial decoding depends on nLevel. - QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL); + The partial decodes test error conditions of + incomplete encoded input. -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - // Set up the decoding context including a memory pool so that - // indefinite length items can be checked - UsefulBuf_MAKE_STACK_UB(Pool, 100); + This could be combined with the above test + and made prettier and maybe a little more + thorough. + */ +static int32_t ExtraBytesTest(int nLevel) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError nCBORError; - uCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); - if(uCBORError) { - return -9; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + QCBORDecode_Init(&DCtx, + (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, + QCBOR_DECODE_MODE_NORMAL); - const size_t nIndexx = (size_t)(pF - pFailInputs); - if(nIndexx == 8) { - uCBORError = 9; + if(nLevel < 1) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { + return -1; + } else { + return 0; } + } - // Iterate until there is an error of some sort error - QCBORItem Item; - do { - // Set to something none-zero, something other than QCBOR_TYPE_NONE - memset(&Item, 0x33, sizeof(Item)); - - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - } while(uCBORError == QCBOR_SUCCESS); - - + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) + return -2; - // Must get the expected error or the this test fails - // The data and label type must also be QCBOR_TYPE_NONE - if(uCBORError != pF->nError || - Item.uDataType != QCBOR_TYPE_NONE || - Item.uLabelType != QCBOR_TYPE_NONE) { - // return index of CBOR + 100 - const size_t nIndex = (size_t)(pF - pFailInputs); - return (int32_t)(nIndex * 100 + uCBORError); + if(nLevel < 2) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -3; + } else { + return 0; } } - return 0; -} + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.uCount != 42 || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return -4; + } -static const struct FailInput Failures[] = { - // Most of this is copied from not_well_formed.h. Here the error code - // returned is also checked. + if(nLevel < 3) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -5; + } else { + return 0; + } + } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - // Indefinite length strings must be closed off - // An indefinite length byte string not closed off - { {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, QCBOR_ERR_HIT_END }, - // An indefinite length text string not closed off - { {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, QCBOR_ERR_HIT_END }, - - - // All the chunks in an indefinite length string must be of the type of - // indefinite length string - // indefinite length byte string with text string chunk - { {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length text string with a byte string chunk - { {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an positive integer chunk - { {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an negative integer chunk - { {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an array chunk - { {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an map chunk - { {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, -#ifndef QCBOR_DISABLE_TAGS - // indefinite length byte string with tagged integer chunk - { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, -#else - // indefinite length byte string with tagged integer chunk - { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ - // indefinite length byte string with an simple type chunk - { {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - { {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK}, - // indefinite length text string with indefinite string inside - { {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK}, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return -6; + } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - { {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // An indefinite length text string not closed off - { {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - - - // All the chunks in an indefinite length string must be of the type of - // indefinite length string - // indefinite length byte string with text string chunk - { {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length text string with a byte string chunk - { {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an positive integer chunk - { {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an negative integer chunk - { {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an array chunk - { {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an map chunk - { {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with tagged integer chunk - { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an simple type chunk - { {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - { {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED}, - // indefinite length text string with indefinite string inside - { {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED}, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + if(nLevel < 4) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -7; + } else { + return 0; + } + } - // Definte length maps and arrays must be closed by having the right number of items - // A definte length array that is supposed to have 1 item, but has none - { {(uint8_t[]){0x81}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // A definte length array that is supposed to have 2 items, but has only 1 - { {(uint8_t[]){0x82, 0x00}, 2}, QCBOR_ERR_NO_MORE_ITEMS }, - // A definte length array that is supposed to have 511 items, but has only 1 - { {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4}, QCBOR_ERR_HIT_END }, - // A definte length map that is supposed to have 1 item, but has none - { {(uint8_t[]){0xa1}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // A definte length map that is supposed to have s item, but has only 1 - { {(uint8_t[]){0xa2, 0x01, 0x02}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return -8; + } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // Indefinte length maps and arrays must be ended by a break - // Indefinite length array with zero items and no break - { {(uint8_t[]){0x9f}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // Indefinite length array with two items and no break - { {(uint8_t[]){0x9f, 0x01, 0x02}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, - // Indefinite length map with zero items and no break - { {(uint8_t[]){0xbf}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // Indefinite length map with two items and no break - { {(uint8_t[]){0xbf, 0x01, 0x02, 0x01, 0x02}, 5}, QCBOR_ERR_NO_MORE_ITEMS }, - - - // Nested maps and arrays must be closed off (some extra nested test vectors) - // Unclosed indefinite array containing a closed definite length array - { {(uint8_t[]){0x9f, 0x80, 0x00}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, - // Definite length array containing an unclosed indefinite length array - { {(uint8_t[]){0x81, 0x9f}, 2}, QCBOR_ERR_NO_MORE_ITEMS }, - // Unclosed indefinite map containing a closed definite length array - { {(uint8_t[]){0xbf, 0x01, 0x80, 0x00, 0xa0}, 5}, QCBOR_ERR_NO_MORE_ITEMS }, - // Definite length map containing an unclosed indefinite length array - { {(uint8_t[]){0xa1, 0x02, 0x9f}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, - // Deeply nested definite length arrays with deepest one unclosed - { {(uint8_t[]){0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81}, 9}, QCBOR_ERR_NO_MORE_ITEMS }, - // Deeply nested indefinite length arrays with deepest one unclosed - { {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_NO_MORE_ITEMS }, - // Mixed nesting with indefinite unclosed - { {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_NO_MORE_ITEMS }, - // Mixed nesting with definite unclosed - { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, - // Unclosed indefinite length map in definite length maps - { {(uint8_t[]){0xa1, 0x01, 0xa2, 0x02, 0xbf, 0xff, 0x02, 0xbf}, 8}, - QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed definite length map in indefinite length maps - { {(uint8_t[]){0xbf, 0x01, 0xbf, 0x02, 0xa1}, 5}, QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed indefinite length array in definite length maps - { {(uint8_t[]){0xa1, 0x01, 0xa2, 0x02, 0x9f, 0xff, 0x02, 0x9f}, 8}, - QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed definite length array in indefinite length maps - { {(uint8_t[]){0xbf, 0x01, 0xbf, 0x02, 0x81}, 5}, QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed indefinite length map in definite length arrays - { {(uint8_t[]){0x81, 0x82, 0xbf, 0xff, 0xbf}, 5}, QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed definite length map in indefinite length arrays - { {(uint8_t[]){0x9f, 0x9f, 0xa1}, 3}, QCBOR_ERR_NO_MORE_ITEMS}, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if(nLevel < 5) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -9; + } else { + return 0; + } + } - // The "argument" for the data item is incomplete - // Positive integer missing 1 byte argument - { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 2 byte argument - { {(uint8_t[]){0x19}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 4 byte argument - { {(uint8_t[]){0x1a}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 8 byte argument - { {(uint8_t[]){0x1b}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 1 byte of 2 byte argument - { {(uint8_t[]){0x19, 0x01}, 2}, QCBOR_ERR_HIT_END }, - // Positive integer missing 2 bytes of 4 byte argument - { {(uint8_t[]){0x1a, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END }, - // Positive integer missing 1 bytes of 7 byte argument - { {(uint8_t[]){0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8}, QCBOR_ERR_HIT_END }, - // Negative integer missing 1 byte argument - { {(uint8_t[]){0x38}, 1}, QCBOR_ERR_HIT_END }, - // Binary string missing 1 byte argument - { {(uint8_t[]){0x58}, 1}, QCBOR_ERR_HIT_END }, - // Text string missing 1 byte argument - { {(uint8_t[]){0x78}, 1}, QCBOR_ERR_HIT_END }, - // Array missing 1 byte argument - { {(uint8_t[]){0x98}, 1}, QCBOR_ERR_HIT_END }, - // Map missing 1 byte argument - { {(uint8_t[]){0xb8}, 1}, QCBOR_ERR_HIT_END }, - // Tag missing 1 byte argument - { {(uint8_t[]){0xd8}, 1}, QCBOR_ERR_HIT_END }, - // Simple missing 1 byte argument - { {(uint8_t[]){0xf8}, 1}, QCBOR_ERR_HIT_END }, - // half-precision with 1 byte argument - { {(uint8_t[]){0xf9, 0x00}, 2}, QCBOR_ERR_HIT_END }, - // single-precision with 2 byte argument - { {(uint8_t[]){0xfa, 0x00, 0x00}, 3}, QCBOR_ERR_HIT_END }, - // double-precision with 3 byte argument - { {(uint8_t[]){0xfb, 0x00, 0x00, 0x00}, 4}, QCBOR_ERR_HIT_END }, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return -10; + } -#ifndef QCBOR_DISABLE_TAGS - // Tag with no content - { {(uint8_t[]){0xc0}, 1}, QCBOR_ERR_HIT_END }, -#else /* QCBOR_DISABLE_TAGS */ - { {(uint8_t[]){0xc0}, 1}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ + if(nLevel < 6) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -11; + } else { + return 0; + } + } - // Breaks must not occur in definite length arrays and maps - // Array of length 1 with sole member replaced by a break - { {(uint8_t[]){0x81, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, - // Array of length 2 with 2nd member replaced by a break - { {(uint8_t[]){0x82, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Map of length 1 with sole member label replaced by a break - { {(uint8_t[]){0xa1, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, - // Map of length 1 with sole member label replaced by break - // Alternate representation that some decoders handle differently - { {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, QCBOR_ERR_BAD_BREAK }, - // Array of length 1 with 2nd member value replaced by a break - { {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Map of length 2 with 2nd member replaced by a break - { {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4}, QCBOR_ERR_BAD_BREAK }, - - - // Breaks must not occur on their own out of an indefinite length data item - // A bare break is not well formed - { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_BAD_BREAK }, - // A bare break after a zero length definite length array - { {(uint8_t[]){0x80, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // A bare break after a zero length indefinite length map - { {(uint8_t[]){0x9f, 0xff, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // A break inside a definite length array inside an indefenite length array - { {(uint8_t[]){0x9f, 0x81, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Complicated mixed nesting with break outside indefinite length array - { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "map in a map") || + Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 4) + return -12; + if(nLevel < 7) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -13; + } else { + return 0; + } + } - // Forbidden two byte encodings of simple types - // Must use 0xe0 instead - { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe1 instead - { {(uint8_t[]){0xf8, 0x01}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe2 instead - { {(uint8_t[]){0xf8, 0x02}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe3 instead - { {(uint8_t[]){0xf8, 0x03}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe4 instead - { {(uint8_t[]){0xf8, 0x04}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe5 instead - { {(uint8_t[]){0xf8, 0x05}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe6 instead - { {(uint8_t[]){0xf8, 0x06}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe7 instead - { {(uint8_t[]){0xf8, 0x07}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe8 instead - { {(uint8_t[]){0xf8, 0x08}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe9 instead - { {(uint8_t[]){0xf8, 0x09}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xea instead - { {(uint8_t[]){0xf8, 0x0a}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xeb instead - { {(uint8_t[]){0xf8, 0x0b}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xec instead - { {(uint8_t[]){0xf8, 0x0c}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xed instead - { {(uint8_t[]){0xf8, 0x0d}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xee instead - { {(uint8_t[]){0xf8, 0x0e}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xef instead - { {(uint8_t[]){0xf8, 0x0f}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xf0 instead - { {(uint8_t[]){0xf8, 0x10}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xf1 instead - { {(uint8_t[]){0xf8, 0x11}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xf2 instead - { {(uint8_t[]){0xf8, 0x12}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf3 instead - { {(uint8_t[]){0xf8, 0x13}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf4 instead - { {(uint8_t[]){0xf8, 0x14}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf5 instead - { {(uint8_t[]){0xf8, 0x15}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf6 instead - { {(uint8_t[]){0xf8, 0x16}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf7 instead - { {(uint8_t[]){0xf8, 0x17}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf8 instead - { {(uint8_t[]){0xf8, 0x18}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Reserved - { {(uint8_t[]){0xf8, 0x1f}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - - // Integers with additional info indefinite length - // Positive integer with additional info indefinite length - { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_BAD_INT }, - // Negative integer with additional info indefinite length - { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_BAD_INT }, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 1") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + UsefulBufCompareToSZ(Item.val.string, "xxxx")) { + return -14; + } -#ifndef QCBOR_DISABLE_TAGS - // CBOR tag with "argument" an indefinite length - { {(uint8_t[]){0xdf, 0x00}, 2}, QCBOR_ERR_BAD_INT }, - // CBOR tag with "argument" an indefinite length alternate vector - { {(uint8_t[]){0xdf}, 1}, QCBOR_ERR_BAD_INT }, -#else /* QCBOR_DISABLE_TAGS */ - { {(uint8_t[]){0xdf, 0x00}, 2}, QCBOR_ERR_TAGS_DISABLED }, - { {(uint8_t[]){0xdf}, 1}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ + if(nLevel < 8) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -15; + } else { + return 0; + } + } - // Missing bytes from a deterministic length string - // A byte string is of length 1 without the 1 byte - { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END }, - // A text string is of length 1 without the 1 byte - { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END }, - -#if SIZE_MAX > 2147483647 - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^64 bytes, but has 3 - { {(uint8_t[]){0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, - // Text string should have 2^64 bytes, but has 3 - { {(uint8_t[]){0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, -#else - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x5a, 0x00, 0x00, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x7a, 0x00, 0x00, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^16 bytes, but has 3 - { {(uint8_t[]){0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, - // Text string should have 2^64 bytes, but has 3 - { {(uint8_t[]){0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, -#endif + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 2") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + UsefulBufCompareToSZ(Item.val.string, "yyyy")) { + return -16; + } - // Use of unassigned additional information values - // Major type positive integer with reserved value 28 - { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type positive integer with reserved value 29 - { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type positive integer with reserved value 30 - { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type negative integer with reserved value 28 - { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type negative integer with reserved value 29 - { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type negative integer with reserved value 30 - { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type byte string with reserved value 28 length - { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type byte string with reserved value 29 length - { {(uint8_t[]){0x5d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type byte string with reserved value 30 length - { {(uint8_t[]){0x5e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type text string with reserved value 28 length - { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type text string with reserved value 29 length - { {(uint8_t[]){0x7d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type text string with reserved value 30 length - { {(uint8_t[]){0x7e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type array with reserved value 28 length - { {(uint8_t[]){0x9c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type array with reserved value 29 length - { {(uint8_t[]){0x9d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type array with reserved value 30 length - { {(uint8_t[]){0x9e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type map with reserved value 28 length - { {(uint8_t[]){0xbc}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type map with reserved value 29 length - { {(uint8_t[]){0xbd}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type map with reserved value 30 length - { {(uint8_t[]){0xbe}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type tag with reserved value 28 length - { {(uint8_t[]){0xdc}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type tag with reserved value 29 length - { {(uint8_t[]){0xdd}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type tag with reserved value 30 length - { {(uint8_t[]){0xde}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type simple with reserved value 28 length - { {(uint8_t[]){0xfc}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type simple with reserved value 29 length - { {(uint8_t[]){0xfd}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type simple with reserved value 30 length - { {(uint8_t[]){0xfe}, 1}, QCBOR_ERR_UNSUPPORTED }, - - - // Maps must have an even number of data items (key & value) - // Map with 1 item when it should have 2 - { {(uint8_t[]){0xa1, 0x00}, 2}, QCBOR_ERR_HIT_END }, - // Map with 3 item when it should have 4 - { {(uint8_t[]){0xa2, 0x00, 0x00, 0x00}, 2}, QCBOR_ERR_HIT_END }, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // Map with 1 item when it should have 2 - { {(uint8_t[]){0xbf, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Map with 3 item when it should have 4 - { {(uint8_t[]){0xbf, 0x00, 0x00, 0x00, 0xff}, 5}, QCBOR_ERR_BAD_BREAK }, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if(nLevel < 9) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -17; + } else { + return 0; + } + } -#ifndef QCBOR_DISABLE_TAGS - // In addition to not-well-formed, some invalid CBOR - // Text-based date, with an integer - { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, - // Epoch date, with an byte string - { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, - // tagged as both epoch and string dates - { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, - // big num tagged an int, not a byte string - { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, -#else /* QCBOR_DISABLE_TAGS */ - // Text-based date, with an integer - { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_TAGS_DISABLED }, - // Epoch date, with an byte string - { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_TAGS_DISABLED }, - // tagged as both epoch and string dates - { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_TAGS_DISABLED }, - // big num tagged an int, not a byte string - { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "another int") || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) + return -18; -}; + if(nLevel < 10) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -19; + } else { + return 0; + } + } -int32_t DecodeFailureTests(void) -{ - int32_t nResult; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { + return -20; + } - nResult = ProcessFailures(Failures,C_ARRAY_COUNT(Failures,struct FailInput)); - if(nResult) { - return nResult; + if(QCBORDecode_Finish(&DCtx)) { + return -21; } - // Corrupt the UsefulInputBuf and see that - // it reflected correctly for CBOR decoding + return 0; +} + + +/* These are just the item that open large maps and arrays, not + * the items in the array. This is sufficient to test the + * boundary condition. */ +static const uint8_t spLargeArrayFake[] = { + 0x99, 0xff, 0xfe}; + +static const uint8_t spTooLargeArrayFake[] = { + 0x99, 0xff, 0xff}; + +static const uint8_t spLargeMapFake[] = { + 0xb9, 0x7f, 0xff}; + +static const uint8_t spTooLargeMapFake[] = { + 0xba, 0x00, 0x00, 0x80, 0x00}; + + +int32_t ParseMapTest(void) +{ QCBORDecodeContext DCtx; QCBORItem Item; - QCBORError uQCBORError; + QCBORError uErr; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLargeArrayFake), QCBOR_DECODE_MODE_NORMAL); - - if((uQCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)uQCBORError; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 10) { - // This wasn't supposed to happen - return -1; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS || Item.val.uCount != QCBOR_MAX_ITEMS_IN_ARRAY) { + return -100; } - DCtx.InBuf.magic = 0; // Reach in and corrupt the UsefulInputBuf - - uQCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uQCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - // Did not get back the error expected - return -2; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLargeArrayFake), + QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_ERR_ARRAY_DECODE_TOO_LONG) { + return -101; } + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLargeMapFake), + QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS || Item.val.uCount != QCBOR_MAX_ITEMS_IN_MAP) { + return -110; + } - /* - The max size of a string for QCBOR is SIZE_MAX - 4 so this - tests here can be performed to see that the max length - error check works correctly. See DecodeBytes(). If the max - size was SIZE_MAX, it wouldn't be possible to test this. - - This test will automatocally adapt the all CPU sizes - through the use of SIZE_MAX. - */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLargeMapFake), + QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_ERR_ARRAY_DECODE_TOO_LONG) { + return -111; + } - UsefulBuf_MAKE_STACK_UB( HeadBuf, QCBOR_HEAD_BUFFER_SIZE); - UsefulBufC EncodedHead; - // This makes a CBOR head with a text string that is very long - // but doesn't fill in the bytes of the text string as that is - // not needed to test this part of QCBOR. - EncodedHead = QCBOREncode_EncodeHead(HeadBuf, CBOR_MAJOR_TYPE_TEXT_STRING, 0, SIZE_MAX); + // Parse a moderatly complex map structure very thoroughly + int32_t nResult = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); + if(nResult) { + return nResult; + } - QCBORDecode_Init(&DCtx, EncodedHead, QCBOR_DECODE_MODE_NORMAL); + // Again, but in strings-only mode. It should succeed since the input + // map has only string labels. + nResult = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); + if(nResult) { + return nResult; + } - if(QCBOR_ERR_STRING_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item)) { - return -4; + // Again, but try to finish the decoding before the end of the + // input at 10 different place and see that the right error code + // is returned. + for(int i = 0; i < 10; i++) { + nResult = ExtraBytesTest(i); + if(nResult) { + break; + } } - return 0; + return nResult; } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -/* Try all 256 values of the byte at nLen including recursing for - each of the values to try values at nLen+1 ... up to nLenMax - */ -static void ComprehensiveInputRecurser(uint8_t *pBuf, size_t nLen, size_t nLenMax) +/* The simple-values including some not well formed */ +static const uint8_t spSimpleValues[] = { + 0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, + 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, + 0xf8, 0xff}; + +/* A map of good simple values, plus one well-formed integer */ +static const uint8_t spGoodSimpleValues[] = { + 0xa9, 0x01, 0xf4, 0x02, 0xf5, 0x03, 0xf6, 0x04, 0xf7, + 0x05, 0xe0, 0x06, 0xf3, 0x07, 0xf8, 0x20, 0x61, 0x40, + 0xf8, 0xff, 0x0f, 0x0f}; + +int32_t SimpleValueDecodeTests(void) { - if(nLen >= nLenMax) { - return; - } + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uErr; - for(int inputByte = 0; inputByte < 256; inputByte++) { - // Set up the input - pBuf[nLen] = (uint8_t)inputByte; - const UsefulBufC Input = {pBuf, nLen+1}; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), + QCBOR_DECODE_MODE_NORMAL); - // Get ready to parse - QCBORDecodeContext DCtx; - QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); - // Parse by getting the next item until an error occurs - // Just about every possible decoder error can occur here - // The goal of this test is not to check for the correct - // error since that is not really possible. It is to - // see that there is no crash on hostile input. - while(1) { - QCBORItem Item; - QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_SUCCESS) { - break; - } - } + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 10) + return 1; - ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); - } -} + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_FALSE) + return 2; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_TRUE) + return 3; -int32_t ComprehensiveInputTest(void) -{ - // Size 2 tests 64K inputs and runs quickly - uint8_t pBuf[2]; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_NULL) + return 4; - ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UNDEF) + return 5; - return 0; -} + // A break + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) + return 6; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) + return 7; -int32_t BigComprehensiveInputTest(void) -{ - // size 3 tests 16 million inputs and runs OK - // in seconds on fast machines. Size 4 takes - // 10+ minutes and 5 half a day on fast - // machines. This test is kept separate from - // the others so as to no slow down the use - // of them as a very frequent regression. - uint8_t pBuf[3]; // + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) + return 8; - ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) + return 9; - return 0; -} + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) + return 10; + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) + return 11; -static const uint8_t spDateTestInput[] = { - /* 1. The valid date string "1985-04-12" */ - 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) + return 12; - /* 2. An invalid date string due to wrong tag content type */ - 0xc0, // tag for string date - 0x00, // Wrong type for a string date + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) + return 13; - /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ - 0xc1, // tag for epoch date - 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - /* 4. An invalid epoch date due to wrong tag content type */ - 0xc1, - 0x62, 'h', 'i', // wrong type tagged + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spGoodSimpleValues), + QCBOR_DECODE_MODE_NORMAL); - /* 5. Valid epoch date tag as content for a two other nested tags */ - // CBOR_TAG_ENC_AS_B64 - 0xcf, 0xd8, 0x16, 0xc1, // Epoch date with extra tags - 0x1a, 0x53, 0x72, 0x4E, 0x01, + uint8_t uSimple; - /* 6. Epoch date with value to large to fit into int64 */ - 0xc1, // tag for epoch date - 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer + QCBORDecode_EnterMap(&DCtx, &Item); + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_FALSE) { + return 20; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_TRUE) { + return 21; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_NULL) { + return 22; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_UNDEF) { + return 23; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 0) { + return 24; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 19) { + return 25; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 32) { + return 26; + } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 255) { + return 27; + } + QCBORDecode_VGetNext(&DCtx, &Item); + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 28; + } - /* 7. Epoch date with single-precision value of 1.1. */ - 0xc1, // tag for epoch date - 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // single with value 1.1 + QCBORDecode_Rewind(&DCtx); - /* 8. Epoch date with too-large single precision float */ - 0xc1, // tag for epoch date - 0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large + QCBORDecode_GetSimpleInMapN(&DCtx, 6, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 19) { + return 30; + } - /* 9. Epoch date with slightly too-large double precision value */ - 0xc1, // tag for epoch date - 0xfb, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9223372036854775808.000000 just barely too large - //0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large + QCBORDecode_GetSimpleInMapSZ(&DCtx, "@", &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 255) { + return 31; + } - /* 10. Epoch date with largest supported double precision value */ - 0xc1, // tag for epoch date - 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported + QCBORDecode_GetSimpleInMapN(&DCtx, 99, &uSimple); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 32; + } - /* 11. Epoch date with single-precision NaN */ - 0xc1, // tag for epoch date - 0xfa, 0x7f, 0xc0, 0x00, 0x00, // Single-precision NaN + QCBORDecode_GetSimpleInMapSZ(&DCtx, "xx", &uSimple); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 33; + } - /* 12. Epoch date with double precision plus infinity */ - 0xc1, - 0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +infinity + QCBORDecode_GetSimpleInMapN(&DCtx, 15, &uSimple); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 34; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - /* 13. Epoch date with half-precision negative infinity */ - 0xc1, // tag for epoch date - 0xf9, 0xfc, 0x00, // -Infinity -}; + return 0; +} +int32_t NotWellFormedTests(void) +{ + // Loop over all the not-well-formed instance of CBOR + // that are test vectors in not_well_formed_cbor.h + const uint16_t nArraySize = C_ARRAY_COUNT(paNotWellFormedCBOR, + struct someBinaryBytes); + for(uint16_t nIterate = 0; nIterate < nArraySize; nIterate++) { + const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate]; + const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n}; -// have to check float expected only to within an epsilon -#ifndef QCBOR_DISABLE_FLOAT_HW_USE -static int CHECK_EXPECTED_DOUBLE(double val, double expected) { + // Set up decoder context. String allocator needed for indefinite + // string test cases + QCBORDecodeContext DCtx; + QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - double diff = val - expected; + // Loop getting items until no more to get + QCBORError uCBORError; + do { + QCBORItem Item; - diff = fabs(diff); + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + } while(uCBORError == QCBOR_SUCCESS); - return diff > 0.0000001; + // Every test vector must fail with + // a not-well-formed error. If not + // this test fails. + if(!QCBORDecode_IsNotWellFormedError(uCBORError) && + uCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + /* Return index of failure and QCBOR error in the result */ + return (int32_t)(nIterate * 100 + uCBORError); + } + } + return 0; } -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -/* Test date decoding using GetNext() */ -int32_t DateParseTest(void) +struct DecodeFailTestInput { + const char *szDescription; /* Description of the test */ + QCBORDecodeMode DecoderMode; /* The QCBOR Decoder Mode for test */ + UsefulBufC Input; /* Chunk of CBOR that cases error */ + QCBORError nError; /* The expected error */ +}; + + +static int32_t +ProcessDecodeFailures(const struct DecodeFailTestInput *pFailInputs, const int nNumFails) { + int nIndex; QCBORDecodeContext DCtx; + QCBORError uCBORError; QCBORItem Item; - QCBORError uError; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), - QCBOR_DECODE_MODE_NORMAL); + for(nIndex = 0; nIndex < nNumFails; nIndex++) { + const struct DecodeFailTestInput *pF = &pFailInputs[nIndex]; - /* 1. The valid date string "1985-04-12" */ - if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { - return -1; - } - if(Item.uDataType != QCBOR_TYPE_DATE_STRING || - UsefulBufCompareToSZ(Item.val.dateString, "1985-04-12")){ - return -2; - } + QCBORDecode_Init(&DCtx, pF->Input, pF->DecoderMode); - /* 2. An invalid date string due to wrong tag content type */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_ERR_BAD_OPT_TAG) { - return -3; - } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + /* Set up the decoding context including a memory pool so that + * indefinite length items can be checked. + */ + UsefulBuf_MAKE_STACK_UB(Pool, 100); - /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS) { - return -4; - } - if(uError == QCBOR_SUCCESS) { - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1400000000 -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - || Item.val.epochDate.fSecondsFraction != 0 -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - ) { - return -5; + uCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); + if(uCBORError != QCBOR_SUCCESS) { + return -1; } - } - - /* 4. An invalid epoch date due to wrong tag content type */ - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_OPT_TAG) { - return -6; - } - - /* 5. Valid epoch date tag as content for a two other nested tags */ - // Epoch date wrapped in an CBOR_TAG_ENC_AS_B64 and an unknown tag. - // The date is decoded and the two tags are returned. This is to - // make sure the wrapping of epoch date in another tag works OK. - if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { - return -7; - } - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1400000001 || -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - Item.val.epochDate.fSecondsFraction != 0 || -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B64)) { - return -8; - } - - /* 6. Epoch date with value to large to fit into int64 */ - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { - return -9; - } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - /* 7. Epoch date with single-precision value of 1.1. */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return -10; - } - if(uError == QCBOR_SUCCESS) { - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1 -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - || CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1) -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - ) { - return -11; + if(nIndex == 4) { + uCBORError = 9; /* For setting break points */ } - } - /* 8. Epoch date with too-large single-precision float */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -12; - } + /* Iterate until there is an error of some sort */ + do { + /* Set to something non-zero, something other than QCBOR_TYPE_NONE */ + memset(&Item, 0x33, sizeof(Item)); - /* 9. Epoch date with slightly too-large double-precision value */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -13; - } + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + } while(uCBORError == QCBOR_SUCCESS); - /* 10. Epoch date with largest supported double-precision value */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return -14; - } - if(uError == QCBOR_SUCCESS) { - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 9223372036854773760 -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - || Item.val.epochDate.fSecondsFraction != 0.0 -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - ) { - return -14; + /* Must get the expected error or the this test fails. + * The data and label type must also be QCBOR_TYPE_NONE. + */ + if(uCBORError != pF->nError || + Item.uDataType != QCBOR_TYPE_NONE || + Item.uLabelType != QCBOR_TYPE_NONE) { + return (int32_t)(nIndex * 1000 + (int)uCBORError); } } - /* 11. Epoch date with single-precision NaN */ - if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -15; - } - - /* 12. Epoch date with double-precision plus infinity */ - if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -16; - } - - /* 13. Epoch date with half-precision negative infinity */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -17; - } - return 0; } -/* - Test cases covered here. Some items cover more than one of these. - positive integer (zero counts as a positive integer) - negative integer - half-precision float - single-precision float - double-precision float - - float Overflow error - Wrong type error for epoch - Wrong type error for date string - float disabled error - half-precision disabled error - -Infinity - Slightly too large integer - Slightly too far from zero +static const struct DecodeFailTestInput Failures[] = { + /* Most of this is copied from not_well_formed.h. Here the error + * code returned is also checked. + */ - Get epoch by int - Get string by int - Get epoch by string - Get string by string - Fail to get epoch by wrong int label - Fail to get string by wrong string label - Fail to get epoch by string because it is invalid - Fail to get epoch by int because it is invalid +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + /* Indefinite length strings must be closed off */ + { "An indefinite length byte string not closed off", + QCBOR_DECODE_MODE_NORMAL, + {"0x5f\x41\x00", 3}, + QCBOR_ERR_HIT_END + }, + { "An indefinite length text string not closed off", + QCBOR_DECODE_MODE_NORMAL, + {"\x7f\x61\x00", 3}, + QCBOR_ERR_HIT_END + }, - Untagged values - */ -static const uint8_t spSpiffyDateTestInput[] = { - 0x87, // array of 7 items + /* All the chunks in an indefinite length string must be of the + * type of indefinite length string + */ + { "Indefinite length byte string with text string chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x61\x00\xff", 4}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length text string with a byte string chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x7f\x41\x00\xff", 4}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with a positive integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x00\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with an negative integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x21\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with an array chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x80\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with an map chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xa0\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, - 0xa6, // Open a map for tests involving untagged items with labels. +#ifndef QCBOR_DISABLE_TAGS + { "Indefinite length byte string with tagged integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xc0\x00\xff", 4}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, +#else + { "Indefinite length byte string with tagged integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xc0\x00\xff", 4}, + QCBOR_ERR_TAGS_DISABLED + }, +#endif /* QCBOR_DISABLE_TAGS */ - // Untagged integer 0 - 0x08, - 0x00, + { "Indefinite length byte string with an simple type chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xe0\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "???", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x5f\x41\x00\xff\xff", 6}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "indefinite length text string with indefinite string inside", + QCBOR_DECODE_MODE_NORMAL, + {"\x7f\x7f\x61\x00\xff\xff", 6}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // Utagged date string with string label y - 0x61, 0x79, - 0x6a, '2','0','8','5','-','0','4','-','1','2', // Untagged date string +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // Untagged single-precision float with value 3.14 with string label x - 0x61, 0x78, - 0xFA, 0x40, 0x48, 0xF5, 0xC3, + /* Definte length maps and arrays must be closed by having the right number of items */ + { "A definte length array that is supposed to have 1 item, but has none", + QCBOR_DECODE_MODE_NORMAL, + {"\x81", 1}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "A definte length array that is supposed to have 2 items, but has only 1", + QCBOR_DECODE_MODE_NORMAL, + {"\x82\x00", 2}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "A definte length array that is supposed to have 511 items, but has only 1", + QCBOR_DECODE_MODE_NORMAL, + {"\x9a\x01\xff\x00", 4}, + QCBOR_ERR_HIT_END + }, + { "A definte length map that is supposed to have 1 item, but has none", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1", 1}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "A definte length map that is supposed to have s item, but has only 1", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x01\x02", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + /* Indefinte length maps and arrays must be ended by a break */ + { "Indefinite length array with zero items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f", 1}, + QCBOR_ERR_NO_MORE_ITEMS }, + + { "Indefinite length array with two items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\x9\x01\x02", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Indefinite length map with zero items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf", 1}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Indefinite length map with two items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\x02\x01\x02", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, - // Untagged half-precision float with value -2 - 0x09, - 0xF9, 0xC0, 0x00, + /* Nested maps and arrays must be closed off (some extra nested test vectors) */ + { "Unclosed indefinite array containing a closed definite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x80\x00", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, - /* Untagged date-only date string */ - 0x18, 0x63, - 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ + { "Definite length array containing an unclosed indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\x9f", 2}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed indefinite map containing a closed definite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\x80\x00\xa0", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Definite length map containing an unclosed indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x02\x9f", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Deeply nested definite length arrays with deepest one unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\x81\x81\x81\x81\x81\x81\x81\x81", 9}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Deeply nested indefinite length arrays with deepest one unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x9f\x9f\x9f\x9f\xff\xff\xff\xff", 9}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Mixed nesting with indefinite unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x81\x9f\x81\x9f\x9f\xff\xff\xff", 9}, + QCBOR_ERR_NO_MORE_ITEMS }, + { "Mixed nesting with definite unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x82\x9f\x81\x9f\x9f\xff\xff\xff\xff", 10}, + QCBOR_ERR_BAD_BREAK + }, + { "Unclosed indefinite length map in definite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x01\xa2\x02\xbf\xff\x02\xbf", 8}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed definite length map in indefinite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\xbf\x02\xa1", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed indefinite length array in definite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x01\xa2\x02\x9f\xff\x02\x9f", 8}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed definite length array in indefinite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\xbf\x02\x81", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed indefinite length map in definite length arrays", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\x82\xbf\xff\xbf", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed definite length map in indefinite length arrays", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x9f\xa1", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, - /* Untagged days-count epoch date */ - 0x11, - 0x19, 0x0F, 0x9A, /* 3994 */ +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - // End of map, back to array + /* The "argument" for the data item is incomplete */ + { "Positive integer missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x18", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 2 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x19", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 4 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1a", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 8 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1b", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 1 byte of 2 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x19\x01", 2}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 2 bytes of 4 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1a\x01\x02", 3}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 1 bytes of 7 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1b\x01\x02\x03\x04\x05\x06\x07", 8}, + QCBOR_ERR_HIT_END + }, + { "Negative integer missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x38", 1}, + QCBOR_ERR_HIT_END + }, + { "Binary string missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x58", 1}, + QCBOR_ERR_HIT_END + }, + { "Text string missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x78", 1}, + QCBOR_ERR_HIT_END + }, + { "Array missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x98", 1}, + QCBOR_ERR_HIT_END + }, + { "Map missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xb8", 1}, + QCBOR_ERR_HIT_END + }, + { "Tag missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xd8", 1}, + QCBOR_ERR_HIT_END + }, + { "Simple missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8", 1}, + QCBOR_ERR_HIT_END + }, + { "half-precision with 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xf9\x00", 2}, + QCBOR_ERR_HIT_END + }, + { "single-precision with 2 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\0xfa\x00\x00", 3}, + QCBOR_ERR_HIT_END + }, + { "double-precision with 3 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xfb\x00\x00\x00", 4}, + QCBOR_ERR_HIT_END + }, - 0xa7, // Open map of tagged items with labels +#ifndef QCBOR_DISABLE_TAGS + { "Tag with no content", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0", 1}, + QCBOR_ERR_HIT_END + }, +#else /* QCBOR_DISABLE_TAGS */ + { "Tag with no content", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0", 1}, + QCBOR_ERR_TAGS_DISABLED + }, +#endif /* QCBOR_DISABLE_TAGS */ - 0x00, - 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Tagged date string + /* Breaks must not occur in definite length arrays and maps */ + { "Array of length 1 with sole member replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\xff", 2}, + QCBOR_ERR_BAD_BREAK + }, + { "Array of length 2 with 2nd member replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\x82\x00\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Map of length 1 with sole member label replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\xff", 2}, + QCBOR_ERR_BAD_BREAK + }, + /* Map of length 1 with sole member label replaced by break */ + { "Alternate representation that some decoders handle differently", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\xff\x00", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Array of length 1 with 2nd member value replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x00\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Map of length 2 with 2nd entry label replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x00\x00\xff\x00", 5}, + QCBOR_ERR_BAD_BREAK + }, + { "Map of length 2 with 2nd entry value replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x00\x00\x01\xff", 5}, + QCBOR_ERR_BAD_BREAK + }, - 0x01, - 0xda, 0x03, 0x03, 0x03, 0x03, // An additional tag - 0xc1, // tag for epoch date - 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + /* Breaks must not occur on their own out of an indefinite length data item */ + { "A bare break is not well formed", + QCBOR_DECODE_MODE_NORMAL, + {"\xff", 1}, + QCBOR_ERR_BAD_BREAK + }, + { "A bare break after a zero length definite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x80\xff", 2}, + QCBOR_ERR_BAD_BREAK + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + { "A bare break after a zero length indefinite length map", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\xff\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "A break inside a definite length array inside an indefenite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x81\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Complicated mixed nesting with break outside indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x82\x9f\x81\x9f\x9f\xff\xff\xff\xff", 10}, + QCBOR_ERR_BAD_BREAK }, +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - 0x05, - 0xc1, - 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // -9223372036854773760 largest negative + /* Forbidden two byte encodings of simple types */ + { "Must use 0xe0 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x00", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe1 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x01", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe2 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x02", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, { "Should use 0xe3 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x03", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe4 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x04", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe5 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x05", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe6 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x06", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe7 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x07", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe8 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x08", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe9 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x09", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xea instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0a", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xeb instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0b", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xec instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0c", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xed instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0d", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xee instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0e", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xef instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0f", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf0 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x10", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf1 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x11", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf2 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x12", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf3 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x13", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf4 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x14", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf5 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x15", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf6 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x16", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xef7 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x17", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xef8 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x18", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Reserved", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x18", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + /* Maps must have an even number of data items (key & value) */ + { "Map with 1 item when it should have 2", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x00", 2}, + QCBOR_ERR_HIT_END + }, + { "Map with 3 item when it should have 4", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x00\x00\x00", 2}, + QCBOR_ERR_HIT_END + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + { "Map with 1 item when it should have 2", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x00\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Map with 3 item when it should have 4", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x00\x00\x00\xff", 5}, + QCBOR_ERR_BAD_BREAK + }, +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - 0x07, - 0xc1, // tag for epoch date - 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported - /* Tagged days-count epoch date */ - 0x63, 0x53, 0x44, 0x45, - 0xD8, 0x64, /* tag(100) */ - 0x39, 0x29, 0xB3, /* -10676 */ +#ifndef QCBOR_DISABLE_TAGS + /* In addition to not-well-formed, some invalid CBOR */ + { "Text-based date, with an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0\x00", 2}, + QCBOR_ERR_BAD_OPT_TAG + }, + { "Epoch date, with an byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\x41\x33", 3}, + QCBOR_ERR_BAD_OPT_TAG + }, + { "tagged as both epoch and string dates", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\xc0\x00", 3}, + QCBOR_ERR_BAD_OPT_TAG + }, + { "big num tagged an int, not a byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc2\x00", 2}, + QCBOR_ERR_BAD_OPT_TAG + }, +#else /* QCBOR_DISABLE_TAGS */ + /* In addition to not-well-formed, some invalid CBOR */ + { "Text-based date, with an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0\x00", 2}, + QCBOR_ERR_TAGS_DISABLED + }, + { "Epoch date, with an byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\x41\x33", 3}, + QCBOR_ERR_TAGS_DISABLED + }, + { "tagged as both epoch and string dates", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\xc0\x00", 3}, + QCBOR_ERR_TAGS_DISABLED + }, + { "big num tagged an int, not a byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc2\x00", 2}, + QCBOR_ERR_TAGS_DISABLED + }, +#endif /* QCBOR_DISABLE_TAGS */ +}; - // Untagged -1000 with label z - 0x61, 0x7a, - 0xda, 0x01, 0x01, 0x01, 0x01, // An additional tag - 0x39, 0x03, 0xe7, - /* Tagged date-only date string */ - 0x63, 0x53, 0x44, 0x53, - 0xD9, 0x03, 0xEC, - 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ - // End of map of tagged items +int32_t +DecodeFailureTests(void) +{ + int32_t nResult; - 0xc1, - 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // -9.2233720368547748E+18, too negative + nResult = ProcessDecodeFailures(Failures ,C_ARRAY_COUNT(Failures, struct DecodeFailTestInput)); + if(nResult) { + return nResult; + } - 0xc1, // tag for epoch date - 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too-large integer + // Corrupt the UsefulInputBuf and see that + // it reflected correctly for CBOR decoding + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uQCBORError; - 0xc1, // tag for epoch date - 0xf9, 0xfc, 0x00, // Half-precision -Infinity + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), + QCBOR_DECODE_MODE_NORMAL); - // These two at the end because they are unrecoverable errors - 0xc1, // tag for epoch date - 0x80, // Erroneous empty array as content for date + if((uQCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uQCBORError; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 10) { + // This wasn't supposed to happen + return -1; + } - 0xc0, // tag for string date - 0xa0 // Erroneous empty map as content for date -}; + DCtx.InBuf.magic = 0; // Reach in and corrupt the UsefulInputBuf -int32_t SpiffyDateDecodeTest(void) -{ - QCBORDecodeContext DC; - QCBORError uError; - int64_t nEpochDate3, nEpochDate5, - nEpochDate4, nEpochDate6, - nEpochDays2; - UsefulBufC StringDate1, StringDate2, StringDays2; + uQCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uQCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + // Did not get back the error expected + return -2; + } - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyDateTestInput), - QCBOR_DECODE_MODE_NORMAL); - /* Items are in an array or map to test look up by label and other - * that might not occur in isolated items. But it does make the - * test a bit messy. */ - QCBORDecode_EnterArray(&DC, NULL); + /* + The max size of a string for QCBOR is SIZE_MAX - 4 so this + tests here can be performed to see that the max length + error check works correctly. See DecodeBytes(). If the max + size was SIZE_MAX, it wouldn't be possible to test this. - QCBORDecode_EnterMap(&DC, NULL); + This test will automatocally adapt the all CPU sizes + through the use of SIZE_MAX. + */ - // A single-precision date - QCBORDecode_GetEpochDateInMapSZ(&DC, "x", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &nEpochDate5); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 104; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate5 != 3) { - return 103; - } - } + UsefulBuf_MAKE_STACK_UB( HeadBuf, QCBOR_HEAD_BUFFER_SIZE); + UsefulBufC EncodedHead; - // A half-precision date with value -2 FFF - QCBORDecode_GetEpochDateInMapN(&DC, 9, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &nEpochDate4); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 106; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate4 != -2) { - return 105; - } - } + // This makes a CBOR head with a text string that is very long + // but doesn't fill in the bytes of the text string as that is + // not needed to test this part of QCBOR. + EncodedHead = QCBOREncode_EncodeHead(HeadBuf, CBOR_MAJOR_TYPE_TEXT_STRING, 0, SIZE_MAX); - // Fail to get an epoch date by string label - QCBORDecode_GetEpochDateInMapSZ(&DC, "no-label", - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDate6); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 107; - } + QCBORDecode_Init(&DCtx, EncodedHead, QCBOR_DECODE_MODE_NORMAL); - // Fail to get an epoch date by integer label - QCBORDecode_GetEpochDateInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDate6); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 108; + if(QCBOR_ERR_STRING_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item)) { + return -4; } - // Fail to get a string date by string label - QCBORDecode_GetDateStringInMapSZ(&DC, "no-label", - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 109; + return 0; +} + + +/* Try all 256 values of the byte at nLen including recursing for + each of the values to try values at nLen+1 ... up to nLenMax + */ +static void ComprehensiveInputRecurser(uint8_t *pBuf, size_t nLen, size_t nLenMax) +{ + if(nLen >= nLenMax) { + return; } - // Fail to get a string date by integer label - QCBORDecode_GetDateStringInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 110; + for(int inputByte = 0; inputByte < 256; inputByte++) { + // Set up the input + pBuf[nLen] = (uint8_t)inputByte; + const UsefulBufC Input = {pBuf, nLen+1}; + + // Get ready to parse + QCBORDecodeContext DCtx; + QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); + + // Parse by getting the next item until an error occurs + // Just about every possible decoder error can occur here + // The goal of this test is not to check for the correct + // error since that is not really possible. It is to + // see that there is no crash on hostile input. + while(1) { + QCBORItem Item; + QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_SUCCESS) { + break; + } + } + + ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); } +} - // The rest of these succeed even if float features are disabled +int32_t ComprehensiveInputTest(void) +{ + // Size 2 tests 64K inputs and runs quickly + uint8_t pBuf[2]; - // Untagged integer 0 - QCBORDecode_GetEpochDateInMapN(&DC, 8, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDate3); - // Untagged date string - QCBORDecode_GetDateStringInMapSZ(&DC, "y", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDate2); + ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); - QCBORDecode_GetDaysStringInMapN(&DC, 99, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDays2); + return 0; +} - QCBORDecode_GetEpochDaysInMapN(&DC, 17, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDays2); - QCBORDecode_ExitMap(&DC); - if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { - return 3001; - } +int32_t BigComprehensiveInputTest(void) +{ + // size 3 tests 16 million inputs and runs OK + // in seconds on fast machines. Size 4 takes + // 10+ minutes and 5 half a day on fast + // machines. This test is kept separate from + // the others so as to no slow down the use + // of them as a very frequent regression. + uint8_t pBuf[3]; // - // The map of tagged items - QCBORDecode_EnterMap(&DC, NULL); + ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); -#ifndef QCBOR_DISABLE_TAGS - int64_t nEpochDate2, - nEpochDateFail, - nEpochDate1400000000, nEpochDays1; - UsefulBufC StringDays1; - uint64_t uTag1, uTag2; + return 0; +} - // Tagged date string - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &StringDate1); - // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - QCBORDecode_GetEpochDateInMapN(&DC, - 1, - QCBOR_TAG_REQUIREMENT_TAG | - QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - &nEpochDate1400000000); - uTag1 = QCBORDecode_GetNthTagOfLast(&DC, 0); +static const uint8_t spDateTestInput[] = { + /* 1. The valid date string "1985-04-12" */ + 0xc0, // tag for string date + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string - // Get largest negative double precision epoch date allowed - QCBORDecode_GetEpochDateInMapN(&DC, - 5, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG | - QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - &nEpochDate2); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 102; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate2 != -9223372036854773760LL) { - return 101; - } - } + /* 2. An invalid date string due to wrong tag content type */ + 0xc0, // tag for string date + 0x00, // Wrong type for a string date - // Untagged -1000 with label z - QCBORDecode_GetEpochDateInMapSZ(&DC, - "z", - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | - QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - &nEpochDate6); - uTag2 = QCBORDecode_GetNthTagOfLast(&DC, 0); + /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ + 0xc1, // tag for epoch date + 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + /* 4. An invalid epoch date due to wrong tag content type */ + 0xc1, + 0x62, 'h', 'i', // wrong type tagged - // Get largest double precision epoch date allowed - QCBORDecode_GetEpochDateInMapN(&DC, 7, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &nEpochDate2); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 112; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate2 != 9223372036854773760ULL) { - return 111; - } - } + /* 5. Valid epoch date tag as content for a two other nested tags */ + // CBOR_TAG_ENC_AS_B64 + 0xcf, 0xd8, 0x16, 0xc1, // Epoch date with extra tags + 0x1a, 0x53, 0x72, 0x4E, 0x01, - /* The days format is much simpler than the date format - * because it can't be a floating point value. The test - * of the spiffy decode functions sufficiently covers - * the test of the non-spiffy decode days date decoding. - * There is no full fan out of the error conditions - * and decode options as that is implemented by code - * that is tested well by the date testing above. - */ - QCBORDecode_GetDaysStringInMapSZ(&DC, "SDS", QCBOR_TAG_REQUIREMENT_TAG, - &StringDays1); + /* 6. Epoch date with value to large to fit into int64 */ + 0xc1, // tag for epoch date + 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer - QCBORDecode_GetEpochDaysInMapSZ(&DC, "SDE", QCBOR_TAG_REQUIREMENT_TAG, - &nEpochDays1); + /* 7. Epoch date with single-precision value of 1.1. */ + 0xc1, // tag for epoch date + 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // single with value 1.1 - QCBORDecode_ExitMap(&DC); - if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { - return 3001; - } + /* 8. Epoch date with too-large single precision float */ + 0xc1, // tag for epoch date + 0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large - // Too-negative float, -9.2233720368547748E+18 - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return 1111; - } + /* 9. Epoch date with slightly too-large double precision value */ + 0xc1, // tag for epoch date + 0xfb, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9223372036854775808.000000 just barely too large + //0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large - // Too-large integer - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_DATE_OVERFLOW) { - return 1; - } + /* 10. Epoch date with largest supported double precision value */ + 0xc1, // tag for epoch date + 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported - // Half-precision minus infinity - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return 2; - } + /* 11. Epoch date with single-precision NaN */ + 0xc1, // tag for epoch date + 0xfa, 0x7f, 0xc0, 0x00, 0x00, // Single-precision NaN + /* 12. Epoch date with double precision plus infinity */ + 0xc1, + 0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +infinity - // Bad content for epoch date - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 3; - } + /* 13. Epoch date with half-precision negative infinity */ + 0xc1, // tag for epoch date + 0xf9, 0xfc, 0x00, // -Infinity +}; - // Bad content for string date - QCBORDecode_GetDateString(&DC, QCBOR_TAG_REQUIREMENT_TAG, &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 4; - } - QCBORDecode_ExitArray(&DC); - uError = QCBORDecode_Finish(&DC); - if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 1000 + (int32_t)uError; - } -#else /* QCBOR_DISABLE_TAGS */ - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return 4; - } -#endif /* QCBOR_DISABLE_TAGS */ +// have to check float expected only to within an epsilon +#ifndef QCBOR_DISABLE_FLOAT_HW_USE +static int CHECK_EXPECTED_DOUBLE(double val, double expected) { + + double diff = val - expected; -#ifndef QCBOR_DISABLE_TAGS + diff = fabs(diff); - if(nEpochDate1400000000 != 1400000000) { - return 200; + return diff > 0.0000001; +} +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ + + +/* Test date decoding using GetNext() */ +int32_t DateParseTest(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uError; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), + QCBOR_DECODE_MODE_NORMAL); + + /* 1. The valid date string "1985-04-12" */ + if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { + return -1; + } + if(Item.uDataType != QCBOR_TYPE_DATE_STRING || + UsefulBufCompareToSZ(Item.val.string, "1985-04-12")){ + return -2; } - if(uTag1 != 0x03030303) { - return 201; + /* 2. An invalid date string due to wrong tag content type */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_ERR_BAD_OPT_TAG) { + return -3; } - if(nEpochDays1 != -10676) { - return 205; + /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS) { + return -4; + } + if(uError == QCBOR_SUCCESS) { + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1400000000 +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + || Item.val.epochDate.fSecondsFraction != 0 +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + ) { + return -5; + } } - if(UsefulBuf_Compare(StringDays1, UsefulBuf_FromSZ("1985-04-12"))) { - return 207; + /* 4. An invalid epoch date due to wrong tag content type */ + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_OPT_TAG) { + return -6; } - if(uTag2 != 0x01010101) { - return 204; + /* 5. Valid epoch date tag as content for a two other nested tags */ + // Epoch date wrapped in an CBOR_TAG_ENC_AS_B64 and an unknown tag. + // The date is decoded and the two tags are returned. This is to + // make sure the wrapping of epoch date in another tag works OK. + if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { + return -7; + } + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1400000001 || +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + Item.val.epochDate.fSecondsFraction != 0 || +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B64)) { + return -8; } - if(nEpochDate6 != -1000) { - return 203; + /* 6. Epoch date with value to large to fit into int64 */ + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { + return -9; } - if(UsefulBuf_Compare(StringDate1, UsefulBuf_FromSZ("1985-04-12"))) { - return 205; + /* 7. Epoch date with single-precision value of 1.1. */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return -10; + } + if(uError == QCBOR_SUCCESS) { + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1 +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + || CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1) +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + ) { + return -11; + } } -#endif /* QCBOR_DISABLE_TAGS */ + /* 8. Epoch date with too-large single-precision float */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -12; + } - if(nEpochDate3 != 0) { - return 202; + /* 9. Epoch date with slightly too-large double-precision value */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -13; } - if(nEpochDays2 != 3994) { - return 206; + /* 10. Epoch date with largest supported double-precision value */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return -14; + } + if(uError == QCBOR_SUCCESS) { + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 9223372036854773760 +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + || Item.val.epochDate.fSecondsFraction != 0.0 +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ + ) { + return -14; + } } - if(UsefulBuf_Compare(StringDate2, UsefulBuf_FromSZ("2085-04-12"))) { - return 206; + /* 11. Epoch date with single-precision NaN */ + if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -15; } - if(UsefulBuf_Compare(StringDays2, UsefulBuf_FromSZ("1985-04-12"))) { - return 208; + /* 12. Epoch date with double-precision plus infinity */ + if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -16; + } + + /* 13. Epoch date with half-precision negative infinity */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -17; } return 0; } -// Input for one of the tagging tests -static const uint8_t spTagInput[] = { - 0xd9, 0xd9, 0xf7, // CBOR magic number - 0x81, // Array of one - 0xd8, 0x04, // non-preferred serialization of tag 4, decimal fraction - 0x82, // Array of two that is the faction 1/3 - 0x01, - 0x03, - - /* - More than 4 tags on an item 225(226(227(228(229([]))))) - */ - 0xd8, 0xe1, - 0xd8, 0xe2, - 0xd8, 0xe3, - 0xd8, 0xe4, - 0xd8, 0xe5, - 0x80, +/* + Test cases covered here. Some items cover more than one of these. + positive integer (zero counts as a positive integer) + negative integer + half-precision float + single-precision float + double-precision float - /* tag 10489608748473423768( - 2442302356( - 21590( - 240( - [])))) - */ - 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0xda, 0x91, 0x92, 0x93, 0x94, - 0xd9, 0x54, 0x56, - 0xd8, 0xf0, - 0x80, + float Overflow error + Wrong type error for epoch + Wrong type error for date string + float disabled error + half-precision disabled error + -Infinity + Slightly too large integer + Slightly too far from zero - /* tag 21590( - 10489608748473423768( - 2442302357( - 65534( - [])))) - */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, - 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0xda, 0x91, 0x92, 0x93, 0x95, - 0xd9, 0xff, 0xfe, - 0x80, + Get epoch by int + Get string by int + Get epoch by string + Get string by string + Fail to get epoch by wrong int label + Fail to get string by wrong string label + Fail to get epoch by string because it is invalid + Fail to get epoch by int because it is invalid - /* Make sure to blow past the limit of tags that must be mapped. - works in conjuntion with entries above. - 269488144(269488145(269488146(269488147([])))) - */ - 0xda, 0x10, 0x10, 0x10, 0x10, - 0xda, 0x10, 0x10, 0x10, 0x11, - 0xda, 0x10, 0x10, 0x10, 0x12, - 0xda, 0x10, 0x10, 0x10, 0x13, - 0x80, + Untagged values + */ +static const uint8_t spSpiffyDateTestInput[] = { + 0x87, // array of 7 items - /* An invalid decimal fraction with an additional tag */ - 0xd9, 0xff, 0xfa, - 0xd8, 0x02, // non-preferred serialization of tag 2, a big num - 0x00, // the integer 0; should be a byte string -}; + 0xa6, // Open a map for tests involving untagged items with labels. -/* - DB 9192939495969798 # tag(10489608748473423768) - 80 # array(0) - */ -static const uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x98, 0x80}; + // Untagged integer 0 + 0x08, + 0x00, -/* -DB 9192939495969798 # tag(10489608748473423768) - D8 88 # tag(136) - C6 # tag(6) - C7 # tag(7) - 80 # array(0) -*/ -static const uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80}; + // Utagged date string with string label y + 0x61, 0x79, + 0x6a, '2','0','8','5','-','0','4','-','1','2', // Untagged date string -/* - 55799(55799(55799({ - 6(7(-23)): 5859837686836516696(7({ - 7(-20): 11({ - 17(-18): 17(17(17("Organization"))), - 9(-17): 773("SSG"), - -15: 16(17(6(7("Confusion")))), - 17(-16): 17("San Diego"), - 17(-14): 17("US") - }), - 23(-19): 19({ - -11: 9({ - -9: -7 - }), - 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A') - }) - })), - 16(-22): 23({ - 11(8(7(-5))): 8(-3) - }) - }))) - */ -static const uint8_t spCSRWithTags[] = { - 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, - 0xc6, 0xc7, 0x36, - 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, - 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, - 0xcb, 0xa5, - 0xd1, 0x31, - 0xd1, 0xd1, 0xd1, 0x6c, - 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0xc9, 0x30, - 0xd9, 0x03, 0x05, 0x63, - 0x53, 0x53, 0x47, - 0x2e, - 0xd0, 0xd1, 0xc6, 0xc7, - 0x69, - 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, - 0xd1, 0x2f, - 0xd1, 0x69, - 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, - 0xd1, 0x2d, - 0xd1, 0x62, - 0x55, 0x53, - 0xd7, 0x32, - 0xd3, 0xa2, - 0x2a, - 0xc9, 0xa1, - 0x28, - 0x26, - 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, - 0xcc, 0x4a, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, - 0xd0, 0x35, - 0xd7, 0xa1, - 0xcb, 0xc8, 0xc7, 0x24, - 0xc8, 0x22}; + // Untagged single-precision float with value 3.14 with string label x + 0x61, 0x78, + 0xFA, 0x40, 0x48, 0xF5, 0xC3, + // Untagged half-precision float with value -2 + 0x09, + 0xF9, 0xC0, 0x00, -static const uint8_t spSpiffyTagInput[] = { - 0x85, // Open array + /* Untagged date-only date string */ + 0x18, 0x63, + 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ + + /* Untagged days-count epoch date */ + 0x11, + 0x19, 0x0F, 0x9A, /* 3994 */ + + // End of map, back to array + + 0xa7, // Open map of tagged items with labels + 0x00, 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Tagged date string - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string - 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string + 0x01, + 0xda, 0x03, 0x03, 0x03, 0x03, // An additional tag + 0xc1, // tag for epoch date + 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - 0xd8, 0x23, // tag for regex - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x05, + 0xc1, + 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // -9223372036854773760 largest negative - 0xc0, // tag for string date - 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string - // This last case makes the array untraversable because it is - // an uncrecoverable error. Make sure it stays last and is the only - // instance so the other tests can work. -}; + 0x07, + 0xc1, // tag for epoch date + 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported + /* Tagged days-count epoch date */ + 0x63, 0x53, 0x44, 0x45, + 0xD8, 0x64, /* tag(100) */ + 0x39, 0x29, 0xB3, /* -10676 */ -static int32_t CheckCSRMaps(QCBORDecodeContext *pDC); + // Untagged -1000 with label z + 0x61, 0x7a, + 0xda, 0x01, 0x01, 0x01, 0x01, // An additional tag + 0x39, 0x03, 0xe7, + /* Tagged date-only date string */ + 0x63, 0x53, 0x44, 0x53, + 0xD9, 0x03, 0xEC, + 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ -int32_t OptTagParseTest(void) + // End of map of tagged items + + 0xc1, + 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // -9.2233720368547748E+18, too negative + + 0xc1, // tag for epoch date + 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too-large integer + + 0xc1, // tag for epoch date + 0xf9, 0xfc, 0x00, // Half-precision -Infinity + + // These two at the end because they are unrecoverable errors + 0xc1, // tag for epoch date + 0x80, // Erroneous empty array as content for date + + 0xc0, // tag for string date + 0xa0 // Erroneous empty map as content for date +}; + +int32_t SpiffyDateDecodeTest(void) { - QCBORDecodeContext DCtx; - QCBORItem Item; + QCBORDecodeContext DC; QCBORError uError; + int64_t nEpochDate3, nEpochDate5, + nEpochDate4, nEpochDate6, + nEpochDays2; + UsefulBufC StringDate1, StringDate2, StringDays2; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput), + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyDateTestInput), QCBOR_DECODE_MODE_NORMAL); - /* - This test matches the magic number tag and the fraction tag - 55799([...]) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS) { - return -2; + /* Items are in an array or map to test look up by label and other + * that might not occur in isolated items. But it does make the + * test a bit messy. */ + QCBORDecode_EnterArray(&DC, NULL); + + QCBORDecode_EnterMap(&DC, NULL); + + // A single-precision date + QCBORDecode_GetEpochDateInMapSZ(&DC, "x", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &nEpochDate5); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 104; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { - return -3; + if(uError == QCBOR_SUCCESS) { + if(nEpochDate5 != 3) { + return 103; + } } - /* - 4([1,3]) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); -#ifdef QCBOR_DISABLE_EXP_AND_MANTISSA - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_DECIMAL_FRACTION || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 || - Item.val.uCount != 2) { - return -4; + // A half-precision date with value -2 FFF + QCBORDecode_GetEpochDateInMapN(&DC, 9, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &nEpochDate4); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 106; } - // consume the items in the array - uError = QCBORDecode_GetNext(&DCtx, &Item); - uError = QCBORDecode_GetNext(&DCtx, &Item); - -#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 ) { - return -5; + if(uError == QCBOR_SUCCESS) { + if(nEpochDate4 != -2) { + return 105; + } } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - /* - More than 4 tags on an item 225(226(227(228(229([]))))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_ERR_TOO_MANY_TAGS) { - return -6; + // Fail to get an epoch date by string label + QCBORDecode_GetEpochDateInMapSZ(&DC, "no-label", + QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDate6); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 107; } - if(QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64) { - return -106; + // Fail to get an epoch date by integer label + QCBORDecode_GetEpochDateInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDate6); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 108; } - - /* tag 10489608748473423768( - 2442302356( - 21590( - 240( - [])))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_ARRAY || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 10489608748473423768ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 2442302356ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 21590ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 240ULL) { - return -7; + // Fail to get a string date by string label + QCBORDecode_GetDateStringInMapSZ(&DC, "no-label", + QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 109; } - /* tag 21590( - 10489608748473423768( - 2442302357( - 21591( - [])))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_ARRAY || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 65534ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 2442302357ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 10489608748473423768ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 21590ULL) { - return -8; + // Fail to get a string date by integer label + QCBORDecode_GetDateStringInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 110; } - /* Make sure to blow past the limit of tags that must be mapped. - works in conjuntion with entries above. - 269488144(269488145(269488146(269488147([])))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_ERR_TOO_MANY_TAGS) { - return -9; + // The rest of these succeed even if float features are disabled + + + // Untagged integer 0 + QCBORDecode_GetEpochDateInMapN(&DC, 8, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDate3); + // Untagged date string + QCBORDecode_GetDateStringInMapSZ(&DC, "y", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDate2); + + QCBORDecode_GetDaysStringInMapN(&DC, 99, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDays2); + + QCBORDecode_GetEpochDaysInMapN(&DC, 17, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDays2); + + QCBORDecode_ExitMap(&DC); + if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { + return 3001; } - uError = QCBORDecode_GetNext(&DCtx, &Item); + // The map of tagged items + QCBORDecode_EnterMap(&DC, NULL); + +#ifndef QCBOR_DISABLE_TAGS + int64_t nEpochDate2, + nEpochDateFail, + nEpochDate1400000000, nEpochDays1; + UsefulBufC StringDays1; + uint64_t uTag1, uTag2; + + // Tagged date string + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &StringDate1); + + // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + QCBORDecode_GetEpochDateInMapN(&DC, + 1, + QCBOR_TAG_REQUIREMENT_TAG | + QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, + &nEpochDate1400000000); + uTag1 = QCBORDecode_GetNthTagOfLast(&DC, 0); + + // Get largest negative double precision epoch date allowed + QCBORDecode_GetEpochDateInMapN(&DC, + 5, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG | + QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, + &nEpochDate2); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 102; + } if(uError == QCBOR_SUCCESS) { - return -10; + if(nEpochDate2 != -9223372036854773760LL) { + return 101; + } } - // ---------------------------------- - // This test sets up a caller-config list that includes the very large - // tage and then matches it. Caller-config lists are no longer - // used or needed. This tests backwards compatibility with them. - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), - QCBOR_DECODE_MODE_NORMAL); - const uint64_t puList[] = {0x9192939495969798, 257}; - const QCBORTagListIn TL = {2, puList}; - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); + // Untagged -1000 with label z + QCBORDecode_GetEpochDateInMapSZ(&DC, + "z", + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | + QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, + &nEpochDate6); + uTag2 = QCBORDecode_GetNthTagOfLast(&DC, 0); - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -8; + + // Get largest double precision epoch date allowed + QCBORDecode_GetEpochDateInMapN(&DC, 7, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &nEpochDate2); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 112; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || - QCBORDecode_IsTagged(&DCtx, &Item, 257) || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || - Item.val.uCount != 0) { - return -9; + if(uError == QCBOR_SUCCESS) { + if(nEpochDate2 != 9223372036854773760ULL) { + return 111; + } } - //------------------------ - // Sets up a caller-configured list and look up something not in it - // Another backwards compatibility test. - const uint64_t puLongList[17] = {1,2,1}; - const QCBORTagListIn TLLong = {17, puLongList}; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), - QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -11; - } + /* The days format is much simpler than the date format + * because it can't be a floating point value. The test + * of the spiffy decode functions sufficiently covers + * the test of the non-spiffy decode days date decoding. + * There is no full fan out of the error conditions + * and decode options as that is implemented by code + * that is tested well by the date testing above. + */ + QCBORDecode_GetDaysStringInMapSZ(&DC, "SDS", QCBOR_TAG_REQUIREMENT_TAG, + &StringDays1); - uint64_t puTags[4]; - QCBORTagListOut Out = {0, 4, puTags}; + QCBORDecode_GetEpochDaysInMapSZ(&DC, "SDE", QCBOR_TAG_REQUIREMENT_TAG, + &nEpochDays1); + QCBORDecode_ExitMap(&DC); + if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { + return 3001; + } - // This tests retrievel of the full tag list - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), - QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -12; + // Too-negative float, -9.2233720368547748E+18 + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return 1111; } - if(puTags[0] != 0x9192939495969798 || - puTags[1] != 0x88 || - puTags[2] != 0x06 || - puTags[3] != 0x07) { - return -13; + + // Too-large integer + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_DATE_OVERFLOW) { + return 1; } - // ---------------------- - // This tests too small of an out list - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), - QCBOR_DECODE_MODE_NORMAL); - QCBORTagListOut OutSmall = {0, 3, puTags}; - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { - return -14; + // Half-precision minus infinity + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return 2; } + // Bad content for epoch date + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 3; + } - // --------------- - // Decode a version of the "CSR" that has had a ton of tags randomly inserted - // It is a bit of a messy test and maybe could be improved, but - // it is retained as a backwards compatibility check. - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), - QCBOR_DECODE_MODE_NORMAL); - int n = CheckCSRMaps(&DCtx); - if(n) { - return n-2000; + // Bad content for string date + QCBORDecode_GetDateString(&DC, QCBOR_TAG_REQUIREMENT_TAG, &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 4; } - Out = (QCBORTagListOut){0, 16, puTags}; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), - QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_ExitArray(&DC); + uError = QCBORDecode_Finish(&DC); + if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 1000 + (int32_t)uError; + } +#else /* QCBOR_DISABLE_TAGS */ + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return 4; + } +#endif /* QCBOR_DISABLE_TAGS */ - /* With the spiffy decode revision, this tag list is not used. - It doesn't matter if a tag is in this list or not so some - tests that couldn't process a tag because it isn't in this list - now can process these unlisted tags. The tests have been - adjusted for this. */ - const uint64_t puTagList[] = {773, 1, 90599561}; - const QCBORTagListIn TagList = {3, puTagList}; - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); +#ifndef QCBOR_DISABLE_TAGS - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -100; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || - QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || - Item.val.uCount != 2 || - puTags[0] != CBOR_TAG_CBOR_MAGIC || - puTags[1] != CBOR_TAG_CBOR_MAGIC || - puTags[2] != CBOR_TAG_CBOR_MAGIC || - Out.uNumUsed != 3) { - return -101; + if(nEpochDate1400000000 != 1400000000) { + return 200; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -102; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || - QCBORDecode_IsTagged(&DCtx, &Item, 6) || - !QCBORDecode_IsTagged(&DCtx, &Item, 7) || - Item.val.uCount != 2 || - puTags[0] != 5859837686836516696 || - puTags[1] != 7 || - Out.uNumUsed != 2) { - return -103; + if(uTag1 != 0x03030303) { + return 201; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -104; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 5 || - puTags[0] != 0x0b || - Out.uNumUsed != 1) { - return -105; + if(nEpochDays1 != -10676) { + return 205; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -106; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || - Item.val.string.len != 12 || - puTags[0] != CBOR_TAG_COSE_MAC0 || - puTags[1] != CBOR_TAG_COSE_MAC0 || - puTags[2] != CBOR_TAG_COSE_MAC0 || - Out.uNumUsed != 3) { - return -105; + if(UsefulBuf_Compare(StringDays1, UsefulBuf_FromSZ("1985-04-12"))) { + return 207; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -107; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 773) || - Item.val.string.len != 3 || - puTags[0] != 773 || - Out.uNumUsed != 1) { - return -108; + if(uTag2 != 0x01010101) { + return 204; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -109; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 16) || - Item.val.string.len != 9 || - puTags[0] != 16 || - puTags[3] != 7 || - Out.uNumUsed != 4) { - return -110; + if(nEpochDate6 != -1000) { + return 203; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -111; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 17) || - Item.val.string.len != 9 || - puTags[0] != 17 || - Out.uNumUsed != 1) { - return -112; + if(UsefulBuf_Compare(StringDate1, UsefulBuf_FromSZ("1985-04-12"))) { + return 205; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -111; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 17) || - Item.val.string.len != 2 || - puTags[0] != 17 || - Out.uNumUsed != 1) { - return -112; - } +#endif /* QCBOR_DISABLE_TAGS */ - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -113; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, 19) || - Item.val.uCount != 2 || - puTags[0] != 19 || - Out.uNumUsed != 1) { - return -114; + if(nEpochDate3 != 0) { + return 202; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -115; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, 9) || - Item.val.uCount != 1 || - puTags[0] != 9 || - Out.uNumUsed != 1) { - return -116; + if(nEpochDays2 != 3994) { + return 206; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -116; - } - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -7 || - Out.uNumUsed != 0) { - return -117; + if(UsefulBuf_Compare(StringDate2, UsefulBuf_FromSZ("2085-04-12"))) { + return 206; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -118; - } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.val.string.len != 10 || - puTags[0] != 12 || - Out.uNumUsed != 1) { - return -119; + if(UsefulBuf_Compare(StringDays2, UsefulBuf_FromSZ("1985-04-12"))) { + return 208; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -120; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || - Item.val.uCount != 1 || - puTags[0] != 0x17 || - Out.uNumUsed != 1) { - return -121; - } + return 0; +} - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -122; - } - if(Item.uDataType != QCBOR_TYPE_INT64 || - !QCBORDecode_IsTagged(&DCtx, &Item, 8) || - Item.val.int64 != -3 || - puTags[0] != 8 || - Out.uNumUsed != 1) { - return -123; - } - if(QCBORDecode_Finish(&DCtx)) { - return -124; - } +// Input for one of the tagging tests +static const uint8_t spTagInput[] = { + 0xd9, 0xd9, 0xf7, // CBOR magic number + 0x81, // Array of one + 0xd8, 0x04, // non-preferred serialization of tag 4, decimal fraction + 0x82, // Array of two that is the faction 1/3 + 0x01, + 0x03, - UsefulBufC DateString; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), - QCBOR_DECODE_MODE_NORMAL); + /* + More than 4 tags on an item 225(226(227(228(229([]))))) + */ + 0xd8, 0xe1, + 0xd8, 0xe2, + 0xd8, 0xe3, + 0xd8, 0xe4, + 0xd8, 0xe5, + 0x80, - QCBORDecode_EnterArray(&DCtx, NULL); - // tagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - // untagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { - return 100; - } - // untagged byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 101; - } - // tagged regex - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 102; - } - // tagged date string with a byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 103; - } - // The exit errors out because the last item, the date string with - // bad content makes the array untraversable (the bad date string - // could have tag content of an array or such that is not consumed - // by the date decoding). - QCBORDecode_ExitArray(&DCtx); - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 104; - } + /* tag 10489608748473423768( + 2442302356( + 21590( + 240( + [])))) + */ + 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0xda, 0x91, 0x92, 0x93, 0x94, + 0xd9, 0x54, 0x56, + 0xd8, 0xf0, + 0x80, + /* tag 21590( + 10489608748473423768( + 2442302357( + 65534( + [])))) + */ + 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, + 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0xda, 0x91, 0x92, 0x93, 0x95, + 0xd9, 0xff, 0xfe, + 0x80, - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), - QCBOR_DECODE_MODE_NORMAL); + /* Make sure to blow past the limit of tags that must be mapped. + works in conjuntion with entries above. + 269488144(269488145(269488146(269488147([])))) + */ + 0xda, 0x10, 0x10, 0x10, 0x10, + 0xda, 0x10, 0x10, 0x10, 0x11, + 0xda, 0x10, 0x10, 0x10, 0x12, + 0xda, 0x10, 0x10, 0x10, 0x13, + 0x80, - QCBORDecode_EnterArray(&DCtx, NULL); - // tagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - // untagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { - return 200; - } - // untagged byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 201; - } - // tagged regex - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 202; - } - // tagged date string with a byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 203; - } - // See comments above - QCBORDecode_ExitArray(&DCtx); - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 204; - } + /* An invalid decimal fraction with an additional tag */ + 0xd9, 0xff, 0xfa, + 0xd8, 0x02, // non-preferred serialization of tag 2, a big num + 0x00, // the integer 0; should be a byte string +}; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), - QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_EnterArray(&DCtx, NULL); - // tagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 300; - } - // untagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 301; - } - // untagged byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 302; - } - // tagged regex - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 303; - } - // tagged date string with a byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 304; - } - // See comments above - QCBORDecode_ExitArray(&DCtx); - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 305; - } +/* + DB 9192939495969798 # tag(10489608748473423768) + 80 # array(0) + */ +static const uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x80}; - return 0; -} +/* +DB 9192939495969798 # tag(10489608748473423768) + D8 88 # tag(136) + C6 # tag(6) + C7 # tag(7) + 80 # array(0) +*/ +static const uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80}; /* - * These are showing the big numbers converted to integers. - * The tag numbers are not shown. - * - * [ 18446744073709551616, - * -18446744073709551617, - * {"BN+": 18446744073709551616, - * 64: 18446744073709551616, - * "BN-": -18446744073709551617, - * -64: -18446744073709551617 - * } - * ] + 55799(55799(55799({ + 6(7(-23)): 5859837686836516696(7({ + 7(-20): 11({ + 17(-18): 17(17(17("Organization"))), + 9(-17): 773("SSG"), + -15: 16(17(6(7("Confusion")))), + 17(-16): 17("San Diego"), + 17(-14): 17("US") + }), + 23(-19): 19({ + -11: 9({ + -9: -7 + }), + 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A') + }) + })), + 16(-22): 23({ + 11(8(7(-5))): 8(-3) + }) + }))) */ +static const uint8_t spCSRWithTags[] = { + 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, + 0xc6, 0xc7, 0x36, + 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, + 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, + 0xcb, 0xa5, + 0xd1, 0x31, + 0xd1, 0xd1, 0xd1, 0x6c, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0xc9, 0x30, + 0xd9, 0x03, 0x05, 0x63, + 0x53, 0x53, 0x47, + 0x2e, + 0xd0, 0xd1, 0xc6, 0xc7, + 0x69, + 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0xd1, 0x2f, + 0xd1, 0x69, + 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, + 0xd1, 0x2d, + 0xd1, 0x62, + 0x55, 0x53, + 0xd7, 0x32, + 0xd3, 0xa2, + 0x2a, + 0xc9, 0xa1, + 0x28, + 0x26, + 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, + 0xcc, 0x4a, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, + 0xd0, 0x35, + 0xd7, 0xa1, + 0xcb, 0xc8, 0xc7, 0x24, + 0xc8, 0x22}; -static const uint8_t spBigNumInput[] = { - 0x83, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xA4, - 0x63, 0x42, 0x4E, 0x2B, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x40, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x42, 0x4E, 0x2D, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x3F, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -#ifndef QCBOR_DISABLE_TAGS -/* The expected big num */ -static const uint8_t spBigNum[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}; -#endif /* QCBOR_DISABLE_TAGS */ +static const uint8_t spSpiffyTagInput[] = { + 0x85, // Open array + + 0xc0, // tag for string date + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string -int32_t BignumParseTest(void) + 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string + + 0xd8, 0x23, // tag for regex + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + + 0xc0, // tag for string date + 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string + + // This last case makes the array untraversable because it is + // an uncrecoverable error. Make sure it stays last and is the only + // instance so the other tests can work. +}; + + +static const uint8_t spTaggedString[] = { + 0xd8, 0xf0, 0x61, 0x40, +}; + +static const uint8_t spTaggedInt[] = { + 0xd8, 0xf4, 0x01, +}; + +static int32_t CheckCSRMaps(QCBORDecodeContext *pDC); + + +int32_t OptTagParseTest(void) { QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + QCBORItem Item; + QCBORError uError; + UsefulBufC UBC; + int64_t nInt; + QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput), QCBOR_DECODE_MODE_NORMAL); - - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_ARRAY) { + /* + This test matches the magic number tag and the fraction tag + 55799([...]) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS) { return -2; } - -#ifndef QCBOR_DISABLE_TAGS - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { return -3; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + } + + /* + 4([1,3]) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); +#ifdef QCBOR_DISABLE_EXP_AND_MANTISSA + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_DECIMAL_FRACTION || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 || + Item.val.uCount != 2) { return -4; } + // consume the items in the array + uError = QCBORDecode_GetNext(&DCtx, &Item); + uError = QCBORDecode_GetNext(&DCtx, &Item); - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) +#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 ) { return -5; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -6; } +#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -7; - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -8; + /* + More than 4 tags on an item 225(226(227(228(229([]))))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_ERR_TOO_MANY_TAGS) { + return -6; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -9; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -10; + if(QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64) { + return -106; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -11; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - Item.uLabelType != QCBOR_TYPE_INT64 || - Item.label.int64 != 64 || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -12; + + /* tag 10489608748473423768( + 2442302356( + 21590( + 240( + [])))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_ARRAY || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 10489608748473423768ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 2442302356ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 21590ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 240ULL) { + return -7; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -13; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -14; + /* tag 21590( + 10489608748473423768( + 2442302357( + 21591( + [])))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_ARRAY || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 65534ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 2442302357ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 10489608748473423768ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 21590ULL) { + return -8; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -15; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - Item.uLabelType != QCBOR_TYPE_INT64 || - Item.label.int64 != -64 || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -16; + /* Make sure to blow past the limit of tags that must be mapped. + works in conjuntion with entries above. + 269488144(269488145(269488146(269488147([])))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_ERR_TOO_MANY_TAGS) { + return -9; } -#else - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_TAGS_DISABLED) { - return -100; + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError == QCBOR_SUCCESS) { + return -10; } -#endif /* QCBOR_DISABLE_TAGS */ - - return 0; -} - + // ---------------------------------- + // This test sets up a caller-config list that includes the very large + // tage and then matches it. Caller-config lists are no longer + // used or needed. This tests backwards compatibility with them. + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), + QCBOR_DECODE_MODE_NORMAL); + const uint64_t puList[] = {0x9192939495969798, 257}; + const QCBORTagListIn TL = {2, puList}; + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); -static int32_t CheckItemWithIntLabel(QCBORDecodeContext *pCtx, - uint8_t uDataType, - uint8_t uNestingLevel, - uint8_t uNextNest, - int64_t nLabel, - QCBORItem *pItem) -{ - QCBORItem Item; - QCBORError nCBORError; - - if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; - if(Item.uDataType != uDataType) return -1; - if(uNestingLevel > 0) { - if(Item.uLabelType != QCBOR_TYPE_INT64 && - Item.uLabelType != QCBOR_TYPE_UINT64) { - return -1; - } - if(Item.uLabelType == QCBOR_TYPE_INT64) { - if(Item.label.int64 != nLabel) return -1; - } else { - if(Item.label.uint64 != (uint64_t)nLabel) return -1; - } + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -8; } - if(Item.uNestingLevel != uNestingLevel) return -1; - if(Item.uNextNestLevel != uNextNest) return -1; - - if(pItem) { - *pItem = Item; + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || + QCBORDecode_IsTagged(&DCtx, &Item, 257) || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || + Item.val.uCount != 0) { + return -9; } - return 0; -} - - -// Same code checks definite and indefinite length versions of the map -static int32_t CheckCSRMaps(QCBORDecodeContext *pDC) -{ - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -2; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -3; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -4; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -5; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -6; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -7; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -8; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -9; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -10; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -11; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -12; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -13; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -14; - - if(QCBORDecode_Finish(pDC)) return -20; - - return 0; -} - - -/* -{ - -23: { - -20: { - -18: "Organization", - -17: "SSG", - -15: "Confusion", - -16: "San Diego", - -14: "US" - }, - -19: { - -11: { - -9: -7 - }, - -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' - } - }, - -22: { - -5: -3 - } -} -*/ -static const uint8_t spCSRInput[] = { - 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, - 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, - 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, - 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, - 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; - -// Same map as above, but using indefinite lengths -static const uint8_t spCSRInputIndefLen[] = { - 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, - 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, - 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, - 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, - 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, - 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; - - -int32_t NestedMapTest(void) -{ - QCBORDecodeContext DCtx; + //------------------------ + // Sets up a caller-configured list and look up something not in it + // Another backwards compatibility test. + const uint64_t puLongList[17] = {1,2,1}; + const QCBORTagListIn TLLong = {17, puLongList}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -11; + } - return CheckCSRMaps(&DCtx); -} - - + uint64_t puTags[4]; + QCBORTagListOut Out = {0, 4, puTags}; -int32_t StringDecoderModeFailTest(void) -{ - QCBORDecodeContext DCtx; + // This tests retrievel of the full tag list QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), - QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); - - QCBORItem Item; - QCBORError nCBORError; - - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -1; + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), + QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -12; } - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -2; + if(puTags[0] != 0x9192939495969798 || + puTags[1] != 0x88 || + puTags[2] != 0x06 || + puTags[3] != 0x07) { + return -13; } - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { - return -3; + // ---------------------- + // This tests too small of an out list + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), + QCBOR_DECODE_MODE_NORMAL); + QCBORTagListOut OutSmall = {0, 3, puTags}; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { + return -14; } - return 0; -} - - -int32_t NestedMapTestIndefLen(void) -{ - QCBORDecodeContext DCtx; + // --------------- + // Decode a version of the "CSR" that has had a ton of tags randomly inserted + // It is a bit of a messy test and maybe could be improved, but + // it is retained as a backwards compatibility check. QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL); + int n = CheckCSRMaps(&DCtx); + if(n) { + return n-2000; + } - return CheckCSRMaps(&DCtx); -} - + Out = (QCBORTagListOut){0, 16, puTags}; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_NORMAL); + /* With the spiffy decode revision, this tag list is not used. + It doesn't matter if a tag is in this list or not so some + tests that couldn't process a tag because it isn't in this list + now can process these unlisted tags. The tests have been + adjusted for this. */ + const uint64_t puTagList[] = {773, 1, 90599561}; + const QCBORTagListIn TagList = {3, puTagList}; + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); -static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) -{ - UsefulOutBuf UOB; - UsefulOutBuf_Init(&UOB, Storage); - int i; - for(i = 0; i < n; i++) { - UsefulOutBuf_AppendByte(&UOB, 0x9f); - } - - for(i = 0; i < n; i++) { - UsefulOutBuf_AppendByte(&UOB, 0xff); + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -100; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || + QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || + Item.val.uCount != 2 || + puTags[0] != CBOR_TAG_CBOR_MAGIC || + puTags[1] != CBOR_TAG_CBOR_MAGIC || + puTags[2] != CBOR_TAG_CBOR_MAGIC || + Out.uNumUsed != 3) { + return -101; } - return UsefulOutBuf_OutUBuf(&UOB); -} - - -static int32_t parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) -{ - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, Nested, 0); - int j; - for(j = 0; j < nNestLevel; j++) { - QCBORItem Item; - QCBORError nReturn = QCBORDecode_GetNext(&DC, &Item); - if(j >= QCBOR_MAX_ARRAY_NESTING) { - // Should be in error - if(nReturn != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { - return -4; - } else { - return 0; // Decoding doesn't recover after an error - } - } else { - // Should be no error - if(nReturn) { - return -9; // Should not have got an error - } - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -7; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -102; } - QCBORError nReturn = QCBORDecode_Finish(&DC); - if(nReturn) { - return -3; + if(Item.uDataType != QCBOR_TYPE_MAP || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || + QCBORDecode_IsTagged(&DCtx, &Item, 6) || + !QCBORDecode_IsTagged(&DCtx, &Item, 7) || + Item.val.uCount != 2 || + puTags[0] != 5859837686836516696 || + puTags[1] != 7 || + Out.uNumUsed != 2) { + return -103; } - return 0; -} - -int32_t IndefiniteLengthNestTest(void) -{ - UsefulBuf_MAKE_STACK_UB(Storage, 50); - int i; - for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { - const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); - int nReturn = parse_indeflen_nested(Nested, i); - if(nReturn) { - return nReturn; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -104; } - return 0; -} - -// [1, [2, 3]] -static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; -// No closing break -static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; -// Not enough closing breaks -static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; -// Too many closing breaks -static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; -// Unclosed indeflen inside def len -static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; -// confused tag -static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; - -int32_t IndefiniteLengthArrayMapTest(void) -{ - QCBORError nResult; - // --- first test ----- - UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); - - // Decode it and see if it is OK - QCBORDecodeContext DC; - QCBORItem Item; - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_GetNext(&DC, &Item); - - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != 0 || - Item.uNextNestLevel != 1) { - return -111; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 1 || - Item.uNextNestLevel != 1) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != 1 || - Item.uNextNestLevel != 2) { - return -3; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 2 || - Item.uNextNestLevel != 2) { - return -4; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 2 || - Item.uNextNestLevel != 0) { - return -5; - } - - if(QCBORDecode_Finish(&DC)) { - return -6; - } - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -7; + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 5 || + puTags[0] != 0x0b || + Out.uNumUsed != 1) { + return -105; } - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -8; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -106; } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -9; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || + Item.val.string.len != 12 || + puTags[0] != CBOR_TAG_COSE_MAC0 || + puTags[1] != CBOR_TAG_COSE_MAC0 || + puTags[2] != CBOR_TAG_COSE_MAC0 || + Out.uNumUsed != 3) { + return -105; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -10; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -107; } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { - return -11; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 773) || + Item.val.string.len != 3 || + puTags[0] != 773 || + Out.uNumUsed != 1) { + return -108; } - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -12; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -109; } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -13; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 16) || + Item.val.string.len != 9 || + puTags[0] != 16 || + puTags[3] != 7 || + Out.uNumUsed != 4) { + return -110; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_SUCCESS) { - return -14; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -111; } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_ERR_BAD_BREAK) { - return -140; - } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -15; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 17) || + Item.val.string.len != 9 || + puTags[0] != 17 || + Out.uNumUsed != 1) { + return -112; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -16; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -111; } - - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -17; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 17) || + Item.val.string.len != 2 || + puTags[0] != 17 || + Out.uNumUsed != 1) { + return -112; } - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - -#ifndef QCBOR_DISABLE_TAGS - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -18; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -113; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, 19) || + Item.val.uCount != 2 || + puTags[0] != 19 || + Out.uNumUsed != 1) { + return -114; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_ERR_BAD_BREAK) { - return -19; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -115; } -#else /* QCBOR_DISABLE_TAGS */ - if(nResult != QCBOR_ERR_TAGS_DISABLED) { - return -20; + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, 9) || + Item.val.uCount != 1 || + puTags[0] != 9 || + Out.uNumUsed != 1) { + return -116; } -#endif /* QCBOR_DISABLE_TAGS */ - - return 0; -} - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - -static const uint8_t spIndefiniteLenString[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad2[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad3[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x01, 0x02, // Not a string - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad4[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - // missing end of string -}; - -static const uint8_t spIndefiniteLenStringLabel[] = { - 0xa1, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - 0xff, // ending break - 0x01 // integer being labeled. -}; - -/** - Make an indefinite length string - - @param Storage Storage for string, must be 144 bytes in size - @return The indefinite length string - - This makes an array with one indefinite length string that has 7 chunks - from size of 1 byte up to 64 bytes. - */ -static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) -{ - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, Storage); - UsefulOutBuf_AppendByte(&UOB, 0x81); - UsefulOutBuf_AppendByte(&UOB, 0x5f); - uint8_t uStringByte = 0; - // Use of type int is intentional - for(int uChunkSize = 1; uChunkSize <= 128; uChunkSize *= 2) { - // Not using preferred encoding here, but that is OK. - UsefulOutBuf_AppendByte(&UOB, 0x58); - UsefulOutBuf_AppendByte(&UOB, (uint8_t)uChunkSize); - for(int j = 0; j < uChunkSize; j++) { - UsefulOutBuf_AppendByte(&UOB, uStringByte); - uStringByte++; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -116; } - UsefulOutBuf_AppendByte(&UOB, 0xff); - - return UsefulOutBuf_OutUBuf(&UOB); -} - -static int CheckBigString(UsefulBufC BigString) -{ - if(BigString.len != 255) { - return 1; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -7 || + Out.uNumUsed != 0) { + return -117; } - for(uint8_t i = 0; i < 255; i++){ - if(((const uint8_t *)BigString.ptr)[i] != i) { - return 1; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -118; } - return 0; -} - - -int32_t IndefiniteLengthStringTest(void) -{ - QCBORDecodeContext DC; - QCBORItem Item; - // big enough for MakeIndefiniteBigBstr() + MemPool overhead - UsefulBuf_MAKE_STACK_UB(MemPool, 350); - - // --- Simple normal indefinite length string ------ - UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -1; + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.val.string.len != 10 || + puTags[0] != 12 || + Out.uNumUsed != 1) { + return -119; } - if(QCBORDecode_GetNext(&DC, &Item)) { - return -2; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -120; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { - return -3; + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || + Item.val.uCount != 1 || + puTags[0] != 0x17 || + Out.uNumUsed != 1) { + return -121; } - if(QCBORDecode_GetNext(&DC, &Item)) { - return -4; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -122; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { - return -5; + if(Item.uDataType != QCBOR_TYPE_INT64 || + !QCBORDecode_IsTagged(&DCtx, &Item, 8) || + Item.val.int64 != -3 || + puTags[0] != 8 || + Out.uNumUsed != 1) { + return -123; } - if(QCBORDecode_Finish(&DC)) { - return -6; + + if(QCBORDecode_Finish(&DCtx)) { + return -124; } - // ----- types mismatch --- - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), + UsefulBufC DateString; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -7; + QCBORDecode_EnterArray(&DCtx, NULL); + // tagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + // untagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { + return 100; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -8; + // untagged byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 101; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -9; + // tagged regex + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 102; } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { - return -10; + // tagged date string with a byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 103; + } + // The exit errors out because the last item, the date string with + // bad content makes the array untraversable (the bad date string + // could have tag content of an array or such that is not consumed + // by the date decoding). + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 104; } - // ----- not a string --- - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), - QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -11; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterMap(&DCtx, NULL); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 55799) { + return 200; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -12; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 55799) { + return 202; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -13; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != 55799) { + return 203; } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { - return -14; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 204; } - // ----- no end ----- - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), - QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -15; + QCBORDecode_EnterMap(&DCtx, NULL); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) { + return 210; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -16; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 5859837686836516696) { + return 212; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -17; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != CBOR_TAG_INVALID64) { + return 213; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 214; } - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { - return -18; - } - - // ------ Don't set a string allocator and see an error ----- - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -19; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_EnterMapFromMapN(&DCtx, -23); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) { + return 220; } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { - return -20; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 5859837686836516696) { + return 221; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != CBOR_TAG_INVALID64) { + return 222; } - // ----- Mempool is way too small ----- - UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, QCBOR_DECODE_MIN_MEM_POOL_SIZE-1); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { - return -21; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_MAP_AS_ARRAY); + QCBORDecode_EnterArray(&DCtx, NULL); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 55799) { + return 230; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 55799) { + return 231; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != 55799) { + return 232; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 234; + } + QCBORDecode_GetInt64(&DCtx, &nInt); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) { + return 240; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 6) { + return 241; } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != CBOR_TAG_INVALID64) { + return 242; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 243; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - // ----- Mempool is way too small ----- - UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); - const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); - // 80 is big enough for MemPool overhead, but not BigIndefBStr - UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); - QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { - return -22; - } + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), + QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -23; + QCBORDecode_EnterArray(&DCtx, NULL); + // tagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + // untagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { + return 250; } - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { - return -24; + // untagged byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 251; } - - // ---- big bstr ----- - QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -25; + // tagged regex + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 252; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -26; + // tagged date string with a byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 253; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { - return -26; + // See comments above + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 254; } - if(QCBORDecode_GetNext(&DC, &Item)) { - return -27; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), + QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_EnterArray(&DCtx, NULL); + // tagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 300; } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { - return -28; + // untagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 301; } - if(CheckBigString(Item.val.string)) { - return -3; + // untagged byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 302; } - if(QCBORDecode_Finish(&DC)) { - return -29; + // tagged regex + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 303; + } + // tagged date string with a byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 304; + } + // See comments above + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 305; } - // --- label is an indefinite length string ------ - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedString), + QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -30; + /* See that QCBORDecode_GetTextString() ignores tags */ + QCBORDecode_GetTextString(&DCtx, &UBC); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 400; + } + if(UBC.len != 1) { + return 401; } - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -31; + uint64_t uTagNumber = QCBORDecode_GetNthTagOfLast(&DCtx, 0); + if(uTagNumber != 240) { + return 404; } - if(QCBORDecode_GetNext(&DC, &Item)){ - return -32; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedInt), + QCBOR_DECODE_MODE_NORMAL); + /* See that QCBORDecode_GetInt64() ignores tags */ + QCBORDecode_GetInt64(&DCtx, &nInt); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 410; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.uDataAlloc || !Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { - return -33; + if(nInt != 1) { + return 411; } - if(QCBORDecode_Finish(&DC)) { - return -34; + uTagNumber = QCBORDecode_GetNthTagOfLast(&DCtx, 0); + if(uTagNumber != 244) { + return 414; } return 0; } +/* + * These are showing the big numbers converted to integers. + * The tag numbers are not shown. + * + * [ + * 18446744073709551616, + * -18446744073709551617, + * { + * -64: -18446744073709551617, + * 64: 18446744073709551616, + * "BN+": 18446744073709551616, + * "BN-": -18446744073709551617 + * } + * ] + */ -int32_t AllocAllStringsTest(void) +static const uint8_t spBigNumInput[] = { + 0x83, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA4, + 0x38, 0x3F, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x40, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x42, 0x4E, 0x2B, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x42, 0x4E, 0x2D, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#ifndef QCBOR_DISABLE_TAGS +/* The expected big num */ +static const uint8_t spBigNum[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}; +#endif /* QCBOR_DISABLE_TAGS */ + + +int32_t BignumParseTest(void) { - QCBORDecodeContext DC; + QCBORDecodeContext DCtx; + QCBORItem Item; QCBORError nCBORError; - - // First test, use the "CSRMap" as easy input and checking - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. - if(nCBORError) { + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -1; - } - - if(CheckCSRMaps(&DC)) { + if(Item.uDataType != QCBOR_TYPE_ARRAY) { return -2; } - // Next parse, save pointers to a few strings, destroy original and - // see all is OK. - UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); - - QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_Set(Pool, '/'); - QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. - - QCBORItem Item1, Item2, Item3, Item4; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return (int32_t)nCBORError; - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3) +#ifndef QCBOR_DISABLE_TAGS + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -3; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return (int32_t)nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) - return (int32_t)nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) - return (int32_t)nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) - return (int32_t)nCBORError; - - UsefulBuf_Set(CopyOfStorage, '_'); - - if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item1.uDataType != QCBOR_TYPE_INT64 || - Item1.val.int64 != 42 || - Item1.uDataAlloc != 0 || - Item1.uLabelAlloc == 0 || - UsefulBufCompareToSZ(Item1.label.string, "first integer")) { + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ return -4; } - - if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item2.label.string, "an array of two strings") || - Item2.uDataType != QCBOR_TYPE_ARRAY || - Item2.uDataAlloc != 0 || - Item2.uLabelAlloc == 0 || - Item2.val.uCount != 2) + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -5; - - if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || - Item3.uDataAlloc == 0 || - Item3.uLabelAlloc != 0 || - UsefulBufCompareToSZ(Item3.val.string, "string1")) { + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ return -6; } - if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || - Item4.uDataAlloc == 0 || - Item4.uLabelAlloc != 0 || - UsefulBufCompareToSZ(Item4.val.string, "string2")) { + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -7; + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -8; } - // Next parse with a pool that is too small - UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), - QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return -8; - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3) { - return -9; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -15; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + Item.uLabelType != QCBOR_TYPE_INT64 || + Item.label.int64 != -64 || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -16; } - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { - nCBORError = QCBORDecode_GetNext(&DC, &Item4); - } - } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -11; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + Item.uLabelType != QCBOR_TYPE_INT64 || + Item.label.int64 != 64 || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -12; } - if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -9; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ return -10; } + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -13; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -14; + } + + +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + +#else + + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_TAGS_DISABLED) { + return -100; + } +#endif /* QCBOR_DISABLE_TAGS */ + return 0; } -int32_t MemPoolTest(void) +static int32_t CheckItemWithIntLabel(QCBORDecodeContext *pCtx, + uint8_t uDataType, + uint8_t uNestingLevel, + uint8_t uNextNest, + int64_t nLabel, + QCBORItem *pItem) { - // Set up the decoder with a tiny bit of CBOR to parse because - // nothing can be done with it unless that is set up. - QCBORDecodeContext DC; - const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + QCBORItem Item; + QCBORError nCBORError; + + if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; + if(Item.uDataType != uDataType) return -1; + if(uNestingLevel > 0) { + if(Item.uLabelType != QCBOR_TYPE_INT64) { + return -1; + } + if(Item.label.int64 != nLabel) { + return -1; + } - // Set up an memory pool of 100 bytes - // Then fish into the internals of the decode context - // to get the allocator function so it can be called directly. - // Also figure out how much pool is available for use - // buy subtracting out the overhead. - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); - if(nError) { - return -9; } - QCBORStringAllocate pAlloc = DC.StringAllocator.pfAllocator; - void *pAllocCtx = DC.StringAllocator.pAllocateCxt; - size_t uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; + if(Item.uNestingLevel != uNestingLevel) return -1; + if(Item.uNextNestLevel != uNextNest) return -1; - // First test -- ask for one more byte than available and see failure - UsefulBuf Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool+1); - if(!UsefulBuf_IsNULL(Allocated)) { - return -1; + if(pItem) { + *pItem = Item; } + return 0; +} - // Re do the set up for the next test that will do a successful alloc, - // a fail, a free and then success - QCBORDecode_SetMemPool(&DC, Pool, 0); - pAlloc = DC.StringAllocator.pfAllocator; - pAllocCtx = DC.StringAllocator.pAllocateCxt; - uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; +// Same code checks definite and indefinite length versions of the map +static int32_t CheckCSRMaps(QCBORDecodeContext *pDC) +{ + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; - // Allocate one byte less than available and see success - Allocated = (pAlloc)(pAllocCtx, NULL, uAvailPool-1); - if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed - return -2; - } - // Ask for some more and see failure - UsefulBuf Allocated2 = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); - if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail - return -3; - } - // Free the first allocate, retry the second and see success - (*pAlloc)(pAllocCtx, Allocated.ptr, 0); // Free - Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); - if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free - return -4; - } + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -2; - // Re do set up for next test that involves a successful alloc, - // and a successful realloc and a failed realloc - QCBORDecode_SetMemPool(&DC, Pool, 0); - pAlloc = DC.StringAllocator.pfAllocator; - pAllocCtx = DC.StringAllocator.pAllocateCxt; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -3; - // Allocate half the pool and see success - Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); - if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed - return -5; - } - // Reallocate to take up the whole pool and see success - Allocated2 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool); - if(UsefulBuf_IsNULL(Allocated2)) { - return -6; - } - // Make sure its the same pointer and the size is right - if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { - return -7; - } - // Try to allocate more to be sure there is failure after a realloc - UsefulBuf Allocated3 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool+1); - if(!UsefulBuf_IsNULL(Allocated3)) { - return -8; - } + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -4; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -5; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -6; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -7; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -8; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -9; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -10; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -11; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -12; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -13; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -14; + + if(QCBORDecode_Finish(pDC)) return -20; return 0; } -/* Just enough of an allocator to test configuration of one */ -static UsefulBuf AllocateTestFunction(void *pCtx, void *pOldMem, size_t uNewSize) +/* { - (void)pOldMem; // unused variable - - if(uNewSize) { - // Assumes the context pointer is the buffer and - // nothing too big will ever be asked for. - // This is only good for this basic test! - return (UsefulBuf) {pCtx, uNewSize}; - } else { - return NULLUsefulBuf; - } + -23: { + -20: { + -18: "Organization", + -17: "SSG", + -15: "Confusion", + -16: "San Diego", + -14: "US" + }, + -19: { + -11: { + -9: -7 + }, + -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' + } + }, + -22: { + -5: -3 + } } +*/ +static const uint8_t spCSRInput[] = { + 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, + 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, + 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, + 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, + 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; + +// Same map as above, but using indefinite lengths +static const uint8_t spCSRInputIndefLen[] = { + 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, + 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, + 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, + 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, + 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, + 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; -int32_t SetUpAllocatorTest(void) +int32_t NestedMapTest(void) { - // Set up the decoder with a tiny bit of CBOR to parse because - // nothing can be done with it unless that is set up. - QCBORDecodeContext DC; - const uint8_t pMinimalCBOR[] = {0x62, 0x48, 0x69}; // "Hi" - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + QCBORDecodeContext DCtx; - uint8_t pAllocatorBuffer[50]; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBOR_DECODE_MODE_NORMAL); - // This is really just to test that this call works. - // The full functionality of string allocators is tested - // elsewhere with the MemPool internal allocator. - QCBORDecode_SetUpAllocator(&DC, AllocateTestFunction, pAllocatorBuffer, 1); + return CheckCSRMaps(&DCtx); +} + + + +int32_t StringDecoderModeFailTest(void) +{ + QCBORDecodeContext DCtx; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); QCBORItem Item; - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_SUCCESS) { + QCBORError nCBORError; + + if(QCBORDecode_GetNext(&DCtx, &Item)) { return -1; } - - if(Item.uDataAlloc == 0 || - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.val.string.ptr != pAllocatorBuffer) { + if(Item.uDataType != QCBOR_TYPE_MAP) { return -2; } - if(QCBORDecode_Finish(&DC) != QCBOR_SUCCESS) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { return -3; } return 0; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -struct EaMTest { - const char *szName; - UsefulBufC Input; - uint8_t uTagRequirement; - bool bHasTags; +int32_t NestedMapTestIndefLen(void) +{ + QCBORDecodeContext DCtx; - /* Expected values for GetNext */ - QCBORError uExpectedErrorGN; - uint8_t uQCBORTypeGN; - int64_t nExponentGN; - int64_t nMantissaGN; - UsefulBufC MantissaGN; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), + QCBOR_DECODE_MODE_NORMAL); - /* Expected values for GetDecimalFraction */ - QCBORError uExpectedErrorGDF; - int64_t nExponentGDF; - int64_t nMantissaGDF; + return CheckCSRMaps(&DCtx); +} - /* Expected values for GetDecimalFractionBig */ - QCBORError uExpectedErrorGDFB; - int64_t nExponentGDFB; - UsefulBufC MantissaGDFB; - bool IsNegativeGDFB; - /* Expected values for GetBigFloat */ - QCBORError uExpectedErrorGBF; - int64_t nExponentGBF; - int64_t nMantissaGBF; - /* Expected values for GetBigFloatBig */ - QCBORError uExpectedErrorGBFB; - int64_t nExponentGBFB; - UsefulBufC MantissaGBFB; - bool IsNegativeGBFB; -}; +static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) +{ + UsefulOutBuf UOB; + UsefulOutBuf_Init(&UOB, Storage); + int i; + for(i = 0; i < n; i++) { + UsefulOutBuf_AppendByte(&UOB, 0x9f); + } + for(i = 0; i < n; i++) { + UsefulOutBuf_AppendByte(&UOB, 0xff); + } + return UsefulOutBuf_OutUBuf(&UOB); +} -static const struct EaMTest pEaMTests[] = { - { - "1. Untagged pair (big float or decimal fraction), no tag required", - {(const uint8_t []){0x82, 0x20, 0x03}, 3}, - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - false, - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_ARRAY, - 0, - 0, - {(const uint8_t []){0x00}, 1}, +static int32_t parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) +{ + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, Nested, 0); - QCBOR_SUCCESS, /* GetDecimalFraction */ - -1, - 3, + int j; + for(j = 0; j < nNestLevel; j++) { + QCBORItem Item; + QCBORError nReturn = QCBORDecode_GetNext(&DC, &Item); + if(j >= QCBOR_MAX_ARRAY_NESTING) { + // Should be in error + if(nReturn != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { + return -4; + } else { + return 0; // Decoding doesn't recover after an error + } + } else { + // Should be no error + if(nReturn) { + return -9; // Should not have got an error + } + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -7; + } + } + QCBORError nReturn = QCBORDecode_Finish(&DC); + if(nReturn) { + return -3; + } + return 0; +} - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -1, - {(const uint8_t []){0x03}, 1}, - false, - QCBOR_SUCCESS, /* for GetBigFloat */ - -1, - 3, +int32_t IndefiniteLengthNestTest(void) +{ + UsefulBuf_MAKE_STACK_UB(Storage, 50); + int i; + for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { + const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); + int nReturn = parse_indeflen_nested(Nested, i); + if(nReturn) { + return nReturn; + } + } + return 0; +} - QCBOR_SUCCESS, /* for GetBigFloatBig */ - -1, - {(const uint8_t []){0x03}, 1}, - false - }, +// [1, [2, 3]] +static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; +// No closing break +static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; +// Not enough closing breaks +static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; +// Too many closing breaks +static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; +// Unclosed indeflen inside def len +static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; +// confused tag +static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; - { - "2. Untagged pair (big float or decimal fraction), tag required", - {(const uint8_t []){0x82, 0x20, 0x03}, 3}, - QCBOR_TAG_REQUIREMENT_TAG, - false, +int32_t IndefiniteLengthArrayMapTest(void) +{ + QCBORError nResult; + // --- first test ----- + UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_ARRAY, - 0, - 0, - {(const uint8_t []){0x00}, 1}, + // Decode it and see if it is OK + QCBORDecodeContext DC; + QCBORItem Item; + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ - 0, - 0, + QCBORDecode_GetNext(&DC, &Item); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false, + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != 0 || + Item.uNextNestLevel != 1) { + return -111; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 1 || + Item.uNextNestLevel != 1) { + return -2; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != 1 || + Item.uNextNestLevel != 2) { + return -3; + } - }, + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 2 || + Item.uNextNestLevel != 2) { + return -4; + } - { - "3. Tagged 1.5 decimal fraction, tag 4 optional", - {(const uint8_t []){0xC4, 0x82, 0x20, 0x03}, 4}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 2 || + Item.uNextNestLevel != 0) { + return -5; + } - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION, - -1, - 3, - {(const uint8_t []){0x00}, 1}, + if(QCBORDecode_Finish(&DC)) { + return -6; + } + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); - QCBOR_SUCCESS, /* for GetDecimalFraction */ - -1, - 3, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -1, - {(const uint8_t []){0x03}, 1}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -7; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -8; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false - }, - { - "4. Tagged 100 * 2^300 big float, tag 5 optional", - {(const uint8_t []){0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 7}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_BIGFLOAT, - 300, - 100, - {(const uint8_t []){0x00}, 1}, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -9; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ - 0, - {(const uint8_t []){0x03}, 1}, - false, - - QCBOR_SUCCESS, /* for GetBigFloat */ - 300, - 100, - - QCBOR_SUCCESS, /* for GetBigFloatBig */ - 300, - {(const uint8_t []){0x64}, 1}, - false - }, - - { - "5. Tagged 4([-20, 4759477275222530853136]) decimal fraction, tag 4 required", - {(const uint8_t []){0xC4, 0x82, 0x33, - 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 15}, - QCBOR_TAG_REQUIREMENT_TAG, - true, - - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - -20, - 0, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -10; + } - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { + return -11; + } - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -20, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - false, + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -12; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 0}, - false - }, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); - { - "6. Error: Mantissa and exponent inside a Mantissa and exponent", - {(const uint8_t []){0xC4, 0x82, 0x33, - 0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 10}, - QCBOR_TAG_REQUIREMENT_TAG, - true, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - 0, - 0, - {(const uint8_t []){0x00}, 0}, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -13; + } - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_SUCCESS) { + return -14; + } - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFractionBig */ - 0, - {(const uint8_t []){0x00}, 0}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_ERR_BAD_BREAK) { + return -140; + } - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloat */ - 0, - 0, - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 0}, - false - }, - { - "7. Tagged 5([-20, 4294967295]) big float, big num mantissa, tag 5 required", - {(const uint8_t []){0xC5, 0x82, 0x33, - 0xC2, 0x44, 0xff, 0xff, 0xff, 0xff}, 9}, - QCBOR_TAG_REQUIREMENT_TAG, - true, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - -20, - 0, - {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -15; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ - -20, - {(const uint8_t []){0x00}, 1}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -16; + } - QCBOR_SUCCESS, /* for GetBigFloat */ - -20, - 4294967295, + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -17; + } - QCBOR_SUCCESS, /* for GetBigFloatBig */ - -20, - {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, - false - }, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); - { - /* Special case for test 8. Don't renumber it. */ - "8. Untagged pair with big num (big float or decimal fraction), tag optional", - {(const uint8_t []){0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 14}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_ARRAY, - 0, - 0, - {(const uint8_t []){0x00}, 1}, + nResult = QCBORDecode_GetNext(&DC, &Item); - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ - 0, - 0, +#ifndef QCBOR_DISABLE_TAGS + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -18; + } - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -20, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_ERR_BAD_BREAK) { + return -19; + } +#else /* QCBOR_DISABLE_TAGS */ + if(nResult != QCBOR_ERR_TAGS_DISABLED) { + return -20; + } +#endif /* QCBOR_DISABLE_TAGS */ - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */ - 0, - 0, + return 0; +} - QCBOR_SUCCESS, /* for GetBigFloatBig */ - -20, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - false - }, - { - "9. decimal fraction with large exponent and negative big num mantissa", - {(const uint8_t []){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, - 9223372036854775807, - 0, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, +static const uint8_t spIndefiniteLenString[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + 0xff // ending break +}; - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ - 0, - 0, +static const uint8_t spIndefiniteLenStringBad2[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type + 0xff // ending break +}; - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - 9223372036854775807, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - true, +static const uint8_t spIndefiniteLenStringBad3[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x01, 0x02, // Not a string + 0xff // ending break +}; - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, +static const uint8_t spIndefiniteLenStringBad4[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + // missing end of string +}; - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false - }, +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +static const uint8_t spIndefiniteLenStringLabel[] = { + 0xa1, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + 0xff, // ending break + 0x01 // integer being labeled. }; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +/** + Make an indefinite length string + @param Storage Storage for string, must be 144 bytes in size + @return The indefinite length string -int32_t ProcessEaMTests(void) + This makes an array with one indefinite length string that has 7 chunks + from size of 1 byte up to 64 bytes. + */ +static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) { - size_t uIndex; - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError uError; - int64_t nMantissa, nExponent; - MakeUsefulBufOnStack( MantissaBuf, 200); - UsefulBufC Mantissa; - bool bMantissaIsNegative; - - for(uIndex = 0; uIndex < C_ARRAY_COUNT(pEaMTests, struct EaMTest); uIndex++) { - const struct EaMTest *pT = &pEaMTests[uIndex]; - /* Decode with GetNext */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - - if(uIndex + 1 == 9) { - nExponent = 99; // just to set a break point - } + UsefulOutBuf UOB; - uError = QCBORDecode_GetNext(&DCtx, &Item); -#ifdef QCBOR_DISABLE_TAGS - /* Test 8 is a special case when tags are disabled */ - if(pT->bHasTags && uIndex + 1 != 8) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 9; - } - } else { -#endif - /* Now check return code, data type, mantissa and exponent */ - if(pT->uExpectedErrorGN != uError) { - return (int32_t)(1+uIndex) * 1000 + 1; - } - if(uError == QCBOR_SUCCESS && pT->uQCBORTypeGN != QCBOR_TYPE_ARRAY) { - if(pT->uQCBORTypeGN != Item.uDataType) { - return (int32_t)(1+uIndex) * 1000 + 2; - } - if(pT->nExponentGN != Item.val.expAndMantissa.nExponent) { - return (int32_t)(1+uIndex) * 1000 + 3; - } - if(Item.uDataType == QCBOR_TYPE_DECIMAL_FRACTION || Item.uDataType == QCBOR_TYPE_BIGFLOAT ) { - if(pT->nMantissaGN != Item.val.expAndMantissa.Mantissa.nInt) { - return (int32_t)(1+uIndex) * 1000 + 4; - } - } else { - if(UsefulBuf_Compare(Item.val.expAndMantissa.Mantissa.bigNum, pT->MantissaGN)) { - return (int32_t)(1+uIndex) * 1000 + 5; - } - } - } -#ifdef QCBOR_DISABLE_TAGS - } -#endif + UsefulOutBuf_Init(&UOB, Storage); + UsefulOutBuf_AppendByte(&UOB, 0x81); + UsefulOutBuf_AppendByte(&UOB, 0x5f); - /* Decode with GetDecimalFraction */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetDecimalFraction(&DCtx, - pT->uTagRequirement, - &nMantissa, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 39; - } - } else { -#endif - /* Now check return code, mantissa and exponent */ - if(pT->uExpectedErrorGDF != uError) { - return (int32_t)(1+uIndex) * 1000 + 31; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGDF != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 32; - } - if(pT->nMantissaGDF != nMantissa) { - return (int32_t)(1+uIndex) * 1000 + 33; - } - } -#ifdef QCBOR_DISABLE_TAGS + uint8_t uStringByte = 0; + // Use of type int is intentional + for(int uChunkSize = 1; uChunkSize <= 128; uChunkSize *= 2) { + // Not using preferred encoding here, but that is OK. + UsefulOutBuf_AppendByte(&UOB, 0x58); + UsefulOutBuf_AppendByte(&UOB, (uint8_t)uChunkSize); + for(int j = 0; j < uChunkSize; j++) { + UsefulOutBuf_AppendByte(&UOB, uStringByte); + uStringByte++; } -#endif + } + UsefulOutBuf_AppendByte(&UOB, 0xff); - /* Decode with GetDecimalFractionBig */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetDecimalFractionBig(&DCtx, - pT->uTagRequirement, - MantissaBuf, - &Mantissa, - &bMantissaIsNegative, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 49; - } - } else { -#endif - /* Now check return code, mantissa (bytes and sign) and exponent */ - if(pT->uExpectedErrorGDFB != uError) { - return (int32_t)(1+uIndex) * 1000 + 41; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGDFB != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 42; - } - if(pT->IsNegativeGDFB != bMantissaIsNegative) { - return (int32_t)(1+uIndex) * 1000 + 43; - } - if(UsefulBuf_Compare(Mantissa, pT->MantissaGDFB)) { - return (int32_t)(1+uIndex) * 1000 + 44; - } - } -#ifdef QCBOR_DISABLE_TAGS - } -#endif + return UsefulOutBuf_OutUBuf(&UOB); +} - /* Decode with GetBigFloat */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetBigFloat(&DCtx, - pT->uTagRequirement, - &nMantissa, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 19; - } - } else { -#endif - /* Now check return code, mantissa and exponent */ - if(pT->uExpectedErrorGBF != uError) { - return (int32_t)(1+uIndex) * 1000 + 11; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGBF != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 12; - } - if(pT->nMantissaGBF != nMantissa) { - return (int32_t)(1+uIndex) * 1000 + 13; - } - } -#ifdef QCBOR_DISABLE_TAGS - } -#endif +static int CheckBigString(UsefulBufC BigString) +{ + if(BigString.len != 255) { + return 1; + } - /* Decode with GetBigFloatBig */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetBigFloatBig(&DCtx, - pT->uTagRequirement, - MantissaBuf, - &Mantissa, - &bMantissaIsNegative, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 29; - } - } else { -#endif - /* Now check return code, mantissa (bytes and sign) and exponent */ - if(pT->uExpectedErrorGBFB != uError) { - return (int32_t)(1+uIndex) * 1000 + 21; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGBFB != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 22; - } - if(pT->IsNegativeGBFB != bMantissaIsNegative) { - return (int32_t)(1+uIndex) * 1000 + 23; - } - if(UsefulBuf_Compare(Mantissa, pT->MantissaGBFB)) { - return (int32_t)(1+uIndex) * 1000 + 24; - } - } -#ifdef QCBOR_DISABLE_TAGS + for(uint8_t i = 0; i < 255; i++){ + if(((const uint8_t *)BigString.ptr)[i] != i) { + return 1; } -#endif } - return 0; } -int32_t ExponentAndMantissaDecodeTestsSecondary(void) +int32_t IndefiniteLengthStringTest(void) { -#ifndef QCBOR_DISABLE_TAGS QCBORDecodeContext DC; - QCBORError uErr; - QCBORItem item; - - static const uint8_t spBigNumMantissa[] = {0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x010}; - UsefulBufC BN = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumMantissa); - - - - /* Now encode some stuff and then decode it */ - uint8_t pBuf[40]; - QCBOREncodeContext EC; - UsefulBufC Encoded; - - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf)); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddDecimalFraction(&EC, 999, 1000); // 999 * (10 ^ 1000) - QCBOREncode_AddBigFloat(&EC, 100, INT32_MIN); - QCBOREncode_AddDecimalFractionBigNum(&EC, BN, false, INT32_MAX); - QCBOREncode_CloseArray(&EC); - QCBOREncode_Finish(&EC, &Encoded); + QCBORItem Item; + // big enough for MakeIndefiniteBigBstr() + MemPool overhead + UsefulBuf_MAKE_STACK_UB(MemPool, 350); + // --- Simple normal indefinite length string ------ + UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 100; + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -1; } - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 101; + if(QCBORDecode_GetNext(&DC, &Item)) { + return -2; } - - if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || - item.val.expAndMantissa.nExponent != 1000 || - item.val.expAndMantissa.Mantissa.nInt != 999) { - return 102; + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { + return -3; } - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 103; + if(QCBORDecode_GetNext(&DC, &Item)) { + return -4; } - - if(item.uDataType != QCBOR_TYPE_BIGFLOAT || - item.val.expAndMantissa.nExponent != INT32_MIN || - item.val.expAndMantissa.Mantissa.nInt != 100) { - return 104; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { + return -5; } - - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 105; + if(QCBORDecode_Finish(&DC)) { + return -6; } - if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM || - item.val.expAndMantissa.nExponent != INT32_MAX || - UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { - return 106; + // ----- types mismatch --- + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), + QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -7; } -#endif /* QCBOR_TAGS_DISABLED */ + if(QCBORDecode_GetNext(&DC, &Item)) { + return -8; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -9; + } - return 0; -} + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { + return -10; + } + // ----- not a string --- + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), + QCBOR_DECODE_MODE_NORMAL); -int32_t ExponentAndMantissaDecodeTests(void) -{ - int32_t rv = ProcessEaMTests(); - if(rv) { - return rv; + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -11; } - return ExponentAndMantissaDecodeTestsSecondary(); -} + if(QCBORDecode_GetNext(&DC, &Item)) { + return -12; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -13; + } + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { + return -14; + } -static const struct FailInput ExponentAndMantissaFailures[] = { - // Exponent > INT64_MAX - { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF,}, 20}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // Mantissa > INT64_MAX - { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // End of input - { {(uint8_t[]){0xC4, 0x82}, 2}, QCBOR_ERR_NO_MORE_ITEMS}, - // End of input - { {(uint8_t[]){0xC4, 0x82, 0x01}, 3}, QCBOR_ERR_NO_MORE_ITEMS}, - // bad content for big num - { {(uint8_t[]){0xC4, 0x82, 0x01, 0xc3, 0x01}, 5}, QCBOR_ERR_BAD_OPT_TAG}, - // bad content for big num - { {(uint8_t[]){0xC4, 0x82, 0xc2, 0x01, 0x1f}, 5}, QCBOR_ERR_BAD_INT}, - // Bad integer for exponent - { {(uint8_t[]){0xC4, 0x82, 0x01, 0x1f}, 4}, QCBOR_ERR_BAD_INT}, - // Bad integer for mantissa - { {(uint8_t[]){0xC4, 0x82, 0x1f, 0x01}, 4}, QCBOR_ERR_BAD_INT}, - // 3 items in array - { {(uint8_t[]){0xC4, 0x83, 0x03, 0x01, 02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // unterminated indefinite length array - { {(uint8_t[]){0xC4, 0x9f, 0x03, 0x01, 0x02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // unterminated indefinite length array - { {(uint8_t[]){0xC4, 0x9f, 0x03, 0x01, 0x02}, 5}, QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED}, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // Empty array - { {(uint8_t[]){0xC4, 0x80}, 2}, QCBOR_ERR_NO_MORE_ITEMS}, - // Second is not an integer - { {(uint8_t[]){0xC4, 0x82, 0x03, 0x40}, 4}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // First is not an integer - { {(uint8_t[]){0xC4, 0x82, 0x40}, 3}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // Not an array - { {(uint8_t[]){0xC4, 0xa2}, 2}, QCBOR_ERR_BAD_EXP_AND_MANTISSA} -}; + // ----- no end ----- + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), + QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -15; + } -int32_t ExponentAndMantissaDecodeFailTests(void) -{ - return ProcessFailures(ExponentAndMantissaFailures, - C_ARRAY_COUNT(ExponentAndMantissaFailures, - struct FailInput)); -} + if(QCBORDecode_GetNext(&DC, &Item)) { + return -16; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -17; + } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { + return -18; + } + // ------ Don't set a string allocator and see an error ----- + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -19; + } -/* - Some basic CBOR with map and array used in a lot of tests. - The map labels are all strings + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { + return -20; + } - { - "first integer": 42, - "an array of two strings": [ - "string1", "string2" - ], - "map in a map": { - "bytes 1": h'78787878', - "bytes 2": h'79797979', - "another int": 98, - "text 2": "lies, damn lies and statistics" + // ----- Mempool is way too small ----- + UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, QCBOR_DECODE_MIN_MEM_POOL_SIZE-1); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { + return -21; } - } - */ -int32_t SpiffyDecodeBasicMap(UsefulBufC input) -{ - QCBORItem Item1, Item2, Item3; - int64_t nDecodedInt1, nDecodedInt2; - UsefulBufC B1, B2, S1, S2, S3; + // ----- Mempool is way too small ----- + UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); + const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); - QCBORDecodeContext DCtx; - QCBORError nCBORError; + // 80 is big enough for MemPool overhead, but not BigIndefBStr + UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); - QCBORDecode_Init(&DCtx, input, 0); + QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { + return -22; + } - QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -23; + } + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { + return -24; + } - QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt1); + // ---- big bstr ----- + QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 1", &B1); - QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 2", &B2); - QCBORDecode_GetTextStringInMapSZ(&DCtx, "text 2", &S1); - QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -25; + } - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item2); - if(QCBORDecode_GetNext(&DCtx, &Item3) != QCBOR_ERR_NO_MORE_ITEMS) { - return -400; - } - QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_GetNext(&DC, &Item)) { + return -26; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { + return -26; + } - // Parse the same array again using GetText() instead of GetItem() - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_GetTextString(&DCtx, &S2); - QCBORDecode_GetTextString(&DCtx, &S3); - if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { - return 5000; - } - /* QCBORDecode_GetText(&DCtx, &S3); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { - return 5001; - } */ + if(QCBORDecode_GetNext(&DC, &Item)) { + return -27; + } + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { + return -28; + } + if(CheckBigString(Item.val.string)) { + return -3; + } + if(QCBORDecode_Finish(&DC)) { + return -29; + } - QCBORDecode_ExitArray(&DCtx); +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + // --- label is an indefinite length string ------ + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -30; + } - nCBORError = QCBORDecode_Finish(&DCtx); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -31; + } - if(nCBORError) { - return (int32_t)nCBORError; - } + if(QCBORDecode_GetNext(&DC, &Item)){ + return -32; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.uDataAlloc || !Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { + return -33; + } - if(nDecodedInt1 != 42) { - return 1001; - } + if(QCBORDecode_Finish(&DC)) { + return -34; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - if(nDecodedInt2 != 98) { - return 1002; - } + return 0; +} - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item1.val.string, "string1")) { - return 1003; - } - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item2.val.string, "string2")) { - return 1004; - } +int32_t AllocAllStringsTest(void) +{ + QCBORDecodeContext DC; + QCBORError nCBORError; - if(UsefulBufCompareToSZ(S1, "lies, damn lies and statistics")) { - return 1005; - } - if(UsefulBuf_Compare(B1, UsefulBuf_FromSZ("xxxx"))){ - return 1006; - } + // First test, use the "CSRMap" as easy input and checking + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBOR_DECODE_MODE_NORMAL); - if(UsefulBuf_Compare(B2, UsefulBuf_FromSZ("yyyy"))){ - return 1007; - } + UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - if(UsefulBuf_Compare(S2, UsefulBuf_FromSZ("string1"))){ - return 1008; - } + nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. + if(nCBORError) { + return -1; + } - if(UsefulBuf_Compare(S3, UsefulBuf_FromSZ("string2"))){ - return 1009; - } + if(CheckCSRMaps(&DC)) { + return -2; + } - return 0; -} +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + // Next parse, save pointers to a few strings, destroy original and + // see all is OK. + UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); + const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); -/* - { - -75008: h'05083399', - 88: [], - 100100: { - "sub1": { - 10: [ - 0 - ], - -75009: h'A46823990001', - 100100: { - "json": "{ \"ueid\", \"xyz\"}", - "subsub": { - 100002: h'141813191001' - } - } - } - } - } - */ - -static const uint8_t spNestedCBOR[] = { - 0xa3, 0x3a, 0x00, 0x01, 0x24, 0xff, 0x44, 0x05, - 0x08, 0x33, 0x99, 0x18, 0x58, 0x80, 0x1a, 0x00, - 0x01, 0x87, 0x04, 0xa1, 0x64, 0x73, 0x75, 0x62, - 0x31, 0xa3, 0x0a, 0x81, 0x00, 0x3a, 0x00, 0x01, - 0x25, 0x00, 0x46, 0xa4, 0x68, 0x23, 0x99, 0x00, - 0x01, 0x1a, 0x00, 0x01, 0x87, 0x04, 0xa2, 0x64, - 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x7b, 0x20, 0x22, - 0x75, 0x65, 0x69, 0x64, 0x22, 0x2c, 0x20, 0x22, - 0x78, 0x79, 0x7a, 0x22, 0x7d, 0x66, 0x73, 0x75, - 0x62, 0x73, 0x75, 0x62, 0xa1, 0x1a, 0x00, 0x01, - 0x86, 0xa2, 0x46, 0x14, 0x18, 0x13, 0x19, 0x10, - 0x01 -}; + QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); + UsefulBuf_Set(Pool, '/'); + QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. -/* Get item in multi-level nesting in spNestedCBOR */ -static int32_t DecodeNestedGetSubSub(QCBORDecodeContext *pDCtx) -{ - UsefulBufC String; + QCBORItem Item1, Item2, Item3, Item4; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return (int32_t)nCBORError; + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3) + return -3; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return (int32_t)nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) + return (int32_t)nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) + return (int32_t)nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) + return (int32_t)nCBORError; - uint8_t test_oemid_bytes[] = {0x14, 0x18, 0x13, 0x19, 0x10, 0x01}; - const struct q_useful_buf_c test_oemid = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(test_oemid_bytes); + UsefulBuf_Set(CopyOfStorage, '_'); - QCBORDecode_EnterMapFromMapN(pDCtx, 100100); - QCBORDecode_EnterMap(pDCtx, NULL); - QCBORDecode_EnterMapFromMapN(pDCtx, 100100); - QCBORDecode_EnterMapFromMapSZ(pDCtx, "subsub"); - QCBORDecode_GetByteStringInMapN(pDCtx, 100002, &String); - if(QCBORDecode_GetError(pDCtx)) { - return 4001; - } - if(UsefulBuf_Compare(String, test_oemid)) { - return 4002; + if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item1.uDataType != QCBOR_TYPE_INT64 || + Item1.val.int64 != 42 || + Item1.uDataAlloc != 0 || + Item1.uLabelAlloc == 0 || + UsefulBufCompareToSZ(Item1.label.string, "first integer") || + Item1.label.string.ptr < Pool.ptr || + Item1.label.string.ptr > (const void *)((const uint8_t *)Pool.ptr + Pool.len)) { + return -4; } - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); - return 0; -} -/* Iterations on the zero-length array in spNestedCBOR */ -static int32_t DecodeNestedGetEmpty(QCBORDecodeContext *pDCtx) -{ - QCBORItem Item; - QCBORError uErr; + if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item2.label.string, "an array of two strings") || + Item2.uDataType != QCBOR_TYPE_ARRAY || + Item2.uDataAlloc != 0 || + Item2.uLabelAlloc == 0 || + Item2.val.uCount != 2) + return -5; - QCBORDecode_EnterArrayFromMapN(pDCtx, 88); - for(int x = 0; x < 20; x++) { - uErr = QCBORDecode_GetNext(pDCtx, &Item); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 4100; + if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || + Item3.uDataAlloc == 0 || + Item3.uLabelAlloc != 0 || + UsefulBufCompareToSZ(Item3.val.string, "string1")) { + return -6; + } + + if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || + Item4.uDataAlloc == 0 || + Item4.uLabelAlloc != 0 || + UsefulBufCompareToSZ(Item4.val.string, "string2")) { + return -7; + } + // Next parse with a pool that is too small + UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return -8; + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3) { + return -9; + } + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { + nCBORError = QCBORDecode_GetNext(&DC, &Item4); + } } } - QCBORDecode_ExitArray(pDCtx); - if(QCBORDecode_GetError(pDCtx)) { - return 4101; + if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { + return -10; } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ return 0; } -/* Various iterations on the array that contains a zero in spNestedCBOR */ -static int32_t DecodeNestedGetZero(QCBORDecodeContext *pDCtx) + +int32_t MemPoolTest(void) { - QCBORError uErr; + // Set up the decoder with a tiny bit of CBOR to parse because + // nothing can be done with it unless that is set up. + QCBORDecodeContext DC; + const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); - QCBORDecode_EnterMapFromMapN(pDCtx, 100100); - QCBORDecode_EnterMapFromMapSZ(pDCtx, "sub1"); - QCBORDecode_EnterArrayFromMapN(pDCtx, 10); - int64_t nInt = 99; - QCBORDecode_GetInt64(pDCtx, &nInt); - if(nInt != 0) { - return 4200; + // Set up an memory pool of 100 bytes + // Then fish into the internals of the decode context + // to get the allocator function so it can be called directly. + // Also figure out how much pool is available for use + // buy subtracting out the overhead. + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); + if(nError) { + return -9; } - for(int x = 0; x < 20; x++) { - QCBORItem Item; - uErr = QCBORDecode_GetNext(pDCtx, &Item); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 4201; + QCBORStringAllocate pAlloc = DC.StringAllocator.pfAllocator; + void *pAllocCtx = DC.StringAllocator.pAllocateCxt; + size_t uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; - } + // First test -- ask for one more byte than available and see failure + UsefulBuf Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool+1); + if(!UsefulBuf_IsNULL(Allocated)) { + return -1; } - QCBORDecode_ExitArray(pDCtx); - if(QCBORDecode_GetAndResetError(pDCtx)) { - return 4202; + + // Re do the set up for the next test that will do a successful alloc, + // a fail, a free and then success + QCBORDecode_SetMemPool(&DC, Pool, 0); + pAlloc = DC.StringAllocator.pfAllocator; + pAllocCtx = DC.StringAllocator.pAllocateCxt; + uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; + + // Allocate one byte less than available and see success + Allocated = (pAlloc)(pAllocCtx, NULL, uAvailPool-1); + if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed + return -2; } - QCBORDecode_EnterArrayFromMapN(pDCtx, 10); - UsefulBufC dD; - QCBORDecode_GetByteString(pDCtx, &dD); - if(QCBORDecode_GetAndResetError(pDCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 4203; + // Ask for some more and see failure + UsefulBuf Allocated2 = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); + if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail + return -3; } - for(int x = 0; x < 20; x++) { - QCBORDecode_GetByteString(pDCtx, &dD); - uErr = QCBORDecode_GetAndResetError(pDCtx); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 4204; - } + // Free the first allocate, retry the second and see success + (*pAlloc)(pAllocCtx, Allocated.ptr, 0); // Free + Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); + if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free + return -4; + } + + // Re do set up for next test that involves a successful alloc, + // and a successful realloc and a failed realloc + QCBORDecode_SetMemPool(&DC, Pool, 0); + pAlloc = DC.StringAllocator.pfAllocator; + pAllocCtx = DC.StringAllocator.pAllocateCxt; + + // Allocate half the pool and see success + Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); + if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed + return -5; + } + // Reallocate to take up the whole pool and see success + Allocated2 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool); + if(UsefulBuf_IsNULL(Allocated2)) { + return -6; + } + // Make sure its the same pointer and the size is right + if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { + return -7; + } + // Try to allocate more to be sure there is failure after a realloc + UsefulBuf Allocated3 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool+1); + if(!UsefulBuf_IsNULL(Allocated3)) { + return -8; } - QCBORDecode_ExitArray(pDCtx); - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); return 0; } -/* Repeatedly enter and exit maps and arrays, go off the end of maps - and arrays and such. */ -static int32_t DecodeNestedIterate(void) + +/* Just enough of an allocator to test configuration of one */ +static UsefulBuf AllocateTestFunction(void *pCtx, void *pOldMem, size_t uNewSize) { - QCBORDecodeContext DCtx; - int32_t nReturn; - QCBORError uErr; + (void)pOldMem; // unused variable - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNestedCBOR), 0); - QCBORDecode_EnterMap(&DCtx, NULL); + if(uNewSize) { + // Assumes the context pointer is the buffer and + // nothing too big will ever be asked for. + // This is only good for this basic test! + return (UsefulBuf) {pCtx, uNewSize}; + } else { + return NULLUsefulBuf; + } +} - for(int j = 0; j < 5; j++) { - for(int i = 0; i < 20; i++) { - nReturn = DecodeNestedGetSubSub(&DCtx); - if(nReturn) { - return nReturn; - } - } - for(int i = 0; i < 20; i++) { - nReturn = DecodeNestedGetEmpty(&DCtx); - if(nReturn ) { - return nReturn; - } - } +int32_t SetUpAllocatorTest(void) +{ + // Set up the decoder with a tiny bit of CBOR to parse because + // nothing can be done with it unless that is set up. + QCBORDecodeContext DC; + const uint8_t pMinimalCBOR[] = {0x62, 0x48, 0x69}; // "Hi" + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); - for(int i = 0; i < 20; i++) { - nReturn = DecodeNestedGetZero(&DCtx); - if(nReturn ) { - return nReturn; - } - } + uint8_t pAllocatorBuffer[50]; + + // This is really just to test that this call works. + // The full functionality of string allocators is tested + // elsewhere with the MemPool internal allocator. + QCBORDecode_SetUpAllocator(&DC, AllocateTestFunction, pAllocatorBuffer, 1); + + QCBORItem Item; + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_SUCCESS) { + return -1; } - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr) { - return (int32_t)uErr + 4100; + if(Item.uDataAlloc == 0 || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.ptr != pAllocatorBuffer) { + return -2; + } + + if(QCBORDecode_Finish(&DC) != QCBOR_SUCCESS) { + return -3; } return 0; } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ -/* - [ - 23, - 6000, - h'67616C6163746963', - h'686176656E20746F6B656E' - ] - */ -static const uint8_t spSimpleArray[] = { - 0x84, - 0x17, - 0x19, 0x17, 0x70, - 0x48, 0x67, 0x61, 0x6C, 0x61, 0x63, 0x74, 0x69, 0x63, - 0x4B, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E}; +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/* [h'', {}, [], 0] */ -static const uint8_t spArrayOfEmpty[] = {0x84, 0x40, 0xa0, 0x80, 0x00}; +struct EaMTest { + const char *szName; + UsefulBufC Input; + uint8_t uTagRequirement; + bool bHasTags; -/* {} */ -static const uint8_t spEmptyMap[] = {0xa0}; + /* Expected values for GetNext */ + QCBORError uExpectedErrorGN; + uint8_t uQCBORTypeGN; + int64_t nExponentGN; + int64_t nMantissaGN; + UsefulBufC MantissaGN; -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/* {} */ -static const uint8_t spEmptyInDefinteLengthMap[] = {0xbf, 0xff}; + /* Expected values for GetDecimalFraction */ + QCBORError uExpectedErrorGDF; + int64_t nExponentGDF; + int64_t nMantissaGDF; + /* Expected values for GetDecimalFractionBig */ + QCBORError uExpectedErrorGDFB; + int64_t nExponentGDFB; + UsefulBufC MantissaGDFB; + bool IsNegativeGDFB; -/* - { - 0: [], - 9: [ - [], - [] - ], - 8: { - 1: [], - 2: {}, - 3: [] - }, - 4: {}, - 5: [], - 6: [ - [], - [] - ] - } - */ -static const uint8_t spMapOfEmpty[] = { - 0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, - 0xa3, 0x01, 0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, - 0xa0, 0x05, 0x9f, 0xff, 0x06, 0x9f, 0x80, 0x9f, - 0xff, 0xff}; + /* Expected values for GetBigFloat */ + QCBORError uExpectedErrorGBF; + int64_t nExponentGBF; + int64_t nMantissaGBF; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + /* Expected values for GetBigFloatBig */ + QCBORError uExpectedErrorGBFB; + int64_t nExponentGBFB; + UsefulBufC MantissaGBFB; + bool IsNegativeGBFB; +}; -/* - Too many tags - Duplicate label - Integer overflow - Date overflow +static const struct EaMTest pEaMTests[] = { { - 1: 224(225(226(227(4(0))))), - 3: -18446744073709551616, - 4: 1(1.0e+300), - 5: 0, - 8: 8 - } - */ -static const uint8_t spRecoverableMapErrors[] = { -#ifndef QCBOR_DISABLE_TAGS - 0xa6, - 0x04, 0xc1, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c, - 0x01, 0xd8, 0xe0, 0xd8, 0xe1, 0xd8, 0xe2, 0xd8, 0xe3, 0xd8, 0x04, 0x00, -#else - 0xa4, -#endif - 0x03, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x05, 0x00, - 0x05, 0x00, - 0x08, 0x08, -}; - -/* Bad break */ -static const uint8_t spUnRecoverableMapError1[] = { - 0xa2, 0xff, 0x01, 0x00, 0x02, 0x00 -}; + "1. Untagged pair (big float or decimal fraction), no tag required", + {(const uint8_t []){0x82, 0x20, 0x03}, 3}, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + false, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/* No more items */ -static const uint8_t spUnRecoverableMapError2[] = { - 0xbf, 0x02, 0xbf, 0xff, 0x01, 0x00, 0x02, 0x00 -}; + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_ARRAY, + 0, + 0, + {(const uint8_t []){0x00}, 1}, -/* Hit end because string is too long */ -static const uint8_t spUnRecoverableMapError3[] = { - 0xbf, 0x02, 0x69, 0x64, 0x64, 0xff -}; + QCBOR_SUCCESS, /* GetDecimalFraction */ + -1, + 3, -/* Hit end because string is too long */ -static const uint8_t spUnRecoverableMapError4[] = { - 0xbf, - 0x02, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff -}; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -1, + {(const uint8_t []){0x02}, 1}, + false, -const unsigned char not_well_formed_submod_section[] = { - 0xa1, 0x14, 0x1f, -}; + QCBOR_SUCCESS, /* for GetBigFloat */ + -1, + 3, + QCBOR_SUCCESS, /* for GetBigFloatBig */ + -1, + {(const uint8_t []){0x02}, 1}, + false + }, -/* Array of length 3, but only two items. */ -const unsigned char spBadConsumeInput[] = { - 0x83, 0x00, 0x00 -}; + { + "2. Untagged pair (big float or decimal fraction), tag required", + {(const uint8_t []){0x82, 0x20, 0x03}, 3}, + QCBOR_TAG_REQUIREMENT_TAG, + false, -/* Tag nesting too deep. */ -const unsigned char spBadConsumeInput2[] = { - 0x81, - 0xD8, 0x37, - 0xD8, 0x2C, - 0xD8, 0x21, - 0xD6, - 0xCB, - 00 -}; + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_ARRAY, + 0, + 0, + {(const uint8_t []){0x00}, 1}, -const unsigned char spBadConsumeInput3[] = { - 0x81, 0xc0, 0x81, 0x00 -}; + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ + 0, + 0, -const unsigned char spBadConsumeInput4[] = { - 0x81, 0x9f, 0x00, 0xff -}; + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false, -const unsigned char spBadConsumeInput5[] = { - 0xa1, 0x80, 0x00 -}; + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false + }, -int32_t EnterMapTest(void) -{ - QCBORItem Item1; - QCBORItem ArrayItem; - QCBORDecodeContext DCtx; - int32_t nReturn; - QCBORError uErr; + { + "3. Tagged 1.5 decimal fraction, tag 4 optional", + {(const uint8_t []){0xC4, 0x82, 0x20, 0x03}, 4}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapOfEmpty), 0); - QCBORDecode_EnterMap(&DCtx, NULL); + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION, + -1, + 3, + {(const uint8_t []){0x00}, 1}, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 0 - QCBORDecode_ExitArray(&DCtx); + QCBOR_SUCCESS, /* for GetDecimalFraction */ + -1, + 3, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 9 - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitArray(&DCtx); + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -1, + {(const uint8_t []){0x02}, 1}, + false, - QCBORDecode_EnterMap(&DCtx, NULL); // Label 8 - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitMap(&DCtx); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, - QCBORDecode_EnterMap(&DCtx, NULL); // Label4 - QCBORDecode_ExitMap(&DCtx); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false + }, + { + "4. Tagged 100 * 2^300 big float, tag 5 optional", + {(const uint8_t []){0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 7}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 5 - QCBORDecode_ExitArray(&DCtx); + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_BIGFLOAT, + 300, + 100, + {(const uint8_t []){0x00}, 1}, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 6 - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitMap(&DCtx); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ + 0, + 0, - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS){ - return 3011; - } + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ + 0, + {(const uint8_t []){0x02}, 1}, + false, - (void)pValidMapIndefEncoded; - nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded)); - if(nReturn) { - return nReturn + 20000; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + QCBOR_SUCCESS, /* for GetBigFloat */ + 300, + 100, + QCBOR_SUCCESS, /* for GetBigFloatBig */ + 300, + {(const uint8_t []){0x63}, 1}, + false + }, - nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); - if(nReturn) { - return nReturn; - } + { + "5. Tagged 4([-20, 4759477275222530853136]) decimal fraction, tag 4 required", + {(const uint8_t []){0xC4, 0x82, 0x33, + 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 15}, + QCBOR_TAG_REQUIREMENT_TAG, + true, + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, + -20, + 0, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetDecimalFraction */ + 0, + 0, - // These tests confirm the cursor is at the right place after entering - // a map or array - const UsefulBufC ValidEncodedMap = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded); + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -20, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + false, - // Confirm cursor is at right place - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_INT64) { - return 2001; - } + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 0}, + false + }, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_VGetNext(&DCtx, &Item1); - QCBORDecode_VGetNext(&DCtx, &Item1); - QCBORDecode_EnterArray(&DCtx, &ArrayItem); - if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(ArrayItem.label.string, - UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { - return 2051; - } - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { - return 2002; - } - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterMap(&DCtx, &ArrayItem); - if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(ArrayItem.label.string, - UsefulBuf_FROM_SZ_LITERAL("map in a map"))) { - return 2052; - } + { + "6. Error: Mantissa and exponent inside a Mantissa and exponent", + {(const uint8_t []){0xC4, 0x82, 0x33, + 0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 10}, + QCBOR_TAG_REQUIREMENT_TAG, + true, + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, + 0, + 0, + {(const uint8_t []){0x00}, 0}, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_BYTE_STRING) { - return 2003; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFraction */ + 0, + 0, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { - return 2004; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFractionBig */ + 0, + {(const uint8_t []){0x00}, 0}, + false, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP && Item1.uLabelAlloc != QCBOR_TYPE_TEXT_STRING) { - return 2006; - } - QCBORDecode_ExitMap(&DCtx); - if(QCBORDecode_GetNext(&DCtx, &Item1) != QCBOR_ERR_NO_MORE_ITEMS) { - return 2007; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloat */ + 0, + 0, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleArray), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - int64_t nDecodedInt2; - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ - return 2008; - } - UsefulBufC String; - QCBORDecode_GetTextStringInMapN(&DCtx, 88, &String); - if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ - return 2009; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 0}, + false + }, + { + "7. Tagged 5([-20, 4294967295]) big float, big num mantissa, tag 5 required", + {(const uint8_t []){0xC5, 0x82, 0x33, + 0xC2, 0x44, 0xff, 0xff, 0xff, 0xff}, 9}, + QCBOR_TAG_REQUIREMENT_TAG, + true, + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, + -20, + 0, + {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyMap), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - // This will fail because the map is empty. - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ - return 2010; - } - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS){ - return 2011; - } + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ + -20, + {(const uint8_t []){0x00}, 1}, + false, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyInDefinteLengthMap), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - // This will fail because the map is empty. - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ - return 2012; - } - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS){ - return 2013; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spArrayOfEmpty), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_GetByteString(&DCtx, &String); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_GetInt64(&DCtx, &nDecodedInt2); - QCBORDecode_ExitArray(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS) { - return 2014; - } - - int64_t nInt; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spRecoverableMapErrors), 0); - QCBORDecode_EnterMap(&DCtx, NULL); -#ifndef QCBOR_DISABLE_TAGS - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetError(&DCtx); - if(uErr != QCBOR_ERR_TOO_MANY_TAGS) { - return 2021; - } - if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != CBOR_TAG_INVALID64) { - return 2121; - } - (void)QCBORDecode_GetAndResetError(&DCtx); -#endif - + QCBOR_SUCCESS, /* for GetBigFloat */ + -20, + 4294967295, - QCBORDecode_GetInt64InMapN(&DCtx, 0x03, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_INT_OVERFLOW) { - return 2023; - } + QCBOR_SUCCESS, /* for GetBigFloatBig */ + -20, + {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, + false + }, -#ifndef QCBOR_DISABLE_TAGS - QCBORDecode_GetEpochDateInMapN(&DCtx, 0x04, QCBOR_TAG_REQUIREMENT_TAG, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return 2024; - } -#endif + { + /* Special case for test 8. Don't renumber it. */ + "8. Untagged pair with big num (big float or decimal fraction), tag optional", + {(const uint8_t []){0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 14}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, - QCBORDecode_GetInt64InMapN(&DCtx, 0x05, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_DUPLICATE_LABEL) { - return 2025; - } + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_ARRAY, + 0, + 0, + {(const uint8_t []){0x00}, 1}, - QCBORDecode_GetInt64InMapN(&DCtx, 0x08, &nInt); + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ + 0, + 0, - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS) { - return 2026; - } + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -20, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + false, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError1), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_BAD_BREAK) { - return 2030; - } + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */ + 0, + 0, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError2), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 2031; - } + QCBOR_SUCCESS, /* for GetBigFloatBig */ + -20, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + false + }, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError3), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_HIT_END) { - return 2032; - } + { + "9. decimal fraction with large exponent and negative big num mantissa", + {(const uint8_t []){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError4), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { - return 2033; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, + 9223372036854775807, + 0, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP) { - return 2401; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2402; - } + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ + 0, + 0, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_VGetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3 || - Item1.uNextNestLevel != 1) { - return 2403; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2404; - } - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_INT64 || - Item1.uNextNestLevel != 1 || - Item1.val.int64 != 42) { - return 2405; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2406; - } - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_ARRAY || - Item1.uNestingLevel != 1 || - Item1.uNextNestLevel != 1 || - Item1.val.uCount != 2) { - return 2407; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2408; - } - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.uNestingLevel != 1 || - Item1.uNextNestLevel != 0 || - Item1.val.uCount != 4) { - return 2409; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2410; - } + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + 9223372036854775807, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + true, - nReturn = DecodeNestedIterate(); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false + }, +}; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(not_well_formed_submod_section), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_EnterMapFromMapN(&DCtx, 20); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_BAD_INT) { - return 2500; - } - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { - return 2600; - } -#ifndef QCBOR_DISABLE_TAGS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput2), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { - return 2700; - } +int32_t ProcessEaMTests(void) +{ + size_t uIndex; + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uError; + int64_t nMantissa, nExponent; + MakeUsefulBufOnStack( MantissaBuf, 200); + UsefulBufC Mantissa; + bool bMantissaIsNegative; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput3), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 2800; - } -#endif + for(uIndex = 0; uIndex < C_ARRAY_COUNT(pEaMTests, struct EaMTest); uIndex++) { + const struct EaMTest *pT = &pEaMTests[uIndex]; + /* Decode with GetNext */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + if(uIndex + 1 == 9) { + nExponent = 99; // just to set a break point + } - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput4), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { - return 2900; - } -#else - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { - return 2901; - } + uError = QCBORDecode_GetNext(&DCtx, &Item); +#ifdef QCBOR_DISABLE_TAGS + /* Test 8 is a special case when tags are disabled */ + if(pT->bHasTags && uIndex + 1 != 8) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 9; + } + } else { +#endif + /* Now check return code, data type, mantissa and exponent */ + if(pT->uExpectedErrorGN != uError) { + return (int32_t)(1+uIndex) * 1000 + 1; + } + if(uError == QCBOR_SUCCESS && pT->uQCBORTypeGN != QCBOR_TYPE_ARRAY) { + if(pT->uQCBORTypeGN != Item.uDataType) { + return (int32_t)(1+uIndex) * 1000 + 2; + } + if(pT->nExponentGN != Item.val.expAndMantissa.nExponent) { + return (int32_t)(1+uIndex) * 1000 + 3; + } + if(Item.uDataType == QCBOR_TYPE_DECIMAL_FRACTION || Item.uDataType == QCBOR_TYPE_BIGFLOAT ) { + if(pT->nMantissaGN != Item.val.expAndMantissa.Mantissa.nInt) { + return (int32_t)(1+uIndex) * 1000 + 4; + } + } else { + if(UsefulBuf_Compare(Item.val.expAndMantissa.Mantissa.bigNum, pT->MantissaGN)) { + return (int32_t)(1+uIndex) * 1000 + 5; + } + } + } +#ifdef QCBOR_DISABLE_TAGS + } #endif - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput5), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_MAP_LABEL_TYPE) { - return 3000; - } - - return nReturn; -} + /* Decode with GetDecimalFraction */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetDecimalFraction(&DCtx, + pT->uTagRequirement, + &nMantissa, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 39; + } + } else { +#endif + /* Now check return code, mantissa and exponent */ + if(pT->uExpectedErrorGDF != uError) { + return (int32_t)(1+uIndex) * 1000 + 31; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGDF != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 32; + } + if(pT->nMantissaGDF != nMantissa) { + return (int32_t)(1+uIndex) * 1000 + 33; + } + } +#ifdef QCBOR_DISABLE_TAGS + } +#endif + /* Decode with GetDecimalFractionBig */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetDecimalFractionBig(&DCtx, + pT->uTagRequirement, + MantissaBuf, + &Mantissa, + &bMantissaIsNegative, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 49; + } + } else { +#endif + /* Now check return code, mantissa (bytes and sign) and exponent */ + if(pT->uExpectedErrorGDFB != uError) { + return (int32_t)(1+uIndex) * 1000 + 41; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGDFB != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 42; + } + if(pT->IsNegativeGDFB != bMantissaIsNegative) { + return (int32_t)(1+uIndex) * 1000 + 43; + } + if(UsefulBuf_Compare(Mantissa, pT->MantissaGDFB)) { + return (int32_t)(1+uIndex) * 1000 + 44; + } + } +#ifdef QCBOR_DISABLE_TAGS + } +#endif -struct NumberConversion { - char *szDescription; - UsefulBufC CBOR; - int64_t nConvertedToInt64; - QCBORError uErrorInt64; - uint64_t uConvertToUInt64; - QCBORError uErrorUint64; - double dConvertToDouble; - QCBORError uErrorDouble; -}; + /* Decode with GetBigFloat */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetBigFloat(&DCtx, + pT->uTagRequirement, + &nMantissa, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 19; + } + } else { +#endif + /* Now check return code, mantissa and exponent */ + if(pT->uExpectedErrorGBF != uError) { + return (int32_t)(1+uIndex) * 1000 + 11; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGBF != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 12; + } + if(pT->nMantissaGBF != nMantissa) { + return (int32_t)(1+uIndex) * 1000 + 13; + } + } +#ifdef QCBOR_DISABLE_TAGS + } +#endif -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -#define EXP_AND_MANTISSA_ERROR(x) x -#else -#define EXP_AND_MANTISSA_ERROR(x) QCBOR_ERR_UNEXPECTED_TYPE + /* Decode with GetBigFloatBig */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetBigFloatBig(&DCtx, + pT->uTagRequirement, + MantissaBuf, + &Mantissa, + &bMantissaIsNegative, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 29; + } + } else { +#endif + /* Now check return code, mantissa (bytes and sign) and exponent */ + if(pT->uExpectedErrorGBFB != uError) { + return (int32_t)(1+uIndex) * 1000 + 21; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGBFB != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 22; + } + if(pT->IsNegativeGBFB != bMantissaIsNegative) { + return (int32_t)(1+uIndex) * 1000 + 23; + } + if(UsefulBuf_Compare(Mantissa, pT->MantissaGBFB)) { + return (int32_t)(1+uIndex) * 1000 + 24; + } + } +#ifdef QCBOR_DISABLE_TAGS + } #endif + } + + return 0; +} -static const struct NumberConversion NumberConversions[] = { +int32_t ExponentAndMantissaDecodeTestsSecondary(void) +{ #ifndef QCBOR_DISABLE_TAGS - { - "Big float: INT64_MIN * 2e-1 to test handling of INT64_MIN", - {(uint8_t[]){0xC5, 0x82, 0x20, - 0x3B, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x0ff, 0xff, 0xff, - }, 15}, - -4611686018427387904, /* INT64_MIN / 2 */ - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -4.6116860184273879E+18, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "too large to fit into int64_t", - {(uint8_t[]){0xc3, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 10}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - ((double)INT64_MIN) + 1 , - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "largest negative int that fits in int64_t", - {(uint8_t[]){0xc3, 0x48, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 10}, - INT64_MIN, - QCBOR_SUCCESS, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - (double)INT64_MIN, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "negative bignum -1", - {(uint8_t[]){0xc3, 0x41, 0x00}, 3}, - -1, - QCBOR_SUCCESS, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -1.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "Decimal Fraction with positive bignum 257 * 10e3", - {(uint8_t[]){0xC4, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC2, 0x42, 0x01, 0x01}, 15}, - 257000, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 257000, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 257000.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "bigfloat with negative bignum -258 * 2e3", - {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC3, 0x42, 0x01, 0x01}, 15}, - -2064, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -2064.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "bigfloat with positive bignum 257 * 2e3", - {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC2, 0x42, 0x01, 0x01}, 15}, - 2056, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 2056, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 2056.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "negative bignum 0xc349010000000000000000 -18446744073709551617", - {(uint8_t[]){0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 11}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -18446744073709551617.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + QCBORDecodeContext DC; + QCBORError uErr; + QCBORItem item; + + static const uint8_t spBigNumMantissa[] = {0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x010}; + UsefulBufC BN = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumMantissa); + + + + /* Now encode some stuff and then decode it */ + uint8_t pBuf[40]; + QCBOREncodeContext EC; + UsefulBufC Encoded; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf)); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddDecimalFraction(&EC, 999, 1000); // 999 * (10 ^ 1000) + QCBOREncode_AddTBigFloat(&EC, QCBOR_ENCODE_AS_TAG, 100, INT32_MIN); + QCBOREncode_AddTDecimalFractionBigNum(&EC, QCBOR_ENCODE_AS_TAG, BN, false, INT32_MAX); + QCBOREncode_CloseArray(&EC); + QCBOREncode_Finish(&EC, &Encoded); + + + QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 100; + } + + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 101; + } + + if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || + item.val.expAndMantissa.nExponent != 1000 || + item.val.expAndMantissa.Mantissa.nInt != 999) { + return 102; + } + + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 103; + } + + if(item.uDataType != QCBOR_TYPE_BIGFLOAT || + item.val.expAndMantissa.nExponent != INT32_MIN || + item.val.expAndMantissa.Mantissa.nInt != 100) { + return 104; + } + + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 105; + } + + if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM || + item.val.expAndMantissa.nExponent != INT32_MAX || + UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { + return 106; + } + +#endif /* QCBOR_TAGS_DISABLED */ + + return 0; +} + + +int32_t ExponentAndMantissaDecodeTests(void) +{ + int32_t rv = ProcessEaMTests(); + if(rv) { + return rv; + } + + return ExponentAndMantissaDecodeTestsSecondary(); +} + + +static const struct DecodeFailTestInput ExponentAndMantissaFailures[] = { + { "Exponent > INT64_MAX", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x1B\x7f\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1B\x80\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 20}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - { - "Positive bignum 0x01020304 indefinite length string", - {(uint8_t[]){0xC2, 0x5f, 0x42, 0x01, 0x02, 0x41, 0x03, 0x41, 0x04, 0xff}, 10}, - 0x01020304, - QCBOR_SUCCESS, - 0x01020304, - QCBOR_SUCCESS, - 16909060.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + { "Mantissa > INT64_MAX", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x1B\x80\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC3\x4A\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10", 23}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ { - "Decimal Fraction with neg bignum [9223372036854775807, -4759477275222530853137]", - {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 23}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + "End of input", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82", 2}, + QCBOR_ERR_NO_MORE_ITEMS }, - { - "big float [9223372036854775806, 9223372036854775806]", - {(uint8_t[]){0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + {"bad content for big num", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x01\xc3\x01", 5}, + QCBOR_ERR_BAD_OPT_TAG }, - { - "Big float 3 * 2^^2", - {(uint8_t[]){0xC5, 0x82, 0x02, 0x03}, 4}, - 12, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 12, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 12.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + {"bad content for big num", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\xC2\x01\x1F", 5}, + QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT }, - { - "Decimal fraction 3/10", - {(uint8_t[]){0xC4, 0x82, 0x20, 0x03}, 4}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0.30000000000000004, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + {"Bad integer for exponent", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x01\x1f", 4}, + QCBOR_ERR_BAD_INT }, - { - "extreme pos bignum", - {(uint8_t[]){0xc2, 0x59, 0x01, 0x90, - // 50 rows of 8 is 400 digits. - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, - 404}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + {"Bad integer for mantissa", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x1f\x01", 4}, + QCBOR_ERR_BAD_INT }, - - { - "extreme neg bignum", - {(uint8_t[]){0xc3, 0x59, 0x01, 0x90, - // 50 rows of 8 is 400 digits. - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, - 404}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + {"3 items in array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x83\x03\x01\x02", 5}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA}, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + {"unterminated indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x9f\x03\x01\x02", 5}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, - - { - "big float underflow [9223372036854775806, -9223372036854775806]", - {(uint8_t[]){ - 0xC5, 0x82, - 0x3B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + {"unterminated indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x9f\x03\x01\x02", 5}, + QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED }, - - { - "bigfloat that evaluates to -INFINITY", - {(uint8_t[]){ - 0xC5, 0x82, - 0x1B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC3, 0x42, 0x01, 0x01}, 15}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + {"Empty array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x80", 2}, + QCBOR_ERR_NO_MORE_ITEMS }, - { - "Positive bignum 0xffff", - {(uint8_t[]){0xC2, 0x42, 0xff, 0xff}, 4}, - 65536-1, - QCBOR_SUCCESS, - 0xffff, - QCBOR_SUCCESS, - 65535.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + {"Second is not an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x03\x40", 4}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, -#endif /* QCBOR_DISABLE_TAGS */ - { - "Positive integer 18446744073709551615", - {(uint8_t[]){0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 18446744073709551615ULL, - QCBOR_SUCCESS, - 18446744073709551615.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + {"First is not an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x40", 3}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, + {"Not an array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\xA2", 2}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA + } +}; + +int32_t +ExponentAndMantissaDecodeFailTests(void) +{ + return ProcessDecodeFailures(ExponentAndMantissaFailures, + C_ARRAY_COUNT(ExponentAndMantissaFailures, + struct DecodeFailTestInput)); +} + +#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + + + +/* + Some basic CBOR with map and array used in a lot of tests. + The map labels are all strings + + { + "first integer": 42, + "an array of two strings": [ + "string1", "string2" + ], + "map in a map": { + "bytes 1": h'78787878', + "bytes 2": h'79797979', + "another int": 98, + "text 2": "lies, damn lies and statistics" + } + } + */ + +int32_t SpiffyDecodeBasicMap(UsefulBufC input) +{ + QCBORItem Item1, Item2, Item3; + int64_t nDecodedInt1, nDecodedInt2; + UsefulBufC B1, B2, S1, S2, S3; + + QCBORDecodeContext DCtx; + QCBORError nCBORError; + + QCBORDecode_Init(&DCtx, input, 0); + + QCBORDecode_EnterMap(&DCtx, NULL); + + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt1); + + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 1", &B1); + QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 2", &B2); + QCBORDecode_GetTextStringInMapSZ(&DCtx, "text 2", &S1); + QCBORDecode_ExitMap(&DCtx); + + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item2); + if(QCBORDecode_GetNext(&DCtx, &Item3) != QCBOR_ERR_NO_MORE_ITEMS) { + return -400; + } + QCBORDecode_ExitArray(&DCtx); + + // Parse the same array again using GetText() instead of GetItem() + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_GetTextString(&DCtx, &S2); + QCBORDecode_GetTextString(&DCtx, &S3); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5000; + } + /* QCBORDecode_GetText(&DCtx, &S3); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 5001; + } */ + + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_ExitMap(&DCtx); + + nCBORError = QCBORDecode_Finish(&DCtx); + + if(nCBORError) { + return (int32_t)nCBORError; + } + + if(nDecodedInt1 != 42) { + return 1001; + } + + if(nDecodedInt2 != 98) { + return 1002; + } + + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item1.val.string, "string1")) { + return 1003; + } + + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item2.val.string, "string2")) { + return 1004; + } + + if(UsefulBufCompareToSZ(S1, "lies, damn lies and statistics")) { + return 1005; + } + + if(UsefulBuf_Compare(B1, UsefulBuf_FromSZ("xxxx"))){ + return 1006; + } + + if(UsefulBuf_Compare(B2, UsefulBuf_FromSZ("yyyy"))){ + return 1007; + } + + if(UsefulBuf_Compare(S2, UsefulBuf_FromSZ("string1"))){ + return 1008; + } + + if(UsefulBuf_Compare(S3, UsefulBuf_FromSZ("string2"))){ + return 1009; + } + + return 0; +} + +/* { - "Postive integer 0", - {(uint8_t[]){0x0}, 1}, - 0LL, - QCBOR_SUCCESS, - 0ULL, - QCBOR_SUCCESS, - 0.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "Negative integer -18446744073709551616", - {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9}, - -9223372036854775807-1, // INT64_MIN - QCBOR_SUCCESS, - 0ULL, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -9223372036854775808.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "Double Floating point value 100.3", - {(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9}, - 100L, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), - 100ULL, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), - 100.3, - FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS), - }, - { - "Floating point value NaN 0xfa7fc00000", - {(uint8_t[]){0xfa, 0x7f, 0xc0, 0x00, 0x00}, 5}, - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), - NAN, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), - }, - { - "half-precision Floating point value -4", - {(uint8_t[]){0xf9, 0xc4, 0x00}, 3}, - // Normal case with all enabled. - -4, - FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS), - 0, - FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -4.0, - FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS) - }, - { - "+inifinity single precision", - {(uint8_t[]){0xfa, 0x7f, 0x80, 0x00, 0x00}, 5}, - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, + -75008: h'05083399', + 88: [], + 100100: { + "sub1": { + 10: [ + 0 + ], + -75009: h'A46823990001', + 100100: { + "json": "{ \"ueid\", \"xyz\"}", + "subsub": { + 100002: h'141813191001' + } + } + } + } + } + */ + +static const uint8_t spNestedCBOR[] = { + 0xa3, 0x3a, 0x00, 0x01, 0x24, 0xff, 0x44, 0x05, + 0x08, 0x33, 0x99, 0x18, 0x58, 0x80, 0x1a, 0x00, + 0x01, 0x87, 0x04, 0xa1, 0x64, 0x73, 0x75, 0x62, + 0x31, 0xa3, 0x0a, 0x81, 0x00, 0x3a, 0x00, 0x01, + 0x25, 0x00, 0x46, 0xa4, 0x68, 0x23, 0x99, 0x00, + 0x01, 0x1a, 0x00, 0x01, 0x87, 0x04, 0xa2, 0x64, + 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x7b, 0x20, 0x22, + 0x75, 0x65, 0x69, 0x64, 0x22, 0x2c, 0x20, 0x22, + 0x78, 0x79, 0x7a, 0x22, 0x7d, 0x66, 0x73, 0x75, + 0x62, 0x73, 0x75, 0x62, 0xa1, 0x1a, 0x00, 0x01, + 0x86, 0xa2, 0x46, 0x14, 0x18, 0x13, 0x19, 0x10, + 0x01 +}; + +/* Get item in multi-level nesting in spNestedCBOR */ +static int32_t DecodeNestedGetSubSub(QCBORDecodeContext *pDCtx) +{ + UsefulBufC String; + + uint8_t test_oemid_bytes[] = {0x14, 0x18, 0x13, 0x19, 0x10, 0x01}; + const struct q_useful_buf_c test_oemid = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(test_oemid_bytes); + + QCBORDecode_EnterMapFromMapN(pDCtx, 100100); + QCBORDecode_EnterMap(pDCtx, NULL); + QCBORDecode_EnterMapFromMapN(pDCtx, 100100); + QCBORDecode_EnterMapFromMapSZ(pDCtx, "subsub"); + QCBORDecode_GetByteStringInMapN(pDCtx, 100002, &String); + if(QCBORDecode_GetError(pDCtx)) { + return 4001; + } + if(UsefulBuf_Compare(String, test_oemid)) { + return 4002; + } + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + + return 0; +} + +/* Iterations on the zero-length array in spNestedCBOR */ +static int32_t DecodeNestedGetEmpty(QCBORDecodeContext *pDCtx) +{ + QCBORItem Item; + QCBORError uErr; + + QCBORDecode_EnterArrayFromMapN(pDCtx, 88); + for(int x = 0; x < 20; x++) { + uErr = QCBORDecode_GetNext(pDCtx, &Item); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 4100; + + } + } + QCBORDecode_ExitArray(pDCtx); + if(QCBORDecode_GetError(pDCtx)) { + return 4101; + } + + return 0; +} + +/* Various iterations on the array that contains a zero in spNestedCBOR */ +static int32_t DecodeNestedGetZero(QCBORDecodeContext *pDCtx) +{ + QCBORError uErr; + + QCBORDecode_EnterMapFromMapN(pDCtx, 100100); + QCBORDecode_EnterMapFromMapSZ(pDCtx, "sub1"); + QCBORDecode_EnterArrayFromMapN(pDCtx, 10); + int64_t nInt = 99; + QCBORDecode_GetInt64(pDCtx, &nInt); + if(nInt != 0) { + return 4200; + } + for(int x = 0; x < 20; x++) { + QCBORItem Item; + uErr = QCBORDecode_GetNext(pDCtx, &Item); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 4201; + + } + } + QCBORDecode_ExitArray(pDCtx); + if(QCBORDecode_GetAndResetError(pDCtx)) { + return 4202; + } + QCBORDecode_EnterArrayFromMapN(pDCtx, 10); + UsefulBufC dD; + QCBORDecode_GetByteString(pDCtx, &dD); + if(QCBORDecode_GetAndResetError(pDCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 4203; + } + for(int x = 0; x < 20; x++) { + QCBORDecode_GetByteString(pDCtx, &dD); + uErr = QCBORDecode_GetAndResetError(pDCtx); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 4204; + } + } + QCBORDecode_ExitArray(pDCtx); + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + + return 0; +} + +/* Repeatedly enter and exit maps and arrays, go off the end of maps + and arrays and such. */ +static int32_t DecodeNestedIterate(void) +{ + QCBORDecodeContext DCtx; + int32_t nReturn; + QCBORError uErr; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNestedCBOR), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + + for(int j = 0; j < 5; j++) { + for(int i = 0; i < 20; i++) { + nReturn = DecodeNestedGetSubSub(&DCtx); + if(nReturn) { + return nReturn; + } + } + + for(int i = 0; i < 20; i++) { + nReturn = DecodeNestedGetEmpty(&DCtx); + if(nReturn ) { + return nReturn; + } + } + + for(int i = 0; i < 20; i++) { + nReturn = DecodeNestedGetZero(&DCtx); + if(nReturn ) { + return nReturn; + } + } + } + + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr) { + return (int32_t)uErr + 4100; + } + + return 0; +} + + +/* + [ + 23, + 6000, + h'67616C6163746963', + h'686176656E20746F6B656E' + ] + */ +static const uint8_t spSimpleArray[] = { + 0x84, + 0x17, + 0x19, 0x17, 0x70, + 0x48, 0x67, 0x61, 0x6C, 0x61, 0x63, 0x74, 0x69, 0x63, + 0x4B, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E}; + +/* [h'', {}, [], 0] */ +static const uint8_t spArrayOfEmpty[] = {0x84, 0x40, 0xa0, 0x80, 0x00}; + +/* {} */ +static const uint8_t spEmptyMap[] = {0xa0}; + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/* {} */ +static const uint8_t spEmptyInDefinteLengthMap[] = {0xbf, 0xff}; + + +/* + { + 0: [], + 9: [ + [], + [] + ], + 8: { + 1: [], + 2: {}, + 3: [] + }, + 4: {}, + 5: [], + 6: [ + [], + [] + ] + } + */ +static const uint8_t spMapOfEmpty[] = { + 0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, + 0xa3, 0x01, 0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, + 0xa0, 0x05, 0x9f, 0xff, 0x06, 0x9f, 0x80, 0x9f, + 0xff, 0xff}; + +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + +/* + Too many tags + Duplicate label + Integer overflow + Date overflow + + { + 1: 224(225(226(227(4(0))))), + 3: -18446744073709551616, + 4: 1(1.0e+300), + 5: 0, + 8: 8 + } + */ +static const uint8_t spRecoverableMapErrors[] = { +#ifndef QCBOR_DISABLE_TAGS + 0xa6, + 0x04, 0xc1, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c, + 0x01, 0xd8, 0xe0, 0xd8, 0xe1, 0xd8, 0xe2, 0xd8, 0xe3, 0xd8, 0x04, 0x00, +#else + 0xa4, +#endif + 0x03, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x05, 0x00, + 0x05, 0x00, + 0x08, 0x08, +}; + +/* Bad break */ +static const uint8_t spUnRecoverableMapError1[] = { + 0xa2, 0xff, 0x01, 0x00, 0x02, 0x00 +}; + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/* No more items */ +static const uint8_t spUnRecoverableMapError2[] = { + 0xbf, 0x02, 0xbf, 0xff, 0x01, 0x00, 0x02, 0x00 +}; + +/* Hit end because string is too long */ +static const uint8_t spUnRecoverableMapError3[] = { + 0xbf, 0x02, 0x69, 0x64, 0x64, 0xff +}; + +/* Hit end because string is too long */ +static const uint8_t spUnRecoverableMapError4[] = { + 0xbf, + 0x02, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff +}; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + +const unsigned char not_well_formed_submod_section[] = { + 0xa1, 0x14, 0x1f, +}; + + +/* Array of length 3, but only two items. */ +const unsigned char spBadConsumeInput[] = { + 0x83, 0x00, 0x00 +}; + +/* Tag nesting too deep. */ +const unsigned char spBadConsumeInput2[] = { + 0x81, + 0xD8, 0x37, + 0xD8, 0x2C, + 0xD8, 0x21, + 0xD6, + 0xCB, + 00 +}; + + +const unsigned char spBadConsumeInput4[] = { + 0x81, 0x9f, 0x00, 0xff +}; + +const unsigned char spBadConsumeInput5[] = { + 0xa1, 0x80, 0x00 +}; + +/* + Lots of nesting for various nesting tests. + { 1:1, + 2:{ + 21:21, + 22:{ + 221:[2111, 2112, 2113], + 222:222, + 223: {} + }, + 23: 23 + }, + 3:3, + 4: [ {} ] + } + */ +static const uint8_t spNested[] = { +0xA4, /* Map of 4 */ + 0x01, 0x01, /* Map entry 1 : 1 */ + 0x02, 0xA3, /* Map entry 2 : {, an array of 3 */ + 0x15, 0x15, /* Map entry 21 : 21 */ + 0x16, 0xA3, /* Map entry 22 : {, a map of 3 */ + 0x18, 0xDD, 0x83, /* Map entry 221 : [ an array of 3 */ + 0x19, 0x08, 0x3F, /* Array item 2111 */ + 0x19, 0x08, 0x40, /* Array item 2112 */ + 0x19, 0x08, 0x41, /* Array item 2113 */ + 0x18, 0xDE, 0x18, 0xDE, /* Map entry 222 : 222 */ + 0x18, 0xDF, 0xA0, /* Map entry 223 : {} */ + 0x17, 0x17, /* Map entry 23 : 23 */ + 0x03, 0x03, /* Map entry 3 : 3 */ + 0x04, 0x81, /* Map entry 4: [, an array of 1 */ + 0xA0 /* Array entry {}, an empty map */ +}; + + +static int32_t EnterMapCursorTest(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item1; + int64_t nInt; + QCBORError uErr; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN (&DCtx, 3, &nInt); + uErr = QCBORDecode_GetNext(&DCtx, &Item1); + if(uErr != QCBOR_SUCCESS) { + return 701; + } + if(Item1.uDataType != QCBOR_TYPE_INT64) { + return 700; + } + + + int i; + for(i = 0; i < 13; i++) { + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + int j; + /* Move travesal cursor */ + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterMapFromMapN(&DCtx, 2); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 3) { + return 8000; + } + } + + for(i = 0; i < 13; i++) { + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + int j; + /* Move travesal cursor */ + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterMapFromMapN(&DCtx, 2); + QCBORDecode_EnterMapFromMapN(&DCtx, 22); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 23) { + return 8000; + } + } + + for(i = 0; i < 13; i++) { + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + int j; + /* Move travesal cursor */ + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterMapFromMapN(&DCtx, 2); + QCBORDecode_EnterMapFromMapN(&DCtx, 22); + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterArrayFromMapN(&DCtx, 221); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 23) { + return 8000; + } + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 3) { + return 8000; + } + } + + return 0; +} + + +int32_t EnterMapTest(void) +{ + QCBORItem Item1; + QCBORDecodeContext DCtx; + int32_t nReturn; + QCBORError uErr; + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapOfEmpty), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 0 + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 9 + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_EnterMap(&DCtx, NULL); // Label 8 + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitMap(&DCtx); + + QCBORDecode_EnterMap(&DCtx, NULL); // Label4 + QCBORDecode_ExitMap(&DCtx); + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 5 + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 6 + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_ExitMap(&DCtx); + + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS){ + return 3011; + } + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + (void)pValidMapIndefEncoded; + nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded)); + if(nReturn) { + return nReturn + 20000; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORItem ArrayItem; + + nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); + if(nReturn) { + return nReturn; + } + + + + // These tests confirm the cursor is at the right place after entering + // a map or array + const UsefulBufC ValidEncodedMap = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded); + + // Confirm cursor is at right place + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_INT64) { + return 2001; + } + + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_VGetNext(&DCtx, &Item1); + QCBORDecode_VGetNext(&DCtx, &Item1); + QCBORDecode_EnterArray(&DCtx, &ArrayItem); + if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(ArrayItem.label.string, + UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { + return 2051; + } + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { + return 2002; + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterMap(&DCtx, &ArrayItem); + if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(ArrayItem.label.string, + UsefulBuf_FROM_SZ_LITERAL("map in a map"))) { + return 2052; + } + + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_BYTE_STRING) { + return 2003; + } + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { + return 2004; + } + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP && Item1.uLabelAlloc != QCBOR_TYPE_TEXT_STRING) { + return 2006; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetNext(&DCtx, &Item1) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2007; + } +#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */ + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleArray), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + int64_t nDecodedInt2; + + UsefulBufC String; + QCBORDecode_GetTextStringInMapN(&DCtx, 88, &String); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ + return 2009; + } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ + return 2008; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyMap), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + // This will fail because the map is empty. + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ + return 2010; + } + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS){ + return 2011; + } + + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyInDefinteLengthMap), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + // This will fail because the map is empty. + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ + return 2012; + } + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS){ + return 2013; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spArrayOfEmpty), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetByteString(&DCtx, &String); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_GetInt64(&DCtx, &nDecodedInt2); + QCBORDecode_ExitArray(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS) { + return 2014; + } + + int64_t nInt; + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spRecoverableMapErrors), 0); + QCBORDecode_EnterMap(&DCtx, NULL); +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetError(&DCtx); + if(uErr != QCBOR_ERR_TOO_MANY_TAGS) { + return 2021; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != CBOR_TAG_INVALID64) { + return 2121; + } + (void)QCBORDecode_GetAndResetError(&DCtx); +#endif + + + QCBORDecode_GetInt64InMapN(&DCtx, 0x03, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_INT_OVERFLOW) { + return 2023; + } + +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_GetEpochDateInMapN(&DCtx, 0x04, QCBOR_TAG_REQUIREMENT_TAG, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return 2024; + } +#endif + + QCBORDecode_GetInt64InMapN(&DCtx, 0x05, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_DUPLICATE_LABEL) { + return 2025; + } + + QCBORDecode_GetInt64InMapN(&DCtx, 0x08, &nInt); + + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS) { + return 2026; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError1), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_BAD_BREAK) { + return 2030; + } + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError2), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 2031; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError3), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_HIT_END) { + return 2032; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError4), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { + return 2033; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP) { + return 2401; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2402; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + QCBORDecode_VGetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3 || + Item1.uNextNestLevel != 1) { + return 2403; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2404; + } + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_INT64 || + Item1.uNextNestLevel != 1 || + Item1.val.int64 != 42) { + return 2405; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2406; + } + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_ARRAY || + Item1.uNestingLevel != 1 || + Item1.uNextNestLevel != 1 || + Item1.val.uCount != 2) { + return 2407; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2408; + } + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.uNestingLevel != 1 || + Item1.uNextNestLevel != 0 || + Item1.val.uCount != 4) { + return 2409; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2410; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + nReturn = DecodeNestedIterate(); + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(not_well_formed_submod_section), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_EnterMapFromMapN(&DCtx, 20); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_BAD_INT) { + return 2500; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2600; + } + +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput2), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 2700; + } +#endif + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput4), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 2900; + } +#else + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + return 2901; + } +#endif + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput5), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_MAP_LABEL_TYPE) { + return 3000; + } + + nReturn = EnterMapCursorTest(); + + return nReturn; +} + + +struct NumberConversion { + char *szDescription; + UsefulBufC CBOR; + int64_t nConvertedToInt64; + QCBORError uErrorInt64; + uint64_t uConvertToUInt64; + QCBORError uErrorUint64; + double dConvertToDouble; + QCBORError uErrorDouble; +}; + +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA +#define EXP_AND_MANTISSA_ERROR(x) x +#else +#define EXP_AND_MANTISSA_ERROR(x) QCBOR_ERR_UNEXPECTED_TYPE +#endif + + +static const struct NumberConversion NumberConversions[] = { +#ifndef QCBOR_DISABLE_TAGS + { + "Big float: INT64_MIN * 2e-1 to test handling of INT64_MIN", + {(uint8_t[]){0xC5, 0x82, 0x20, + 0x3B, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x0ff, 0xff, 0xff, + }, 15}, + -4611686018427387904, /* INT64_MIN / 2 */ + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -4.6116860184273879E+18, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "too large to fit into int64_t", + {(uint8_t[]){0xc3, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 10}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + ((double)INT64_MIN) + 1 , + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "largest negative int that fits in int64_t", + {(uint8_t[]){0xc3, 0x48, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 10}, + INT64_MIN, + QCBOR_SUCCESS, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + (double)INT64_MIN, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "negative bignum -1", + {(uint8_t[]){0xc3, 0x41, 0x00}, 3}, + -1, + QCBOR_SUCCESS, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -1.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "Decimal Fraction with positive bignum 257 * 10e3", + {(uint8_t[]){0xC4, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC2, 0x42, 0x01, 0x01}, 15}, + 257000, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 257000, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 257000.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "bigfloat with negative bignum -258 * 2e3", + {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC3, 0x42, 0x01, 0x01}, 15}, + -2064, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -2064.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "bigfloat with positive bignum 257 * 2e3", + {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC2, 0x42, 0x01, 0x01}, 15}, + 2056, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 2056, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 2056.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "negative bignum 0xc349010000000000000000 -18446744073709551617", + {(uint8_t[]){0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 11}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -18446744073709551617.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + { + "Positive bignum 0x01020304 indefinite length string", + {(uint8_t[]){0xC2, 0x5f, 0x42, 0x01, 0x02, 0x41, 0x03, 0x41, 0x04, 0xff}, 10}, + 0x01020304, + QCBOR_SUCCESS, + 0x01020304, + QCBOR_SUCCESS, + 16909060.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + { + "Decimal Fraction with neg bignum [9223372036854775807, -4759477275222530853137]", + {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 23}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "big float [9223372036854775806, 9223372036854775806]", + {(uint8_t[]){0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Big float 3 * 2^^2", + {(uint8_t[]){0xC5, 0x82, 0x02, 0x03}, 4}, + 12, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 12, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 12.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Decimal fraction 3/10", + {(uint8_t[]){0xC4, 0x82, 0x20, 0x03}, 4}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0.30000000000000004, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Decimal fraction -3/10", + {(uint8_t[]){0xC4, 0x82, 0x20, 0x22}, 4}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -0.30000000000000004, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Decimal fraction -3/10, neg bignum mantissa", + {(uint8_t[]){0xC4, 0x82, 0x20, 0xc3, 0x41, 0x02}, 6}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -0.30000000000000004, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "extreme pos bignum", + {(uint8_t[]){0xc2, 0x59, 0x01, 0x90, + // 50 rows of 8 is 400 digits. + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, + 404}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + }, + + { + "extreme neg bignum", + {(uint8_t[]){0xc3, 0x59, 0x01, 0x90, + // 50 rows of 8 is 400 digits. + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, + 404}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + + { + "big float underflow [9223372036854775806, -9223372036854775806]", + {(uint8_t[]){ + 0xC5, 0x82, + 0x3B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + + { + "bigfloat that evaluates to -INFINITY", + {(uint8_t[]){ + 0xC5, 0x82, + 0x1B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC3, 0x42, 0x01, 0x01}, 15}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Positive bignum 0xffff", + {(uint8_t[]){0xC2, 0x42, 0xff, 0xff}, 4}, + 65536-1, + QCBOR_SUCCESS, + 0xffff, + QCBOR_SUCCESS, + 65535.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +#endif /* QCBOR_DISABLE_TAGS */ + { + "Positive integer 18446744073709551615", + {(uint8_t[]){0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 18446744073709551615ULL, + QCBOR_SUCCESS, + 18446744073709551615.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + + { + "Postive integer 0", + {(uint8_t[]){0x0}, 1}, + 0LL, + QCBOR_SUCCESS, + 0ULL, + QCBOR_SUCCESS, + 0.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "Negative integer -18446744073709551616", + {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9}, + -9223372036854775807-1, // INT64_MIN + QCBOR_SUCCESS, + 0ULL, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -9223372036854775808.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "Double Floating point value 100.3", + {(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9}, + 100L, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + 100ULL, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + 100.3, + FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS), + }, + { + "Floating point value NaN 0xfa7fc00000", + {(uint8_t[]){0xfa, 0x7f, 0xc0, 0x00, 0x00}, 5}, + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), + NAN, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + }, + { + "half-precision Floating point value -4", + {(uint8_t[]){0xf9, 0xc4, 0x00}, 3}, + // Normal case with all enabled. + -4, + FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS), + 0, + FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -4.0, + FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS) + }, + { + "+inifinity single precision", + {(uint8_t[]){0xfa, 0x7f, 0x80, 0x00, 0x00}, 5}, + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +}; + + + + +static int32_t SetUpDecoder(QCBORDecodeContext *DCtx, UsefulBufC CBOR, UsefulBuf Pool) +{ + QCBORDecode_Init(DCtx, CBOR, QCBOR_DECODE_MODE_NORMAL); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + if(QCBORDecode_SetMemPool(DCtx, Pool, 0)) { + return 1; + } +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + (void)Pool; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + return 0; +} + + +int32_t IntegerConvertTest(void) +{ + const int nNumTests = C_ARRAY_COUNT(NumberConversions, + struct NumberConversion); + + for(int nIndex = 0; nIndex < nNumTests; nIndex++) { + const struct NumberConversion *pF = &NumberConversions[nIndex]; + + // Set up the decoding context including a memory pool so that + // indefinite length items can be checked + QCBORDecodeContext DCtx; + UsefulBuf_MAKE_STACK_UB(Pool, 100); + + /* ----- test conversion to int64_t ------ */ + if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { + return (int32_t)(3333+nIndex); + } + + int64_t nInt; + QCBORDecode_GetInt64ConvertAll(&DCtx, 0xffff, &nInt); + if(QCBORDecode_GetError(&DCtx) != pF->uErrorInt64) { + return (int32_t)(2000+nIndex); + } + if(pF->uErrorInt64 == QCBOR_SUCCESS && pF->nConvertedToInt64 != nInt) { + return (int32_t)(3000+nIndex); + } + + /* ----- test conversion to uint64_t ------ */ + if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { + return (int32_t)(3333+nIndex); + } + + uint64_t uInt; + QCBORDecode_GetUInt64ConvertAll(&DCtx, 0xffff, &uInt); + if(QCBORDecode_GetError(&DCtx) != pF->uErrorUint64) { + return (int32_t)(4000+nIndex); + } + if(pF->uErrorUint64 == QCBOR_SUCCESS && pF->uConvertToUInt64 != uInt) { + return (int32_t)(5000+nIndex); + } + + /* ----- test conversion to double ------ */ + if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { + return (int32_t)(3333+nIndex); + } + +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + double d; + QCBORDecode_GetDoubleConvertAll(&DCtx, 0xffff, &d); + if(QCBORDecode_GetError(&DCtx) != pF->uErrorDouble) { + return (int32_t)(6000+nIndex); + } + if(pF->uErrorDouble == QCBOR_SUCCESS) { + if(isnan(pF->dConvertToDouble)) { + // NaN's can't be compared for equality. A NaN is + // never equal to anything including another NaN + if(!isnan(d)) { + return (int32_t)(7000+nIndex); + } + } else { + if(pF->dConvertToDouble != d) { + return (int32_t)(8000+nIndex); + } + } + } +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + } + + return 0; +} + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + +int32_t CBORTestIssue134(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uCBORError; + const uint8_t spTestIssue134[] = { 0x5F, 0x40, 0xFF }; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTestIssue134), + QCBOR_DECODE_MODE_NORMAL); + + UsefulBuf_MAKE_STACK_UB(StringBuf, 200); + QCBORDecode_SetMemPool(&DCtx, StringBuf, false); + + do { + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + } while (QCBOR_SUCCESS == uCBORError); + + uCBORError = QCBORDecode_Finish(&DCtx); + + return (int32_t)uCBORError; +} + +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + + +static const uint8_t spSequenceTestInput[] = { + /* 1. The valid date string "1985-04-12" */ + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + + /* 2. */ + 0x00, + + /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ + 0x1a, 0x53, 0x72, 0x4E, 0x00, + + /* 4. */ + 0x62, 'h', 'i', +}; + + +int32_t CBORSequenceDecodeTests(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uCBORError; + size_t uConsumed; + + // --- Test a sequence with extra bytes --- + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput), + QCBOR_DECODE_MODE_NORMAL); + + // Get 1. + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 1; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ) { + return 2; + } + + uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); + if(uCBORError != QCBOR_ERR_EXTRA_BYTES || + uConsumed != 11) { + return 102; + } + + // Get 2. + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 66; + } + + uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); + if(uCBORError != QCBOR_ERR_EXTRA_BYTES || + uConsumed != 12) { + return 102; + } + + // Get 3. + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 2; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + 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); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + 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_UNCONSUMED) { + return 11; + } +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + return 20; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + + // --- 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); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + + 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; + } +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + return 20; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + + return 0; +} + + + +int32_t IntToTests(void) +{ + 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_Int64ToUInt16((int64_t)UINT16_MAX, &u16); + if(nErrCode == -1 || u16 != UINT16_MAX) { + return 21; + } + + nErrCode = QCBOR_Int64ToUInt16((int64_t)0, &u16); + if(nErrCode == -1 || u16 != 0) { + return 22; + } + + nErrCode = QCBOR_Int64ToUInt16(1, &u16); + if(nErrCode == -1 || u16 != 1) { + return 23; + } + + nErrCode = QCBOR_Int64ToUInt16(((int64_t)UINT16_MAX)+1, &u16); + if(nErrCode != -1) { + return 24; + } + + nErrCode = QCBOR_Int64ToUInt16((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; + } -static int32_t SetUpDecoder(QCBORDecodeContext *DCtx, UsefulBufC CBOR, UsefulBuf Pool) -{ - QCBORDecode_Init(DCtx, CBOR, QCBOR_DECODE_MODE_NORMAL); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - if(QCBORDecode_SetMemPool(DCtx, Pool, 0)) { - return 1; + nErrCode = QCBOR_Int64ToUInt64((int64_t)0, &u64); + if(nErrCode == -1 || u64 != 0) { + return 33; } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - (void)Pool; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + nErrCode = QCBOR_Int64ToUInt64((int64_t)-1, &u64); + if(nErrCode != -1) { + return 34; + } + return 0; } -int32_t IntegerConvertTest(void) + + +/* +A sequence with + A wrapping bstr + containing a map + 1 + 2 + A wrapping bstr + containing an array + 3 + wrapping bstr + 4 + 5 + 6 + array + 7 + 8 + */ + +static UsefulBufC EncodeBstrWrapTestData(UsefulBuf OutputBuffer) { - const int nNumTests = C_ARRAY_COUNT(NumberConversions, - struct NumberConversion); + UsefulBufC Encoded; + QCBOREncodeContext EC; + QCBORError uErr; - for(int nIndex = 0; nIndex < nNumTests; nIndex++) { - const struct NumberConversion *pF = &NumberConversions[nIndex]; + QCBOREncode_Init(&EC, OutputBuffer); - // Set up the decoding context including a memory pool so that - // indefinite length items can be checked - QCBORDecodeContext DCtx; - UsefulBuf_MAKE_STACK_UB(Pool, 100); +#ifndef QCBOR_DISABLE_TAGS + QCBOREncode_AddTag(&EC, CBOR_TAG_CBOR); +#endif /* ! QCBOR_DISABLE_TAGS */ + QCBOREncode_BstrWrap(&EC); + QCBOREncode_OpenMap(&EC); + QCBOREncode_AddInt64ToMapN(&EC, 100, 1); + QCBOREncode_AddInt64ToMapN(&EC, 200, 2); + QCBOREncode_CloseMap(&EC); + QCBOREncode_BstrWrap(&EC); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddInt64(&EC, 3); + QCBOREncode_BstrWrap(&EC); + QCBOREncode_AddInt64(&EC, 4); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_AddInt64(&EC, 5); + QCBOREncode_CloseArray(&EC); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_AddInt64(&EC, 6); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddInt64(&EC, 7); + QCBOREncode_AddInt64(&EC, 8); + QCBOREncode_CloseArray(&EC); - /* ----- test conversion to int64_t ------ */ - if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { - return (int32_t)(3333+nIndex); - } + uErr = QCBOREncode_Finish(&EC, &Encoded); + if(uErr) { + Encoded = NULLUsefulBufC; + } - int64_t nInt; - QCBORDecode_GetInt64ConvertAll(&DCtx, 0xffff, &nInt); - if(QCBORDecode_GetError(&DCtx) != pF->uErrorInt64) { - return (int32_t)(2000+nIndex); - } - if(pF->uErrorInt64 == QCBOR_SUCCESS && pF->nConvertedToInt64 != nInt) { - return (int32_t)(3000+nIndex); - } + return Encoded; +} - /* ----- test conversion to uint64_t ------ */ - if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { - return (int32_t)(3333+nIndex); - } +/* h'FF' */ +static const uint8_t spBreakInByteString[] = { + 0x41, 0xff +}; - uint64_t uInt; - QCBORDecode_GetUInt64ConvertAll(&DCtx, 0xffff, &uInt); - if(QCBORDecode_GetError(&DCtx) != pF->uErrorUint64) { - return (int32_t)(4000+nIndex); - } - if(pF->uErrorUint64 == QCBOR_SUCCESS && pF->uConvertToUInt64 != uInt) { - return (int32_t)(5000+nIndex); - } - /* ----- test conversion to double ------ */ - if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { - return (int32_t)(3333+nIndex); - } +int32_t EnterBstrTest(void) +{ + UsefulBuf_MAKE_STACK_UB(OutputBuffer, 100); -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - double d; - QCBORDecode_GetDoubleConvertAll(&DCtx, 0xffff, &d); - if(QCBORDecode_GetError(&DCtx) != pF->uErrorDouble) { - return (int32_t)(6000+nIndex); - } - if(pF->uErrorDouble == QCBOR_SUCCESS) { - if(isnan(pF->dConvertToDouble)) { - // NaN's can't be compared for equality. A NaN is - // never equal to anything including another NaN - if(!isnan(d)) { - return (int32_t)(7000+nIndex); - } - } else { - if(pF->dConvertToDouble != d) { - return (int32_t)(8000+nIndex); - } - } - } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + QCBORDecodeContext DC; + + QCBORDecode_Init(&DC, EncodeBstrWrapTestData(OutputBuffer), 0); + + int64_t n1, n2, n3, n4, n5, n6, n7, n8; + +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_TAG, NULL); +#else + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); +#endif /* ! QCBOR_DISABLE_TAGS */ + QCBORDecode_EnterMap(&DC, NULL); + QCBORDecode_GetInt64InMapN(&DC, 100, &n1); + QCBORDecode_GetInt64InMapN(&DC, 200, &n2); + QCBORDecode_ExitMap(&DC); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_GetInt64(&DC, &n3); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + QCBORDecode_GetInt64(&DC, &n4); + QCBORDecode_ExitBstrWrapped(&DC); + QCBORDecode_GetInt64(&DC, &n5); + QCBORDecode_ExitArray(&DC); + QCBORDecode_ExitBstrWrapped(&DC); + QCBORDecode_GetInt64(&DC, &n6); + QCBORDecode_ExitBstrWrapped(&DC); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_GetInt64(&DC, &n7); + QCBORDecode_GetInt64(&DC, &n8); + QCBORDecode_ExitArray(&DC); + + QCBORError uErr = QCBORDecode_Finish(&DC); + if(uErr) { + return (int32_t)uErr; + } + + + /* Enter and exit byte string wrapped CBOR that is bad. It has just a break. + * Successful because no items are fetched from byte string. + */ + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), + 0); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr) { + return 100 + (int32_t)uErr; + } + + QCBORDecode_ExitBstrWrapped(&DC); + uErr = QCBORDecode_GetError(&DC); + if(uErr) { + return 200 + (int32_t)uErr; + } + + /* Try to get item that is a break out of a byte string wrapped CBOR. + * It fails because there should be no break. + */ + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), + 0); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + QCBORItem Item; + uErr = QCBORDecode_GetNext(&DC, &Item); + if(uErr != QCBOR_ERR_BAD_BREAK) { + return 300 + (int32_t)uErr; } return 0; } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS -int32_t CBORTestIssue134(void) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError uCBORError; - const uint8_t spTestIssue134[] = { 0x5F, 0x40, 0xFF }; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTestIssue134), - QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_MAKE_STACK_UB(StringBuf, 200); - QCBORDecode_SetMemPool(&DCtx, StringBuf, false); +static const uint8_t spTaggedTypes[] = { + 0xb2, + + // Date string + 0x00, + 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, + 0x31, 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, + 0x32, 0x5A, + + 0x01, + 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, 0x31, + 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, 0x32, + 0x5A, + + // Bignum + 10, + 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, + + 11, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, + + // URL + 20, + 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, + 0x63, 0x62, 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, + + 21, + 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x62, + 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, + + // B64 + 0x18, 0x1e, + 0xd8, 0x22, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, + 0x31, 0x63, 0x6D, 0x55, 0x75, + + 0x18, 0x1f, + 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, + 0x6D, 0x55, 0x75, - do { - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - } while (QCBOR_SUCCESS == uCBORError); + // B64URL + 0x18, 0x28, + 0xd8, 0x21, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, + 0x31, 0x63, 0x6D, 0x55, 0x75, - uCBORError = QCBORDecode_Finish(&DCtx); + 0x18, 0x29, + 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, + 0x6D, 0x55, 0x75, - return (int32_t)uCBORError; -} + // Regex + 0x18, 0x32, + 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, + 0x6B, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + 0x18, 0x33, + 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, 0x6B, + // MIME + 0x18, 0x3c, + 0xd8, 0x24, 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, + 0x0A, + 0x18, 0x3d, + 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, -static const uint8_t spSequenceTestInput[] = { - /* 1. The valid date string "1985-04-12" */ - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x18, 0x3e, + 0xd9, 0x01, 0x01, 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0A, - /* 2. */ - 0x00, + 0x18, 0x3f, + 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, - /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ - 0x1a, 0x53, 0x72, 0x4E, 0x00, + // UUID + 0x18, 0x46, + 0xd8, 0x25, 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, + 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, - /* 4. */ - 0x62, 'h', 'i', + 0x18, 0x47, + 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, + 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32 }; - -int32_t CBORSequenceDecodeTests(void) +int32_t DecodeTaggedTypeTests(void) { - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError uCBORError; - size_t uConsumed; + QCBORDecodeContext DC; + QCBORError uErr; - // --- Test a sequence with extra bytes --- + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedTypes), 0); - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput), - QCBOR_DECODE_MODE_NORMAL); + UsefulBufC String; + bool bNeg; - // Get 1. - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_EnterMap(&DC, NULL); + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_TAG, &String); + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); + if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { return 1; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ) { - return 2; - } - - uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); - if(uCBORError != QCBOR_ERR_EXTRA_BYTES || - uConsumed != 11) { - return 102; - } - - // Get 2. - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { - return 66; - } - - uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); - if(uCBORError != QCBOR_ERR_EXTRA_BYTES || - uConsumed != 12) { - return 102; - } - - // Get 3. - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { return 2; } - if(Item.uDataType != QCBOR_TYPE_INT64) { + QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { 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) { + QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); + QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { 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) { + QCBORDecode_GetDateStringInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { 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); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(uCBORError != QCBOR_SUCCESS) { - return 9; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { + QCBORDecode_GetBignumInMapN(&DC, 10, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bNeg != false) { 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_UNCONSUMED) { + QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bNeg != true) { return 11; } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { - return 20; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - // --- 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) { + QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { return 12; } - if(Item.uDataType != QCBOR_TYPE_INT64) { + QCBORDecode_GetBignumInMapN(&DC, 14, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { return 13; } - - // Get a second item - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_GetBignumInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { 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; - } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + QCBORDecode_GetURIInMapN(&DC, 20, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { return 20; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - return 0; -} - - - -int32_t IntToTests(void) -{ - int nErrCode; - int32_t n32; - int16_t n16; - int8_t n8; - uint32_t u32; - uint16_t u16; - uint8_t u8; - uint64_t u64; + QCBORDecode_GetURIInMapN(&DC, 21, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 21; + } + QCBORDecode_GetURIInMapN(&DC, 22, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 22; + } + QCBORDecode_GetURIInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 23; + } - nErrCode = QCBOR_Int64ToInt32(1, &n32); - if(nErrCode == -1 || n32 != 1) { - return 1; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + QCBORDecode_GetB64InMapN(&DC, 30, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 30; + } +#endif + QCBORDecode_GetB64InMapN(&DC, 31, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 31; } - - nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MAX, &n32); - if(nErrCode == -1 || n32 != INT32_MAX) { - return 2; + QCBORDecode_GetB64InMapN(&DC, 32, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 32; } - - nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MIN, &n32); - if(nErrCode == -1 || n32 != INT32_MIN) { - return 3; + QCBORDecode_GetB64InMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 33; } - nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MAX)+1, &n32); - if(nErrCode != -1) { - return 4; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + QCBORDecode_GetB64URLInMapN(&DC, 40, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 40; } - - nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MIN)-1, &n32); - if(nErrCode != -1) { - return 5; +#endif + QCBORDecode_GetB64URLInMapN(&DC, 41, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 41; } - - - nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MAX, &n16); - if(nErrCode == -1 || n16 != INT16_MAX) { - return 6; + QCBORDecode_GetB64URLInMapN(&DC, 42, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 42; } - - nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MIN, &n16); - if(nErrCode == -1 || n16 != INT16_MIN) { - return 7; + QCBORDecode_GetB64URLInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 43; } - nErrCode = QCBOR_Int64ToInt16(1, &n16); - if(nErrCode == -1 || n16 != 1) { - return 8; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + QCBORDecode_GetRegexInMapN(&DC, 50, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 50; } - - nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MAX)+1, &n16); - if(nErrCode != -1) { - return 9; +#endif + QCBORDecode_GetRegexInMapN(&DC, 51, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 51; } - - nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MIN)-1, &n16); - if(nErrCode != -1) { - return 10; + QCBORDecode_GetRegexInMapN(&DC, 52, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 52; } - - - nErrCode = QCBOR_Int64ToInt8(1, &n8); - if(nErrCode == -1 || n8 != 1) { - return 11; + QCBORDecode_GetRegexInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 53; } - nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MAX, &n8); - if(nErrCode == -1 || n8 != INT8_MAX) { - return 12; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + // MIME + bool bIsNot7Bit; + QCBORDecode_GetMIMEMessageInMapN(&DC, 60, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == true) { + return 60; } - - nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MIN, &n8); - if(nErrCode == -1 || n8 != INT8_MIN) { - return 13; + QCBORDecode_GetMIMEMessageInMapN(&DC, 61, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == true) { + return 61; } - - nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MAX)+1, &n8); - if(nErrCode != -1) { - return 14; + QCBORDecode_GetMIMEMessageInMapN(&DC, 62, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == false) { + return 62; } - - nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MIN)-1, &n8); - if(nErrCode != -1) { - return 15; + QCBORDecode_GetMIMEMessageInMapN(&DC, 63, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == false) { + return 63; + } + QCBORDecode_GetMIMEMessageInMapN(&DC, 64, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 64; + } + QCBORDecode_GetMIMEMessageInMapSZ(&DC, "zzz", QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 65; } - nErrCode = QCBOR_Int64ToUInt32(1, &u32); - if(nErrCode == -1 || u32 != 1) { - return 16; + QCBORDecode_GetBinaryUUIDInMapN(&DC, 70, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 70; } +#endif /* #ifndef QCBOR_DISABLE_UNCOMMON_TAGS */ - nErrCode = QCBOR_Int64ToUInt32((int64_t)UINT32_MAX, &u32); - if(nErrCode == -1 || u32 != UINT32_MAX) { - return 17; + QCBORDecode_GetBinaryUUIDInMapN(&DC, 71, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 71; } - - nErrCode = QCBOR_Int64ToUInt32((int64_t)0, &u32); - if(nErrCode == -1 || u32 != 0) { - return 18; + QCBORDecode_GetBinaryUUIDInMapN(&DC, 72, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 72; } - - nErrCode = QCBOR_Int64ToUInt32(((int64_t)UINT32_MAX)+1, &u32); - if(nErrCode != -1) { - return 19; + QCBORDecode_GetBinaryUUIDInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 73; } - nErrCode = QCBOR_Int64ToUInt32((int64_t)-1, &u32); - if(nErrCode != -1) { - return 20; - } + // Improvement: add some more error test cases + QCBORDecode_ExitMap(&DC); - nErrCode = QCBOR_Int64UToInt16((int64_t)UINT16_MAX, &u16); - if(nErrCode == -1 || u16 != UINT16_MAX) { - return 21; + uErr = QCBORDecode_Finish(&DC); + if(uErr != QCBOR_SUCCESS) { + return 100; } - nErrCode = QCBOR_Int64UToInt16((int64_t)0, &u16); - if(nErrCode == -1 || u16 != 0) { - return 22; - } + return 0; +} - 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; - } +/* + [ + "aaaaaaaaaa", + {} + ] + */ +static const uint8_t spTooLarge1[] = { + 0x9f, + 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0xa0, + 0xff +}; - nErrCode = QCBOR_Int64ToUInt8((int64_t)UINT8_MAX, &u8); - if(nErrCode == -1 || u8 != UINT8_MAX) { - return 26; - } +/* + [ + { + 0: "aaaaaaaaaa" + } + ] + */ +static const uint8_t spTooLarge2[] = { + 0x9f, + 0xa1, + 0x00, + 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0xff +}; - nErrCode = QCBOR_Int64ToUInt8((int64_t)0, &u8); - if(nErrCode == -1 || u8 != 0) { - return 27; - } +/* + h'A1006A61616161616161616161' - nErrCode = QCBOR_Int64ToUInt8(1, &u8); - if(nErrCode == -1 || u8 != 1) { - return 28; + { + 0: "aaaaaaaaaa" } + */ +static const uint8_t spTooLarge3[] = { + 0x4d, + 0xa1, + 0x00, + 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, +}; - nErrCode = QCBOR_Int64ToUInt8(((int64_t)UINT16_MAX)+1, &u8); - if(nErrCode != -1) { - return 29; - } +int32_t TooLargeInputTest(void) +{ + QCBORDecodeContext DC; + QCBORError uErr; + UsefulBufC String; - nErrCode = QCBOR_Int64ToUInt8((int64_t)-1, &u8); - if(nErrCode != -1) { - return 30; - } + // These tests require a build with QCBOR_MAX_DECODE_INPUT_SIZE set + // to 10 There's not really any way to test this error + // condition. The error condition is not complex, so setting + // QCBOR_MAX_DECODE_INPUT_SIZE gives an OK test. + + // The input CBOR is only too large because the + // QCBOR_MAX_DECODE_INPUT_SIZE is 10. + // + // This test is disabled for the normal test runs because of the + // special build requirement. - nErrCode = QCBOR_Int64ToUInt64(1, &u64); - if(nErrCode == -1 || u64 != 1) { - return 31; + // Tests the start of a map being too large + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge1), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_GetTextString(&DC, &String); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_SUCCESS) { + return 1; + } + QCBORDecode_EnterMap(&DC, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { + return 2; } - nErrCode = QCBOR_Int64ToUInt64(INT64_MAX, &u64); - if(nErrCode == -1 || u64 != INT64_MAX) { - return 32; + // Tests the end of a map being too large + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge2), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_EnterMap(&DC, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_SUCCESS) { + return 3; } - - nErrCode = QCBOR_Int64ToUInt64((int64_t)0, &u64); - if(nErrCode == -1 || u64 != 0) { - return 33; + QCBORDecode_ExitMap(&DC); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { + return 4; } - nErrCode = QCBOR_Int64ToUInt64((int64_t)-1, &u64); - if(nErrCode != -1) { - return 34; + // Tests the entire input CBOR being too large when processing bstr wrapping + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge3), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { + return 5; } return 0; } - +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS /* -A sequence with - A wrapping bstr - containing a map - 1 - 2 - A wrapping bstr - containing an array - 3 - wrapping bstr - 4 - 5 - 6 - array - 7 - 8 + An array of three map entries + 1) Indefinite length string label for indefinite lenght byte string + 2) Indefinite length string label for an integer + 3) Indefinite length string label for an indefinite-length negative big num */ - -static UsefulBufC EncodeBstrWrapTestData(UsefulBuf OutputBuffer) -{ - UsefulBufC Encoded; - QCBOREncodeContext EC; - QCBORError uErr; - - QCBOREncode_Init(&EC, OutputBuffer); - - QCBOREncode_BstrWrap(&EC); - QCBOREncode_OpenMap(&EC); - QCBOREncode_AddInt64ToMapN(&EC, 100, 1); - QCBOREncode_AddInt64ToMapN(&EC, 200, 2); - QCBOREncode_CloseMap(&EC); - QCBOREncode_BstrWrap(&EC); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddInt64(&EC, 3); - QCBOREncode_BstrWrap(&EC); - QCBOREncode_AddInt64(&EC, 4); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_AddInt64(&EC, 5); - QCBOREncode_CloseArray(&EC); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_AddInt64(&EC, 6); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddInt64(&EC, 7); - QCBOREncode_AddInt64(&EC, 8); - QCBOREncode_CloseArray(&EC); - - uErr = QCBOREncode_Finish(&EC, &Encoded); - if(uErr) { - Encoded = NULLUsefulBufC; - } - - return Encoded; -} - -/* h'FF' */ -static const uint8_t spBreakInByteString[] = { - 0x41, 0xff +static const uint8_t spMapWithIndefLenStrings[] = { + 0xa3, + 0x7f, 0x61, 'l', 0x64, 'a', 'b', 'e', 'l' , 0x61, '1', 0xff, + 0x5f, 0x42, 0x01, 0x02, 0x43, 0x03, 0x04, 0x05, 0xff, + 0x7f, 0x62, 'd', 'y', 0x61, 'm', 0x61, 'o', 0xff, + 0x03, + 0x7f, 0x62, 'l', 'a', 0x63, 'b', 'e', 'l', 0x61, '2', 0xff, + 0xc3, + 0x5f, 0x42, 0x00, 0x01, 0x42, 0x00, 0x01, 0x41, 0x01, 0xff, }; - -int32_t EnterBstrTest(void) +int32_t SpiffyIndefiniteLengthStringsTests(void) { - UsefulBuf_MAKE_STACK_UB(OutputBuffer, 100); + QCBORDecodeContext DCtx; - QCBORDecodeContext DC; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapWithIndefLenStrings), + QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_Init(&DC, EncodeBstrWrapTestData(OutputBuffer), 0); + UsefulBuf_MAKE_STACK_UB(StringBuf, 200); + QCBORDecode_SetMemPool(&DCtx, StringBuf, false); - int64_t n1, n2, n3, n4, n5, n6, n7, n8; + UsefulBufC ByteString; + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetByteStringInMapSZ(&DCtx, "label1", &ByteString); +#ifndef QCBOR_DISABLE_TAGS + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 1; + } - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORDecode_EnterMap(&DC, NULL); - QCBORDecode_GetInt64InMapN(&DC, 100, &n1); - QCBORDecode_GetInt64InMapN(&DC, 200, &n2); - QCBORDecode_ExitMap(&DC); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_GetInt64(&DC, &n3); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORDecode_GetInt64(&DC, &n4); - QCBORDecode_ExitBstrWrapped(&DC); - QCBORDecode_GetInt64(&DC, &n5); - QCBORDecode_ExitArray(&DC); - QCBORDecode_ExitBstrWrapped(&DC); - QCBORDecode_GetInt64(&DC, &n6); - QCBORDecode_ExitBstrWrapped(&DC); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_GetInt64(&DC, &n7); - QCBORDecode_GetInt64(&DC, &n8); - QCBORDecode_ExitArray(&DC); + const uint8_t pExectedBytes[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + if(UsefulBuf_Compare(ByteString, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExectedBytes))) { + return 2; + } - QCBORError uErr = QCBORDecode_Finish(&DC); - if(uErr) { - return (int32_t)uErr; + uint64_t uInt; + QCBORDecode_GetUInt64InMapSZ(&DCtx, "dymo", &uInt); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 3; + } + if(uInt != 3) { + return 4; } +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + double uDouble; + QCBORDecode_GetDoubleConvertAllInMapSZ(&DCtx, + "label2", + 0xff, + &uDouble); - /* Enter and exit byte string wrapped CBOR that is bad. It has just a break. - * Successful because no items are fetched from byte string. - */ - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), - 0); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr) { - return 100 + (int32_t)uErr; +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 5; + } + if(uDouble != -16777474) { + return 6; + } +#else /* QCBOR_DISABLE_FLOAT_HW_USE */ + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HW_FLOAT_DISABLED) { + return 7; } +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - QCBORDecode_ExitBstrWrapped(&DC); - uErr = QCBORDecode_GetError(&DC); - if(uErr) { - return 200 + (int32_t)uErr; + QCBORDecode_ExitMap(&DCtx); + + if(QCBORDecode_Finish(&DCtx)) { + return 99; } - /* Try to get item that is a break out of a byte string wrapped CBOR. - * It fails because there should be no break. +#else /* QCBOR_DISABLE_TAGS */ + /* The big num in the input is a CBOR tag and you can't do + * map lookups in a map with a tag so this test does very little + * when tags are disabled. That is OK, the test coverage is still + * good when they are not. */ - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), - 0); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORItem Item; - uErr = QCBORDecode_GetNext(&DC, &Item); - if(uErr != QCBOR_ERR_BAD_BREAK) { - return 300 + (int32_t)uErr; + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_TAGS_DISABLED) { + return 1002; } +#endif /*QCBOR_DISABLE_TAGS */ return 0; } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +/* + * An array of an integer and an array. The second array contains + * a bstr-wrapped map. + * + * [7, [h'A36D6669... (see next lines) 73']] + * + * {"first integer": 42, + * "an array of two strings": ["string1", "string2"], + * "map in a map": + * { "bytes 1": h'78787878', + * "bytes 2": h'79797979', + * "another int": 98, + * "text 2": "lies, damn lies and statistics" + * } + * } + */ +static const uint8_t pValidWrappedMapEncoded[] = { + 0x82, 0x07, 0x81, 0x58, 0x97, + 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, + 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, + 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, + 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, + 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, + 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, + 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, + 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73 +}; -static const uint8_t spTaggedTypes[] = { - 0xb2, - - // Date string - 0x00, - 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, - 0x31, 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, - 0x32, 0x5A, - - 0x01, - 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, 0x31, - 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, 0x32, - 0x5A, - - // Bignum - 10, - 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x10, - - 11, - 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x10, - - // URL - 20, - 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, - 0x63, 0x62, 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, - - 21, - 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x62, - 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, - - // B64 - 0x18, 0x1e, - 0xd8, 0x22, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, - 0x31, 0x63, 0x6D, 0x55, 0x75, - - 0x18, 0x1f, - 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, - 0x6D, 0x55, 0x75, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // B64URL - 0x18, 0x28, - 0xd8, 0x21, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, - 0x31, 0x63, 0x6D, 0x55, 0x75, +/* As above, but the arrays are indefinite length */ +static const uint8_t pValidIndefWrappedMapEncoded[] = { + 0x9f, 0x07, 0x9f, 0x58, 0x97, + 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, + 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, + 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, + 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, + 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, + 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, + 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, + 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, + 0xff, 0xff +}; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - 0x18, 0x29, - 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, - 0x6D, 0x55, 0x75, +static const uint8_t pWithEmptyMap[] = {0x82, 0x18, 0x64, 0xa0}; - // Regex - 0x18, 0x32, - 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, - 0x6B, - 0x18, 0x33, - 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, 0x6B, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +static const uint8_t pWithEmptyMapInDef[] = {0x9f, 0x18, 0x64, 0xbf, 0xff, 0xff}; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - // MIME - 0x18, 0x3c, - 0xd8, 0x24, 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, - 0x0A, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS +/* + * An array of one that contains a byte string that is an indefinite + * length string that CBOR wraps an array of three numbers [42, 43, + * 44]. The byte string is an implicit tag 24. + * + * [ + * (_ h'83', h'18', h'2A182B', h'182C') + * ] + */ +static const uint8_t pWrappedByIndefiniteLength[] = { + 0x81, + 0x5f, + 0x41, 0x83, + 0x41, 0x18, + 0x43, 0x2A, 0x18, 0x2B, + 0x42, 0x18, 0x2C, + 0xff +}; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - 0x18, 0x3d, - 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, +#endif - 0x18, 0x3e, - 0xd9, 0x01, 0x01, 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, - 0x30, 0x0A, +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +int32_t PeekAndRewindTest(void) +{ + QCBORItem Item; + QCBORError nCBORError; + QCBORDecodeContext DCtx; - 0x18, 0x3f, - 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, + // Improvement: rework this test to use only integer labels. - // UUID - 0x18, 0x46, - 0xd8, 0x25, 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, - 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - 0x18, 0x47, - 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, - 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32 -}; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 100+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 200; + } -int32_t DecodeTaggedTypeTests(void) -{ - QCBORDecodeContext DC; - QCBORError uErr; + QCBORDecode_VPeekNext(&DCtx, &Item); + if((nCBORError = QCBORDecode_GetError(&DCtx))) { + return 150+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 250; + } - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedTypes), 0); + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 300; + } - UsefulBufC String; - bool bNeg; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 400 + (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 500; + } - QCBORDecode_EnterMap(&DC, NULL); - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_TAG, &String); - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); - if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { - return 1; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; } - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 2; + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 600; } - QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 3; + + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 900 + (int32_t)nCBORError; } - QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); - QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 4; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 1000; } - QCBORDecode_GetDateStringInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 5; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 1100 + (int32_t)nCBORError; } - QCBORDecode_GetBignumInMapN(&DC, 10, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bNeg != false) { - return 10; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 1200; } - QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bNeg != true) { - return 11; + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 1300 + (int32_t)nCBORError; } - QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 12; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 1400; } - QCBORDecode_GetBignumInMapN(&DC, 14, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 13; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 1500 + (int32_t)nCBORError; } - QCBORDecode_GetBignumInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 14; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 1600; } - QCBORDecode_GetURIInMapN(&DC, 20, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 20; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 1700 + (int32_t)nCBORError; } - QCBORDecode_GetURIInMapN(&DC, 21, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 21; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 1800; } - QCBORDecode_GetURIInMapN(&DC, 22, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 22; + + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return (int32_t)nCBORError; } - QCBORDecode_GetURIInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 23; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 1900; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 2000; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - QCBORDecode_GetB64InMapN(&DC, 30, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 30; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2100 + (int32_t)nCBORError; } -#endif - QCBORDecode_GetB64InMapN(&DC, 31, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 31; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "map in a map") || + Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 4) { + return 2100; } - QCBORDecode_GetB64InMapN(&DC, 32, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 32; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2200 + (int32_t)nCBORError; } - QCBORDecode_GetB64InMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 33; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "xxxx")) { + return 2300; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - QCBORDecode_GetB64URLInMapN(&DC, 40, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 40; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 2400 + (int32_t)nCBORError; } -#endif - QCBORDecode_GetB64URLInMapN(&DC, 41, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 41; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 2") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "yyyy")) { + return 2500; } - QCBORDecode_GetB64URLInMapN(&DC, 42, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 42; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2600 + (int32_t)nCBORError; } - QCBORDecode_GetB64URLInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 43; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 2") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "yyyy")) { + return 2700; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - QCBORDecode_GetRegexInMapN(&DC, 50, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 50; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2800 + (int32_t)nCBORError; } -#endif - QCBORDecode_GetRegexInMapN(&DC, 51, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 51; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "another int") || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) { + return 2900; } - QCBORDecode_GetRegexInMapN(&DC, 52, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 52; + + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 3000 + (int32_t)nCBORError; } - QCBORDecode_GetRegexInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 53; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { + return 3100; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - // MIME - bool bIsNot7Bit; - QCBORDecode_GetMIMEMessageInMapN(&DC, 60, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == true) { - return 60; - } - QCBORDecode_GetMIMEMessageInMapN(&DC, 61, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == true) { - return 61; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 3200 + (int32_t)nCBORError; } - QCBORDecode_GetMIMEMessageInMapN(&DC, 62, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == false) { - return 62; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { + return 3300; } - QCBORDecode_GetMIMEMessageInMapN(&DC, 63, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == false) { - return 63; + + nCBORError = QCBORDecode_PeekNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 3300 + (int32_t)nCBORError; } - QCBORDecode_GetMIMEMessageInMapN(&DC, 64, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 64; + + QCBORDecode_VPeekNext(&DCtx, &Item); + nCBORError = QCBORDecode_GetError(&DCtx); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 3400 + (int32_t)nCBORError; } - QCBORDecode_GetMIMEMessageInMapSZ(&DC, "zzz", QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 65; + + QCBORDecode_VPeekNext(&DCtx, &Item); + nCBORError = QCBORDecode_GetError(&DCtx); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 3500 + (int32_t)nCBORError; } - QCBORDecode_GetBinaryUUIDInMapN(&DC, 70, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 70; - } -#endif /* #ifndef QCBOR_DISABLE_UNCOMMON_TAGS */ + // Rewind to top level after entering several maps + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) { + return 400; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4000+(int32_t)nCBORError; + } + + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 4100; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4100+(int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 4200; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4200+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 4300; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4300+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 4400; + } + + QCBORDecode_Rewind(&DCtx); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4400+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) { + return 4500; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 4600; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 4700; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 4800; + } - QCBORDecode_GetBinaryUUIDInMapN(&DC, 71, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 71; - } - QCBORDecode_GetBinaryUUIDInMapN(&DC, 72, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 72; - } - QCBORDecode_GetBinaryUUIDInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 73; - } + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4900+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 5000; + } - // Improvement: add some more error test cases - QCBORDecode_ExitMap(&DC); + // Rewind an entered map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - uErr = QCBORDecode_Finish(&DC); - if(uErr != QCBOR_SUCCESS) { - return 100; + QCBORDecode_EnterMap(&DCtx, NULL); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5100+(int32_t)nCBORError; } - return 0; -} + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 5200; + } + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5200+(int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return -5300; + } + QCBORDecode_Rewind(&DCtx); + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5300+(int32_t)nCBORError; + } -/* - [ - "aaaaaaaaaa", - {} - ] - */ -static const uint8_t spTooLarge1[] = { - 0x9f, - 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0xa0, - 0xff -}; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 5400; + } -/* - [ - { - 0: "aaaaaaaaaa" - } - ] - */ -static const uint8_t spTooLarge2[] = { - 0x9f, - 0xa1, - 0x00, - 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0xff -}; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5400+(int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 5500; + } -/* - h'A1006A61616161616161616161' - { - 0: "aaaaaaaaaa" - } - */ -static const uint8_t spTooLarge3[] = { - 0x4d, - 0xa1, - 0x00, - 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, -}; + // Rewind and entered array inside an entered map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); -int32_t TooLargeInputTest(void) -{ - QCBORDecodeContext DC; - QCBORError uErr; - UsefulBufC String; + QCBORDecode_EnterMap(&DCtx, NULL); - // These tests require a build with QCBOR_MAX_DECODE_INPUT_SIZE set - // to 10 There's not really any way to test this error - // condition. The error condition is not complex, so setting - // QCBOR_MAX_DECODE_INPUT_SIZE gives an OK test. + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - // The input CBOR is only too large because the - // QCBOR_MAX_DECODE_INPUT_SIZE is 10. - // - // This test is disabled for the normal test runs because of the - // special build requirement. + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5600+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 5700; + } + QCBORDecode_Rewind(&DCtx); - // Tests the start of a map being too large - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge1), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_GetTextString(&DC, &String); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_SUCCESS) { - return 1; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5700+(int32_t)nCBORError; } - QCBORDecode_EnterMap(&DC, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { - return 2; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 5800; } - // Tests the end of a map being too large - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge2), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_EnterMap(&DC, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_SUCCESS) { - return 3; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; } - QCBORDecode_ExitMap(&DC); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { - return 4; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 5900; } - // Tests the entire input CBOR being too large when processing bstr wrapping - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge3), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { - return 5; + QCBORDecode_Rewind(&DCtx); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5900+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 6000; } - return 0; -} + // Rewind a byte string inside an array inside an array + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidWrappedMapEncoded), 0); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + QCBORDecode_EnterArray(&DCtx, NULL); -/* - An array of three map entries - 1) Indefinite length string label for indefinite lenght byte string - 2) Indefinite length string label for an integer - 3) Indefinite length string label for an indefinite-length negative big num - */ -static const uint8_t spMapWithIndefLenStrings[] = { - 0xa3, - 0x7f, 0x61, 'l', 0x64, 'a', 'b', 'e', 'l' , 0x61, '1', 0xff, - 0x5f, 0x42, 0x01, 0x02, 0x43, 0x03, 0x04, 0x05, 0xff, - 0x7f, 0x62, 'd', 'y', 0x61, 'm', 0x61, 'o', 0xff, - 0x03, - 0x7f, 0x62, 'l', 'a', 0x63, 'b', 'e', 'l', 0x61, '2', 0xff, - 0xc3, - 0x5f, 0x42, 0x00, 0x01, 0x42, 0x00, 0x01, 0x41, 0x01, 0xff, -}; + uint64_t i; + QCBORDecode_GetUInt64(&DCtx, &i); -int32_t SpiffyIndefiniteLengthStringsTests(void) -{ - QCBORDecodeContext DCtx; + QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapWithIndefLenStrings), - QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + if(QCBORDecode_GetError(&DCtx)) { + return 6100; + } - UsefulBuf_MAKE_STACK_UB(StringBuf, 200); - QCBORDecode_SetMemPool(&DCtx, StringBuf, false); + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6200; + } - UsefulBufC ByteString; - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetByteStringInMapSZ(&DCtx, "label1", &ByteString); + QCBORDecode_Rewind(&DCtx); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 6300+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6400; + } + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + // Rewind a byte string inside an indefinite-length array inside + // indefinite-length array + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidIndefWrappedMapEncoded), 0); + + QCBORDecode_EnterArray(&DCtx, NULL); -#ifndef QCBOR_DISABLE_TAGS - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 1; - } + QCBORDecode_GetUInt64(&DCtx, &i); - const uint8_t pExectedBytes[] = {0x01, 0x02, 0x03, 0x04, 0x05}; - if(UsefulBuf_Compare(ByteString, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExectedBytes))) { - return 2; + QCBORDecode_EnterArray(&DCtx, NULL); + + QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + if(QCBORDecode_GetError(&DCtx)) { + return 6500; } - uint64_t uInt; - QCBORDecode_GetUInt64InMapSZ(&DCtx, "dymo", &uInt); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 3; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 6600+(int32_t)nCBORError; } - if(uInt != 3) { - return 4; + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6700; } -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - double uDouble; - QCBORDecode_GetDoubleConvertAllInMapSZ(&DCtx, - "label2", - 0xff, - &uDouble); + QCBORDecode_Rewind(&DCtx); -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 5; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 6800+(int32_t)nCBORError; } - if(uDouble != -16777474) { - return 6; + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6900; } -#else /* QCBOR_DISABLE_FLOAT_HW_USE */ - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HW_FLOAT_DISABLED) { - return 7; +#endif + + // Rewind an empty map + // [100, {}] + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMap), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7010; } -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + QCBORDecode_EnterMap(&DCtx, NULL); + /* Do it 5 times to be sure multiple rewinds work */ + for(int n = 0; n < 5; n++) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 7000 + n; + } + QCBORDecode_Rewind(&DCtx); + } QCBORDecode_ExitMap(&DCtx); - - if(QCBORDecode_Finish(&DCtx)) { - return 99; + QCBORDecode_Rewind(&DCtx); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7010; + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_Rewind(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + i = 9; + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7020; + } + if(QCBORDecode_GetError(&DCtx)){ + return 7030; } -#else /* QCBOR_DISABLE_TAGS */ - /* The big num in the input is a CBOR tag and you can't do - * map lookups in a map with a tag so this test does very little - * when tags are disabled. That is OK, the test coverage is still - * good when they are not. - */ - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_TAGS_DISABLED) { - return 1002; + // Rewind an empty indefinite length map +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMapInDef), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7810; } -#endif /*QCBOR_DISABLE_TAGS */ + QCBORDecode_EnterMap(&DCtx, NULL); - return 0; -} -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + /* Do it 5 times to be sure multiple rewinds work */ + for(int n = 0; n < 5; n++) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 7800 + n; + } + QCBORDecode_Rewind(&DCtx); + } + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_Rewind(&DCtx); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7810; + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_Rewind(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + i = 9; + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7820; + } + if(QCBORDecode_GetError(&DCtx)){ + return 7830; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + // Rewind an indefnite length byte-string wrapped sequence +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWrappedByIndefiniteLength), + 0); + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); -/* - * An array of an integer and an array. The second array contains - * a bstr-wrapped map. - * - * [7, [h'A36D6669... (see next lines) 73']] - * - * {"first integer": 42, - * "an array of two strings": ["string1", "string2"], - * "map in a map": - * { "bytes 1": h'78787878', - * "bytes 2": h'79797979', - * "another int": 98, - * "text 2": "lies, damn lies and statistics" - * } - * } - */ + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) { + return 7300; + } -static const uint8_t pValidWrappedMapEncoded[] = { - 0x82, 0x07, 0x81, 0x58, 0x97, - 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, - 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, - 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, - 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, - 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, - 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, - 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, - 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73 -}; + /* + Improvement: Fix QCBORDecode_EnterBstrWrapped() so it can work on + allocated strings. This is a fairly big job because of all the + UsefulBuf internal book keeping that needs tweaking. + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 42) { + return 7110; + } + QCBORDecode_Rewind(&DCtx); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 42) { + return 7220; + } + */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ -/* As above, but the arrays are indefinite length */ -static const uint8_t pValidIndefWrappedMapEncoded[] = { - 0x9f, 0x07, 0x9f, 0x58, 0x97, - 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, - 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, - 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, - 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, - 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, - 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, - 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, - 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73, - 0xff, 0xff -}; -#endif + // Rewind an indefnite length byte-string wrapped sequence -static const uint8_t pWithEmptyMap[] = {0x82, 0x18, 0x64, 0xa0}; + return 0; +} -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -static const uint8_t pWithEmptyMapInDef[] = {0x9f, 0x18, 0x64, 0xbf, 0xff, 0xff}; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS -/* -An array of one that contains - a byte string that is tagged 24 which means CBOR-encoded data - the byte string is an indefinite length string - the wrapped byte string is an array of three numbers - [42, 43, 44] - -[ - 24( - (_ h'83', h'18', h'2A182B', h'182C') - ) -] - */ -static const uint8_t pWrappedByIndefiniteLength[] = { - 0x81, - 0xd8, 0x18, - 0x5f, - 0x41, 0x83, - 0x41, 0x18, - 0x43, 0x2A, 0x18, 0x2B, - 0x42, 0x18, 0x2C, - 0xff +static const uint8_t spBooleansInMap[] = +{ + 0xa1, 0x08, 0xf5 }; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - -int32_t PeekAndRewindTest(void) +static const uint8_t spBooleansInMapWrongType[] = { - QCBORItem Item; - QCBORError nCBORError; - QCBORDecodeContext DCtx; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 100+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 200; - } + 0xa1, 0x08, 0xf6 +}; - QCBORDecode_VPeekNext(&DCtx, &Item); - if((nCBORError = QCBORDecode_GetError(&DCtx))) { - return 150+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 250; - } +static const uint8_t spBooleansInMapNWF[] = +{ + 0xa1, 0x08, 0x1a +}; - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 300; - } +static const uint8_t spNullInMap[] = +{ + 0xa1, 0x08, 0xf6 +}; - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 400 + (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 500; - } +static const uint8_t spUndefinedInMap[] = +{ + 0xa1, 0x08, 0xf7 +}; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 600; - } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 900 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 1000; - } +#ifndef QCBOR_DISABLE_TAGS +static const uint8_t spTaggedSimples[] = +{ + 0xd8, 0x58, 0xd8, 0x2c, 0xd6, 0xf5, + 0xd9, 0x0f, 0xA0, 0xf7 +}; +#endif /* ! QCBOR_DISABLE_TAGS */ - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 1100 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 1200; - } +int32_t BoolTest(void) +{ + QCBORDecodeContext DCtx; + bool b; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 1300 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 1400; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetAndResetError(&DCtx) || !b) { + return 1; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 1500 + (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 1600; + QCBORDecode_GetBoolInMapN(&DCtx, 7, &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 2; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 1700 + (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 1800; + QCBORDecode_GetBoolInMapN(&DCtx, 8, &b); + if(QCBORDecode_GetAndResetError(&DCtx) || !b) { + return 3; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 1900; - } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + QCBORDecode_GetBoolInMapSZ(&DCtx, "xx", &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 4; + } + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapWrongType), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 5; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 2000; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { + return 6; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2100 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "map in a map") || - Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 4) { - return 2100; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNull(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 7; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2200 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "xxxx")) { - return 2300; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNull(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 8; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 2400 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 2") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "yyyy")) { - return 2500; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNullInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 9; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2600 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 2") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "yyyy")) { - return 2700; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNullInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 10; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2800 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "another int") || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) { - return 2900; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { + return 11; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 3000 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { - return 3100; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 12; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 3200 + (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 13; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { - return 3300; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefinedInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 14; } - nCBORError = QCBORDecode_PeekNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 3300 + (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefinedInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 15; } - QCBORDecode_VPeekNext(&DCtx, &Item); - nCBORError = QCBORDecode_GetError(&DCtx); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 3400 + (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { + return 15; } - QCBORDecode_VPeekNext(&DCtx, &Item); - nCBORError = QCBORDecode_GetError(&DCtx); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 3500 + (int32_t)nCBORError; +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedSimples), + 0); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 22) { + return 401; } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 44) { + return 402; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != 88) { + return 403; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 404; + } + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 4000) { + return 405; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != CBOR_TAG_INVALID64) { + return 406; + } + QCBORDecode_GetNull(&DCtx); /* Off the end */ + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != CBOR_TAG_INVALID64) { + return 407; + } +#endif /* ! QCBOR_DISABLE_TAGS */ + return 0; +} - // Rewind to top level after entering several maps - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) { - return 400; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4000+(int32_t)nCBORError; - } - - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 4100; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4100+(int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 4200; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4200+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 4300; - } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4300+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 4400; - } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +static const uint8_t spExpectedArray2s[] = { + 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x31, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x32}; - QCBORDecode_Rewind(&DCtx); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +static const uint8_t spExpectedArray2sIndef[] = { + 0x9f, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x31, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x32, 0xff}; +#endif - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4400+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) { - return 4500; - } +static const uint8_t spExpectedMap4[] = { + 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, + 0x31, 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x20, 0x32, 0x44, 0x79, + 0x79, 0x79, 0x79, 0x6b, 0x61, 0x6e, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x18, + 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, + 0x78, 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, + 0x64, 0x61, 0x6d, 0x6e, 0x20, 0x6c, 0x69, 0x65, + 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73}; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 4600; - } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 4700; - } +static const uint8_t spExpectedMap4Indef[] = { + 0xbf, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, + 0x31, 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x20, 0x32, 0x44, 0x79, + 0x79, 0x79, 0x79, 0x6b, 0x61, 0x6e, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x18, + 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, + 0x78, 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, + 0x64, 0x61, 0x6d, 0x6e, 0x20, 0x6c, 0x69, 0x65, + 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0xff}; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 4800; - } +/* + * [[[[[0, []]]]], 0] + */ +static const uint8_t spDefAndIndef[] = { + 0x82, + 0x9f, 0x9f, 0x9f, 0x82, 0x00, 0x9f, 0xff, 0xff, 0xff, 0xff, 0x00 +}; +#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4900+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 5000; - } +#ifndef QCBOR_DISABLE_TAGS +/* An exp / mant tag in two nested arrays */ +static const uint8_t spExpMant[] = {0x81, 0x81, 0xC4, 0x82, 0x20, 0x03}; +#endif /* !QCBOR_DISABLE_TAGS */ +#endif +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +int32_t GetMapAndArrayTest(void) +{ + QCBORDecodeContext DCtx; + size_t uPosition ; + QCBORItem Item; + UsefulBufC ReturnedEncodedCBOR; - // Rewind an entered map - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + // Improvement: rework so it can run with QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + 0); QCBORDecode_EnterMap(&DCtx, NULL); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5100+(int32_t)nCBORError; + QCBORDecode_VGetNextConsume(&DCtx, &Item); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 1; + } + if(Item.val.uCount != 2) { + return 2; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2s))) { + return 3; } if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 5200; - } + UsefulBuf_Compare(Item.label.string, UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { + return 4; + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5200+(int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return -5300; - } + uPosition = QCBORDecode_Tell(&DCtx); + + + QCBORDecode_GetMap(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 10; + } + if(Item.val.uCount != 4) { + return 11; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4))) { + return 12; + } + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, + "an array of two strings", + &Item, + &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 20; + } + if(Item.val.uCount != 2) { + return 21; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2s))) { + return 22; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 23; + } QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5300+(int32_t)nCBORError; + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetMapFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 30; + } + if(Item.val.uCount != 4) { + return 31; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4))) { + return 32; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 33; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 5400; + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 40; + } + if(UINT32_MAX != QCBORDecode_Tell(&DCtx)) { + return 41; + } + QCBORDecode_GetAndResetError(&DCtx); + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 42; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5400+(int32_t)nCBORError; + +#ifndef QCBOR_DISABLE_TAGS + UsefulBufC ExpMant = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpMant); + QCBORDecode_Init(&DCtx, ExpMant, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 200; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return 201; + } + if(!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION)) { + return 202; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 5500; + if(Item.val.uCount != 2) { + return 201; } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(ExpMant, 2))) { + return 205; + } +#endif /* !QCBOR_DISABLE_TAGS */ - // Rewind and entered array inside an entered map - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - - QCBORDecode_EnterMap(&DCtx, NULL); - - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5600+(int32_t)nCBORError; + UsefulBufC DefAndIndef = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDefAndIndef); + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 50; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 5700; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 11), 1))) { + return 51; } - QCBORDecode_Rewind(&DCtx); + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 52; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 10), 2))) { + return 53; + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5700+(int32_t)nCBORError; + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 54; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 5800; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 9), 3))) { + return 55; + } + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 56; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 8), 4))) { + return 57; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_VGetNextConsume(&DCtx, &Item); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 58; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 5900; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 8), 6))) { + return 59; } - QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5900+(int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), + 0); + + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_VGetNextConsume(&DCtx, &Item); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 60; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 6000; + if(Item.val.uCount != UINT16_MAX) { + return 61; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2sIndef))) { + return 62; } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { + return 63; + } - // Rewind a byte string inside an array inside an array - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidWrappedMapEncoded), 0); + uPosition = QCBORDecode_Tell(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - uint64_t i; - QCBORDecode_GetUInt64(&DCtx, &i); + QCBORDecode_GetMap(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 70; + } + if(Item.val.uCount != UINT16_MAX) { + return 71; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4Indef))) { + return 72; + } - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, + "an array of two strings", + &Item, + &ReturnedEncodedCBOR); if(QCBORDecode_GetError(&DCtx)) { - return 6100; + return 80; } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if(Item.val.uCount != UINT16_MAX) { + return 81; } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6200; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2sIndef))) { + return 82; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 83; } QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 6300+(int32_t)nCBORError; + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetMapFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 90; } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6400; + if(Item.val.uCount != UINT16_MAX) { + return 91; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4Indef))) { + return 92; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 93; } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // Rewind a byte string inside an indefinite-length array inside - // indefinite-length array + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 100; + } + if(UINT32_MAX != QCBORDecode_Tell(&DCtx)) { + return 101; + } + QCBORDecode_GetAndResetError(&DCtx); + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 102; + } +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidIndefWrappedMapEncoded), 0); + return 0; +} +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - QCBORDecode_EnterArray(&DCtx, NULL); + +int32_t +ErrorHandlingTests(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uError; + int64_t integer; - QCBORDecode_GetUInt64(&DCtx, &i); + /* Test QCBORDecode_SetError() */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_SetError(&DCtx, QCBOR_ERR_FIRST_USER_DEFINED); - QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - if(QCBORDecode_GetError(&DCtx)) { - return 6500; - } + QCBORDecode_VGetNext(&DCtx, &Item); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 6600+(int32_t)nCBORError; + uError = QCBORDecode_GetError(&DCtx); + + if(uError != QCBOR_ERR_FIRST_USER_DEFINED) { + return -1; } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6700; + + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_NONE) { + return -2; } - QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 6800+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6900; + /* Test data type returned from previous error */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_GetInt64(&DCtx, &integer); + uError = QCBORDecode_GetError(&DCtx); + if(uError != QCBOR_ERR_UNEXPECTED_TYPE) { + return -3; } -#endif - // Rewind an empty map - // [100, {}] - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMap), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7010; + QCBORDecode_VGetNext(&DCtx, &Item); + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_NONE) { + return -2; } - QCBORDecode_EnterMap(&DCtx, NULL); - - /* Do it 5 times to be sure multiple rewinds work */ - for(int n = 0; n < 5; n++) { - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 7000 + n; - } - QCBORDecode_Rewind(&DCtx); + uError = QCBORDecode_GetError(&DCtx); + if(uError != QCBOR_ERR_UNEXPECTED_TYPE) { + return -3; } - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7010; + + + /* Test error classification functions */ + + if(!QCBORDecode_IsUnrecoverableError(QCBOR_ERR_INDEFINITE_STRING_CHUNK)) { + return -10; } - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - i = 9; - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7020; + if(QCBORDecode_IsUnrecoverableError(QCBOR_SUCCESS)) { + return -11; } - if(QCBORDecode_GetError(&DCtx)){ - return 7030; + if(!QCBORDecode_IsUnrecoverableError(QCBOR_ERR_INDEFINITE_STRING_CHUNK)) { + return -12; } - - // Rewind an empty indefinite length map -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMapInDef), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7810; + if(QCBORDecode_IsUnrecoverableError(QCBOR_ERR_DUPLICATE_LABEL)) { + return -13; } - QCBORDecode_EnterMap(&DCtx, NULL); - /* Do it 5 times to be sure multiple rewinds work */ - for(int n = 0; n < 5; n++) { - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 7800 + n; - } - QCBORDecode_Rewind(&DCtx); + if(!QCBORDecode_IsNotWellFormedError(QCBOR_ERR_BAD_TYPE_7)) { + return -20; } - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7810; + if(!QCBORDecode_IsNotWellFormedError(QCBOR_ERR_BAD_BREAK)) { + return -21; } - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - i = 9; - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7820; + if(QCBORDecode_IsNotWellFormedError(QCBOR_SUCCESS)) { + return -22; } - if(QCBORDecode_GetError(&DCtx)){ - return 7830; + if(QCBORDecode_IsNotWellFormedError(QCBOR_ERR_ARRAY_DECODE_TOO_LONG)) { + return -23; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - // Rewind an indefnite length byte-string wrapped sequence -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - // TODO: rewrite this test to not use tags - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWrappedByIndefiniteLength), - 0); - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORDecode_SetMemPool(&DCtx, Pool, 0); + /* Test error strings */ + const char *szErrString; - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL); -#ifndef QCBOR_DISABLE_TAGS - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INPUT_TOO_LARGE) { - /* TODO: This is what happens when trying to enter - * indefinite-length byte string wrapped CBOR. Tolerate for - * now. Eventually it needs to be fixed so this works, but that - * is not simple. - */ - return 7300; + szErrString = qcbor_err_to_str(QCBOR_ERR_ARRAY_DECODE_TOO_LONG); + if(szErrString == NULL) { + return -100; + } + if(strcmp(szErrString, "QCBOR_ERR_ARRAY_DECODE_TOO_LONG")) { + return -101; } - /* - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 42) { - return 7110; + szErrString = qcbor_err_to_str(QCBOR_SUCCESS); + if(szErrString == NULL) { + return -102; + } + if(strcmp(szErrString, "QCBOR_SUCCESS")) { + return -103; } - QCBORDecode_Rewind(&DCtx); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 42) { - return 7220; - }*/ -#else /* QCBOR_DISABLE_TAGS */ - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_TAGS_DISABLED) { - return 7301; + szErrString = qcbor_err_to_str(100); + if(szErrString == NULL) { + return -104; + } + if(strcmp(szErrString, "Unidentified QCBOR error")) { + return -105; } -#endif /* QCBOR_DISABLE_TAGS */ -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + szErrString = qcbor_err_to_str(200); + if(szErrString == NULL) { + return -106; + } + if(strcmp(szErrString, "USER_DEFINED_200")) { + return -107; + } + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); - // Rewind an indefnite length byte-string wrapped sequence + UsefulBufC Xx = QCBORDecode_RetrieveUndecodedInput(&DCtx); + if(Xx.ptr != pValidMapEncoded) { + return -200; + } + if(Xx.len != sizeof(pValidMapEncoded)) { + return -201; + } return 0; } - - -static const uint8_t spBooleansInMap[] = -{ - 0xa1, 0x08, 0xf5 -}; - -static const uint8_t spBooleansInMapWrongType[] = -{ - 0xa1, 0x08, 0xf6 -}; - -static const uint8_t spBooleansInMapNWF[] = -{ - 0xa1, 0x08, 0x1a -}; - -static const uint8_t spNullInMap[] = -{ - 0xa1, 0x08, 0xf6 -}; - -static const uint8_t spUndefinedInMap[] = -{ - 0xa1, 0x08, 0xf7 -}; - - -int32_t BoolTest(void) +int32_t TellTests(void) { QCBORDecodeContext DCtx; - bool b; + QCBORItem Item; + uint32_t uPosition; + int nIndex; + int64_t nDecodedInt; + // Improvement: rewrite so this can run with only integer labels + static const uint32_t aPos[] = + {0, 1, 17, 42, 50, 58, 72, 85, 98, 112, 151}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetBool(&DCtx, &b); - if(QCBORDecode_GetAndResetError(&DCtx) || !b) { - return 1; - } + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aPos[nIndex]) { + return nIndex; + } - QCBORDecode_GetBoolInMapN(&DCtx, 7, &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 2; - } + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } - QCBORDecode_GetBoolInMapN(&DCtx, 8, &b); - if(QCBORDecode_GetAndResetError(&DCtx) || !b) { - return 3; + QCBORDecode_VGetNext(&DCtx, &Item); } - - QCBORDecode_GetBoolInMapSZ(&DCtx, "xx", &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 4; - } - +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + static const uint32_t aPosIndef[] = + {0, 1, 17, 42, 50, 59, 73, 86, 99, 113, 154}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapWrongType), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetBool(&DCtx, &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 5; + + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aPosIndef[nIndex]) { + return nIndex + 100; + } + + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } + + QCBORDecode_VGetNext(&DCtx, &Item); } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + /* Next, some tests with entered maps and arrays */ QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetBool(&DCtx, &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { - return 6; + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 1001; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 1002; + } + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + if(QCBORDecode_Tell(&DCtx) != 72) { + return 1003; } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 1004; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 72) { + return 1005; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 85) { + return 1006; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 1007; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 85) { + return 1008; + } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNull(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 7; + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 151) { + return 1009; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 1010; } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + /* Next, some tests with entered maps and arrays */ QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNull(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 8; + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 2000; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 2001; + } + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + if(QCBORDecode_Tell(&DCtx) != 73) { + return 2002; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNullInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 9; + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 2003; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 73) { + return 2004; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 86) { + return 2005; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 2006; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 86) { + return 2007; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNullInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 10; + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 154) { + return 2008; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2010; } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + + /* Error state test */ QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { - return 11; + /* Cause an error */ + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 3000; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_MAP_NOT_ENTERED) { + return 3001; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 12; + + /* Empties tests */ + const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 4000; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_SUCCESS) { + return 4008; + } + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4001; + } + if(QCBORDecode_Tell(&DCtx) != 1) { + return 4002; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4003; + } + if(QCBORDecode_Tell(&DCtx) != 1) { + return 4004; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4005; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4010; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 13; +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + const uint8_t pMinimalIndefCBOR[] = {0xbf, 0xff}; // One empty map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalIndefCBOR),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 4100; + } + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4101; + } + if(QCBORDecode_Tell(&DCtx) != 2) { + return 4102; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4103; + } + if(QCBORDecode_Tell(&DCtx) != 2) { + return 4104; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4005; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4110; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + /* Test on a CBOR sequence */ + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 5000; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5001; } + if(QCBORDecode_Tell(&DCtx) != 11) { + return 5002; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5003; + } + if(QCBORDecode_Tell(&DCtx) != 12) { + return 5004; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5005; + } + if(QCBORDecode_Tell(&DCtx) != 17) { + return 5006; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5007; + } + if(QCBORDecode_Tell(&DCtx) != 20) { + return 5008; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 5010; + } + QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefinedInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 14; + QCBORDecode_EnterMap(&DCtx, &Item); + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + if(QCBORDecode_Tell(&DCtx) != 42) { + return 6001; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 50) { + return 6002; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 58) { + return 6008; + } + QCBORDecode_VGetNext(&DCtx, &Item); + (void)QCBORDecode_GetAndResetError(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 58) { + return 6003; + } + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 58) { + return 6004; } + static const uint32_t aEmptiesPos[] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefinedInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 15; + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aEmptiesPos[nIndex]) { + return nIndex + 200; + } + + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } + + QCBORDecode_VGetNext(&DCtx, &Item); } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + static const uint32_t aIndefEmptiesPos[] = + {0, 1, 2, 4, 5, 7, 8, 10, 12, 13, 16, 19, 25}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmptiesIndef), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { - return 15; + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aIndefEmptiesPos[nIndex]) { + return nIndex + 300; + } + + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } + + QCBORDecode_VGetNext(&DCtx, &Item); } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + return 0; } diff --git a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h index 11fdc94bca4a..a08a3afda645 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h +++ b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h @@ -126,7 +126,7 @@ int32_t ParseMapAsArrayTest(void); /* Test parsing of some simple values like true, false, null... */ -int32_t ParseSimpleTest(void); +int32_t SimpleValueDecodeTests(void); /* @@ -318,4 +318,17 @@ Test GitHub issue #134: decode an indefinite-length string with a zero-length fi */ int32_t CBORTestIssue134(void); + + +int32_t ErrorHandlingTests(void); + + +/* + * Test QCBORDecode_GetArray and QCBORDecode_GetMap + */ +int32_t GetMapAndArrayTest(void); + +int32_t TellTests(void); + + #endif /* defined(__QCBOR__qcbort_decode_tests__) */ diff --git a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c index 6e569cac82fb..14bcc63d0795 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c +++ b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c @@ -1,6 +1,6 @@ /*============================================================================== Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2021, Laurence Lundblade. + Copyright (c) 2018-2024, Laurence Lundblade. Copyright (c) 2022, Arm Limited. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -73,11 +73,11 @@ static void printencoded(const uint8_t *pEncoded, size_t nLen) static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) { size_t i; for(i = 0; i < U1.len; i++) { - if(((uint8_t *)U1.ptr)[i] != ((uint8_t *)U2.ptr)[i]) { - printf("Position: %d Actual: 0x%x Expected: 0x%x\n", + if(((const uint8_t *)U1.ptr)[i] != ((const uint8_t *)U2.ptr)[i]) { + printf("Position: %u Actual: 0x%x Expected: 0x%x\n", (uint32_t)i, - ((uint8_t *)U1.ptr)[i], - ((uint8_t *)U2.ptr)[i]); + ((const uint8_t *)U1.ptr)[i], + ((const uint8_t *)U2.ptr)[i]); return 1; } } @@ -180,6 +180,11 @@ int32_t BasicEncodeTest(void) } + UsefulBuf Tmp = QCBOREncode_RetrieveOutputStorage(&EC); + if(Tmp.ptr != spBigBuf && Tmp.len != sizeof(spBigBuf)) { + return -111; + } + // Make another encoded message with the CBOR from the previous // put into this one UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20); @@ -196,6 +201,8 @@ int32_t BasicEncodeTest(void) if(QCBOREncode_Finish(&EC, &Encoded2)) { return -5; } + + /* [ // 0 1:3 451, // 1 1:2 @@ -516,6 +523,9 @@ this is the attachment text\n\ static void AddAll(QCBOREncodeContext *pECtx) { + /* This calls a mix of deprecated and non-deprecated to test both. + * Sometimes only deprecated because the deprecated calls the + * non-deprecated */ QCBOREncode_OpenArray(pECtx); /* Some ints that are tagged and have strings preceeding them @@ -543,7 +553,7 @@ static void AddAll(QCBOREncodeContext *pECtx) /* Epoch date with labels */ QCBOREncode_OpenMap(pECtx); QCBOREncode_AddDateEpochToMap(pECtx, "LongLiveDenisRitchie", 1400000000); - QCBOREncode_AddDateEpochToMap(pECtx, "time()", 1477263730); + QCBOREncode_AddTDateEpochToMapSZ(pECtx, "time()", QCBOR_ENCODE_AS_TAG, 1477263730); QCBOREncode_AddDateEpochToMapN(pECtx, -1969, 1477263222); QCBOREncode_CloseMap(pECtx); @@ -556,7 +566,7 @@ static void AddAll(QCBOREncodeContext *pECtx) QCBOREncode_AddTag(pECtx, 100000); QCBOREncode_AddBytes(pECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1})); QCBOREncode_AddBytesToMap(pECtx, "empty", NULLUsefulBufC); // Empty string - QCBOREncode_AddBytesToMap(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3})); + QCBOREncode_AddBytesToMapSZ(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3})); QCBOREncode_AddBytesToMapN(pECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4})); QCBOREncode_CloseMap(pECtx); @@ -575,7 +585,7 @@ static void AddAll(QCBOREncodeContext *pECtx) /* text blobs in maps */ QCBOREncode_OpenMap(pECtx); QCBOREncode_AddTextToMap(pECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo")); - QCBOREncode_AddTextToMap(pECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar")); + QCBOREncode_AddTextToMapSZ(pECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar")); QCBOREncode_AddSZString(pECtx, "()()()"); QCBOREncode_AddTag(pECtx, 1000); QCBOREncode_AddSZString(pECtx, "rab rab oof"); @@ -602,13 +612,13 @@ static void AddAll(QCBOREncodeContext *pECtx) QCBOREncode_CloseMap(pECtx); /* true / false ... */ - QCBOREncode_AddSimple(pECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddUndef(pECtx); QCBOREncode_OpenMap(pECtx); QCBOREncode_AddSZString(pECtx, "dare"); QCBOREncode_AddTag(pECtx, 66); QCBOREncode_AddBool(pECtx, true); QCBOREncode_AddBoolToMap(pECtx, "uu", false); - QCBOREncode_AddSimpleToMapN(pECtx, 737634, CBOR_SIMPLEV_NULL); + QCBOREncode_AddNULLToMapN(pECtx, 737634); QCBOREncode_CloseMap(pECtx); /* opening an array */ @@ -671,7 +681,7 @@ static void AddAll(QCBOREncodeContext *pECtx) QCBOREncode_AddBool(pECtx, true); QCBOREncode_AddBool(pECtx, false); QCBOREncode_OpenMap(pECtx); - QCBOREncode_AddBoolToMap(pECtx, "George is the man", true); + QCBOREncode_AddBoolToMapSZ(pECtx, "George is the man", true); QCBOREncode_AddBoolToMapN(pECtx, 010101, true); QCBOREncode_CloseMap(pECtx); @@ -912,14 +922,14 @@ int32_t SimpleValuesTest1(void) QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); QCBOREncode_OpenArray(&ECtx); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddBool(&ECtx, true); + QCBOREncode_AddBool(&ECtx, false); + QCBOREncode_AddNULL(&ECtx); + QCBOREncode_AddUndef(&ECtx); QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddUndefToMapSZ(&ECtx, "UNDef"); QCBOREncode_CloseMap(&ECtx); QCBOREncode_CloseArray(&ECtx); @@ -935,6 +945,7 @@ int32_t SimpleValuesTest1(void) return(nReturn); } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS /* 9F # array(5) F5 # primitive(21) @@ -951,36 +962,61 @@ int32_t SimpleValuesTest1(void) static const uint8_t spExpectedEncodedSimpleIndefiniteLength[] = { 0x9f, 0xf5, 0xf4, 0xf6, 0xf7, 0xbf, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7, 0xff, 0xff}; -int32_t SimpleValuesIndefiniteLengthTest1(void) +int32_t IndefiniteLengthTest(void) { QCBOREncodeContext ECtx; - int nReturn = 0; QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); QCBOREncode_OpenArrayIndefiniteLength(&ECtx); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddBool(&ECtx, true); + QCBOREncode_AddBool(&ECtx, false); + QCBOREncode_AddNULL(&ECtx); + QCBOREncode_AddUndef(&ECtx); QCBOREncode_OpenMapIndefiniteLength(&ECtx); - QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddUndefToMap(&ECtx, "UNDef"); QCBOREncode_CloseMapIndefiniteLength(&ECtx); QCBOREncode_CloseArrayIndefiniteLength(&ECtx); UsefulBufC ECBOR; if(QCBOREncode_Finish(&ECtx, &ECBOR)) { - nReturn = -1; + return -1; } - if(CheckResults(ECBOR, spExpectedEncodedSimpleIndefiniteLength)) + if(CheckResults(ECBOR, spExpectedEncodedSimpleIndefiniteLength)) { return -2; + } - return(nReturn); + +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArrayIndefiniteLength(&ECtx); + QCBOREncode_CloseArray(&ECtx); + if(QCBOREncode_GetErrorState(&ECtx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -3; + } + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&ECtx); + QCBOREncode_CloseArrayIndefiniteLength(&ECtx); + if(QCBOREncode_GetErrorState(&ECtx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -3; + } + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArrayIndefiniteLength(&ECtx); + QCBOREncode_CloseMapIndefiniteLength(&ECtx); + if(QCBOREncode_GetErrorState(&ECtx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -3; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + return 0; } +#endif /* A5 # map(5) @@ -1155,32 +1191,32 @@ int32_t EncodeLengthThirtyoneTest(void) QCBOREncode_OpenMap(&ECtx); // add array with 31 items - QCBOREncode_OpenArrayInMap(&ECtx, "arr"); + QCBOREncode_OpenArrayInMapSZ(&ECtx, "arr"); for (size_t ix = 0; ix < 31; ix++) { QCBOREncode_AddInt64(&ECtx, (int64_t)ix); } QCBOREncode_CloseArray(&ECtx); // add map with 31 items - QCBOREncode_OpenMapInMap(&ECtx, "map"); + QCBOREncode_OpenMapInMapSZ(&ECtx, "map"); for (int ix = 0; ix < 31; ix++) { // make sure we have unique keys in the map (a-z then follow by A-Z) int c = 'a'; if (ix < 26) c = c + ix; else c = 'A' + (ix - 26); char buffer[2] = { (char)c, 0 }; - QCBOREncode_AddInt64ToMap(&ECtx, buffer, ix); + QCBOREncode_AddInt64ToMapSZ(&ECtx, buffer, ix); } QCBOREncode_CloseMap(&ECtx); // add -31 and +31 - QCBOREncode_AddInt64ToMap(&ECtx, "min31", -31); - QCBOREncode_AddInt64ToMap(&ECtx, "plus31", 31); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "min31", -31); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "plus31", 31); // add string with length 31 const char *str = "testtesttesttesttesttestqcbor11"; UsefulBufC str_b = { str, 31 }; - QCBOREncode_AddTextToMap(&ECtx, "str", str_b); + QCBOREncode_AddTextToMapSZ(&ECtx, "str", str_b); QCBOREncode_CloseMap(&ECtx); @@ -1259,9 +1295,10 @@ int32_t EncodeDateTest(void) QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddDateStringToMap(&ECtx, - "Sample Date from RFC 3339", - "1985-04-12T23:20:50.52Z"); + QCBOREncode_AddTDateStringToMapSZ(&ECtx, + "Sample Date from RFC 3339", + QCBOR_ENCODE_AS_TAG, + "1985-04-12T23:20:50.52Z"); QCBOREncode_AddDateEpochToMap(&ECtx, "SD", 999); QCBOREncode_AddTDaysStringToMapSZ(&ECtx, "Sample Date from RFC 8943", @@ -1501,16 +1538,16 @@ static int32_t CreateMap(uint8_t **pEncoded, size_t *pEncodedLen) do { QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddInt64ToMap(&ECtx, "first integer", 42); - QCBOREncode_OpenArrayInMap(&ECtx, "an array of two strings"); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "first integer", 42); + QCBOREncode_OpenArrayInMapSZ(&ECtx, "an array of two strings"); QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string1", 7})); QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string2", 7})); QCBOREncode_CloseArray(&ECtx); - QCBOREncode_OpenMapInMap(&ECtx, "map in a map"); + QCBOREncode_OpenMapInMapSZ(&ECtx, "map in a map"); QCBOREncode_AddBytesToMap(&ECtx,"bytes 1", ((UsefulBufC) { "xxxx", 4})); - QCBOREncode_AddBytesToMap(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4})); - QCBOREncode_AddInt64ToMap(&ECtx, "another int", 98); - QCBOREncode_AddTextToMap(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30})); + QCBOREncode_AddBytesToMapSZ(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4})); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "another int", 98); + QCBOREncode_AddTextToMapSZ(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30})); QCBOREncode_CloseMap(&ECtx); QCBOREncode_CloseMap(&ECtx); @@ -1647,10 +1684,10 @@ FormatRTICResults(uint8_t uRResult, // The result: 0 if scan happened and found nothing; 1 if it happened and // found something wrong; 2 if it didn't happen - QCBOREncode_AddSimpleToMap(&ECtx, "integrity", uRResult); + QCBOREncode_AddSimpleToMapSZ(&ECtx, "integrity", uRResult); // Add the diagnostic code - QCBOREncode_AddSZStringToMap(&ECtx, "type", szType); + QCBOREncode_AddSZStringToMapSZ(&ECtx, "type", szType); // Add a time stamp if(time) { @@ -1658,24 +1695,24 @@ FormatRTICResults(uint8_t uRResult, } // Add the diagnostic code - QCBOREncode_AddSZStringToMap(&ECtx, "diag", szAlexString); + QCBOREncode_AddSZStringToMapSZ(&ECtx, "diag", szAlexString); // Open a subordinate map for telemtry data - QCBOREncode_OpenMapInMap(&ECtx, "telemetry"); + QCBOREncode_OpenMapInMapSZ(&ECtx, "telemetry"); { // Brace / indention just to show CBOR encoding nesting // Add a few fake integers and buffers for now. - QCBOREncode_AddInt64ToMap(&ECtx, "Shoe Size", 12); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "Shoe Size", 12); // Add a few fake integers and buffers for now. - QCBOREncode_AddInt64ToMap(&ECtx, "IQ", 0xffffffff); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "IQ", 0xffffffff); // Add a few fake integers and buffers for now. static const uint8_t pPV[] = {0x66, 0x67, 0x00, 0x56, 0xaa, 0xbb, 0x01, 0x01}; const UsefulBufC WSPV = {pPV, sizeof(pPV)}; - QCBOREncode_AddBytesToMap(&ECtx, "WhaleSharkPatternVector", WSPV); + QCBOREncode_AddBytesToMapSZ(&ECtx, "WhaleSharkPatternVector", WSPV); } } @@ -1896,6 +1933,24 @@ int32_t BstrWrapTest(void) return -11; } +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + // Seventh test, erroneous cancel + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_CancelBstrWrap(&EC); + uErr = QCBOREncode_GetErrorState(&EC); + if(uErr != QCBOR_ERR_TOO_MANY_CLOSES) { + return -12; + } + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&EC); + QCBOREncode_CancelBstrWrap(&EC); + uErr = QCBOREncode_GetErrorState(&EC); + if(uErr != QCBOR_ERR_CLOSE_MISMATCH) { + return -13; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + return 0; } @@ -2483,6 +2538,8 @@ int32_t EncodeErrorTests(void) { QCBOREncodeContext EC; QCBORError uErr; + UsefulBufC EncodedResult; + MakeUsefulBufOnStack(SmallBuffer, 4); // ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------ @@ -2648,6 +2705,12 @@ int32_t EncodeErrorTests(void) return -11; } + UsefulBuf Tmp; + Tmp = QCBOREncode_RetrieveOutputStorage(&EC); + if(Tmp.ptr != NULL && Tmp.len != UINT32_MAX) { + return -111; + } + /* ------ QCBOR_ERR_UNSUPPORTED -------- */ QCBOREncode_Init(&EC, Large); QCBOREncode_OpenArray(&EC); @@ -2678,6 +2741,62 @@ int32_t EncodeErrorTests(void) } #endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + /* Test that still-open error sticks */ + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + QCBOREncode_Finish(&EC, &EncodedResult); +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -120; + } +#else /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + if(QCBOREncode_GetErrorState(&EC) != QCBOR_SUCCESS) { + return -122; + } +#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + /* Test that too-small error is sticky */ + QCBOREncode_Init(&EC, SmallBuffer); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddInt64(&EC, INT64_MAX); + QCBOREncode_AddInt64(&EC, INT64_MAX); + QCBOREncode_AddInt64(&EC, INT64_MAX); + QCBOREncode_CloseArray(&EC); + QCBOREncode_Finish(&EC, &EncodedResult); + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_BUFFER_TOO_SMALL) { + return -130; + } + + +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + /* ------ QCBOR_ERR_ARRAY_TOO_LONG -------- */ + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + int i; + for(i = 0; i < QCBOR_MAX_ITEMS_IN_ARRAY; i++) { + QCBOREncode_AddInt64(&EC, 0); + } + if(QCBOREncode_GetErrorState(&EC)) { + return 250; + } + QCBOREncode_AddInt64(&EC, 0); + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_TOO_LONG) { + return 251; + } + + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenMap(&EC); + for(i = 0; i < QCBOR_MAX_ITEMS_IN_MAP; i++) { + QCBOREncode_AddInt64ToMapN(&EC, 0,0); + } + if(QCBOREncode_GetErrorState(&EC)) { + return 250; + } + QCBOREncode_AddInt64ToMapN(&EC, 0,0); + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_TOO_LONG) { + return 251; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ return 0; } @@ -2687,26 +2806,34 @@ int32_t EncodeErrorTests(void) /* [ 4([-1, 3]), + [-1, 4], 4([-20, 4759477275222530853136]), + [2, 4759477275222530853136], 4([9223372036854775807, -4759477275222530853137]), 5([300, 100]), + [600, 200], 5([-20, 4759477275222530853136]), - 5([-9223372036854775808, -4759477275222530853137]) - ] + [4, 4759477275222530853136], + 5([-9223372036854775808, -4759477275222530853137])] + ] */ static const uint8_t spExpectedExponentAndMantissaArray[] = { - 0x86, 0xC4, 0x82, 0x20, 0x03, 0xC4, 0x82, 0x33, - 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x10, 0xC4, 0x82, 0x1B, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, - 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x10, 0xC5, 0x82, 0x19, 0x01, 0x2C, - 0x18, 0x64, 0xC5, 0x82, 0x33, 0xC2, 0x4A, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x10, 0xC5, 0x82, 0x3B, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}; - + 0x8A, 0xC4, 0x82, 0x20, 0x03, 0x82, 0x20, 0x04, + 0xC4, 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x82, + 0x02, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x10, 0xC4, 0x82, 0x1B, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x10, 0xC5, 0x82, 0x19, 0x01, + 0x2C, 0x18, 0x64, 0x82, 0x19, 0x02, 0x58, 0x18, + 0xC8, 0xC5, 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + 0x82, 0x04, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0xC5, 0x82, + 0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x10}; /* { @@ -2785,11 +2912,15 @@ int32_t ExponentAndMantissaEncodeTests(void) QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); QCBOREncode_OpenArray(&EC); QCBOREncode_AddDecimalFraction(&EC, 3, -1); // 3 * (10 ^ -1) + QCBOREncode_AddTDecimalFraction(&EC, QCBOR_ENCODE_AS_BORROWED, 4, -1); // 3 * (10 ^ -1) QCBOREncode_AddDecimalFractionBigNum(&EC, BigNum , false, -20); - QCBOREncode_AddDecimalFractionBigNum(&EC, BigNum, true, INT64_MAX); + QCBOREncode_AddTDecimalFractionBigNum(&EC, QCBOR_ENCODE_AS_BORROWED, BigNum , false, 2); + QCBOREncode_AddTDecimalFractionBigNum(&EC, QCBOR_ENCODE_AS_TAG, BigNum, true, INT64_MAX); QCBOREncode_AddBigFloat(&EC, 100, 300); + QCBOREncode_AddTBigFloat(&EC, QCBOR_ENCODE_AS_BORROWED, 200, 600); QCBOREncode_AddBigFloatBigNum(&EC, BigNum, false, -20); - QCBOREncode_AddBigFloatBigNum(&EC, BigNum, true, INT64_MIN); + QCBOREncode_AddTBigFloatBigNum(&EC, QCBOR_ENCODE_AS_BORROWED, BigNum, false, 4); + QCBOREncode_AddTBigFloatBigNum(&EC, QCBOR_ENCODE_AS_TAG, BigNum, true, INT64_MIN); QCBOREncode_CloseArray(&EC); if(QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa)) { @@ -2822,17 +2953,19 @@ int32_t ExponentAndMantissaEncodeTests(void) false, INT32_MAX); - QCBOREncode_AddDecimalFractionBigNumToMapSZ(&EC, - "decimal fraction bignum negative", - BigNum, - true, - INT64_MAX); + QCBOREncode_AddTDecimalFractionBigNumToMapSZ(&EC, + "decimal fraction bignum negative", + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MAX); - QCBOREncode_AddDecimalFractionBigNumToMapN(&EC, - 500, - BigNum, - true, - INT64_MAX); + QCBOREncode_AddTDecimalFractionBigNumToMapN(&EC, + 500, + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MAX); QCBOREncode_AddBigFloatToMap(&EC, "big float", 100, 300); @@ -2850,17 +2983,19 @@ int32_t ExponentAndMantissaEncodeTests(void) false, -20); - QCBOREncode_AddBigFloatBigNumToMap(&EC, - "big float bignum negative", - BigNum, - true, - INT64_MIN); + QCBOREncode_AddTBigFloatBigNumToMapSZ(&EC, + "big float bignum negative", + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MIN); - QCBOREncode_AddBigFloatBigNumToMapN(&EC, - 800, - BigNum, - true, - INT64_MIN); + QCBOREncode_AddTBigFloatBigNumToMapN(&EC, + 800, + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MIN); QCBOREncode_CloseMap(&EC); @@ -3080,3 +3215,85 @@ OpenCloseBytesTest(void) return 0; } + + +int32_t SubStringTest(void) +{ + QCBOREncodeContext EC; + size_t uStart; + size_t uCurrent; + UsefulBufC SS; + UsefulBufC Encoded; + QCBORError uErr; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&EC); + uStart = QCBOREncode_Tell(&EC); + QCBOREncode_AddInt64(&EC, 0); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\x00", 1})) { + return 1; + } + + QCBOREncode_OpenArray(&EC); + + QCBOREncode_CloseArray(&EC); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\x00\x80", 2})) { + return 3; + } + + + /* Try it on a sequence */ + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + uStart = QCBOREncode_Tell(&EC); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\x01\x01\x01\x01", 4})) { + return 10; + } + + uCurrent = QCBOREncode_Tell(&EC); + if(!UsefulBuf_IsNULLC(QCBOREncode_SubString(&EC, uCurrent+1))) { + return 11; + } + +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + /* Now cause an error */ + QCBOREncode_OpenMap(&EC); + QCBOREncode_CloseArray(&EC); + if(!UsefulBuf_IsNULLC(QCBOREncode_SubString(&EC, uStart))) { + return 15; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + uStart = QCBOREncode_Tell(&EC); + QCBOREncode_OpenMap(&EC); + QCBOREncode_OpenMapInMapN(&EC, 3); + QCBOREncode_OpenArrayInMapN(&EC, 4); + QCBOREncode_AddInt64(&EC, 0); + QCBOREncode_CloseArray(&EC); + QCBOREncode_CloseMap(&EC); + QCBOREncode_CloseMap(&EC); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\xA1\x03\xA1\x04\x81\x00", 6})) { + return 20; + } + + uErr = QCBOREncode_Finish(&EC, &Encoded); + if(uErr) { + return 21; + } + if(UsefulBuf_Compare(Encoded, (UsefulBufC){"\x01\x01\xA1\x03\xA1\x04\x81\x00", 8})) { + return 22; + } + + return 0; +} diff --git a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h index bac1085987e6..bc47c55429cf 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h +++ b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h @@ -80,9 +80,8 @@ int32_t ArrayNestingTest3(void); /* - This tests the QCBOREncode_AddRaw() function by adding two chunks or - RAWCBOR to an array and comparing with expected values. This is an - encoding test. + This tests the QCBOREncode_AddRaw() function by adding two chunks of + raw CBOR to an array and comparing with expected values. */ int32_t EncodeRawTest(void); @@ -109,7 +108,7 @@ int32_t SimpleValuesTest1(void); /* Encodes basic maps and arrays with indefinite length */ -int32_t SimpleValuesIndefiniteLengthTest1(void); +int32_t IndefiniteLengthTest(void); /* @@ -192,5 +191,7 @@ int32_t QCBORHeadTest(void); int32_t OpenCloseBytesTest(void); +int32_t SubStringTest(void); + #endif /* defined(__QCBOR__qcbor_encode_tests__) */ diff --git a/3rdparty/exported/QCBOR/test/run_tests.c b/3rdparty/exported/QCBOR/test/run_tests.c index f2baaf114efa..cf806e94b144 100644 --- a/3rdparty/exported/QCBOR/test/run_tests.c +++ b/3rdparty/exported/QCBOR/test/run_tests.c @@ -1,12 +1,12 @@ /*============================================================================== run_tests.c -- test aggregator and results reporting - Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. + Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. Copyright (c) 2021, Arm Limited. All rights reserved. SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/30/18 =============================================================================*/ @@ -66,6 +66,13 @@ static test_entry2 s_tests2[] = { static test_entry s_tests[] = { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + TEST_ENTRY(GetMapAndArrayTest), + TEST_ENTRY(TellTests), + TEST_ENTRY(ParseMapAsArrayTest), + TEST_ENTRY(SpiffyDateDecodeTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + TEST_ENTRY(ErrorHandlingTests), TEST_ENTRY(OpenCloseBytesTest), TEST_ENTRY(EnterBstrTest), TEST_ENTRY(IntegerConvertTest), @@ -73,13 +80,12 @@ static test_entry s_tests[] = { TEST_ENTRY(QCBORHeadTest), TEST_ENTRY(EmptyMapsAndArraysTest), TEST_ENTRY(NotWellFormedTests), - TEST_ENTRY(ParseMapAsArrayTest), #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS TEST_ENTRY(IndefiniteLengthNestTest), TEST_ENTRY(IndefiniteLengthArrayMapTest), TEST_ENTRY(NestedMapTestIndefLen), #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - TEST_ENTRY(ParseSimpleTest), + TEST_ENTRY(SimpleValueDecodeTests), TEST_ENTRY(DecodeFailureTests), TEST_ENTRY(EncodeRawTest), TEST_ENTRY(RTICResultsTest), @@ -95,7 +101,9 @@ static test_entry s_tests[] = { TEST_ENTRY(AllAddMethodsTest), TEST_ENTRY(ParseTooDeepArrayTest), TEST_ENTRY(ComprehensiveInputTest), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(ParseMapTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ TEST_ENTRY(BasicEncodeTest), TEST_ENTRY(NestedMapTest), TEST_ENTRY(BignumParseTest), @@ -104,7 +112,6 @@ static test_entry s_tests[] = { TEST_ENTRY(DateParseTest), TEST_ENTRY(DecodeTaggedTypeTests), #endif /* QCBOR_DISABLE_TAGS */ - TEST_ENTRY(SpiffyDateDecodeTest), TEST_ENTRY(ShortBufferParseTest2), TEST_ENTRY(ShortBufferParseTest), TEST_ENTRY(ParseDeepArrayTest), @@ -114,16 +121,17 @@ static test_entry s_tests[] = { TEST_ENTRY(AllocAllStringsTest), TEST_ENTRY(MemPoolTest), TEST_ENTRY(IndefiniteLengthStringTest), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(SpiffyIndefiniteLengthStringsTests), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ TEST_ENTRY(SetUpAllocatorTest), TEST_ENTRY(CBORTestIssue134), #endif /* #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ +#ifndef USEFULBUF_DISABLE_ALL_FLOAT #ifndef QCBOR_DISABLE_PREFERRED_FLOAT - TEST_ENTRY(HalfPrecisionDecodeBasicTests), - TEST_ENTRY(DoubleAsSmallestTest), - TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), + TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), + TEST_ENTRY(FloatValuesTests), #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -#ifndef USEFULBUF_DISABLE_ALL_FLOAT TEST_ENTRY(GeneralFloatEncodeTests), TEST_ENTRY(GeneralFloatDecodeTests), #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ @@ -131,15 +139,21 @@ static test_entry s_tests[] = { TEST_ENTRY(BstrWrapErrorTest), TEST_ENTRY(BstrWrapNestTest), TEST_ENTRY(CoseSign1TBSTest), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(StringDecoderModeFailTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ TEST_ENTRY_DISABLED(BigComprehensiveInputTest), TEST_ENTRY_DISABLED(TooLargeInputTest), TEST_ENTRY(EncodeErrorTests), - TEST_ENTRY(SimpleValuesIndefiniteLengthTest1), +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + TEST_ENTRY(IndefiniteLengthTest), +#endif TEST_ENTRY(EncodeLengthThirtyoneTest), TEST_ENTRY(CBORSequenceDecodeTests), TEST_ENTRY(IntToTests), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(PeekAndRewindTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA TEST_ENTRY(ExponentAndMantissaDecodeTests), #ifndef QCBOR_DISABLE_TAGS @@ -148,6 +162,7 @@ static test_entry s_tests[] = { TEST_ENTRY(ExponentAndMantissaEncodeTests), #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ TEST_ENTRY(ParseEmptyMapInMapTest), + TEST_ENTRY(SubStringTest), TEST_ENTRY(BoolTest) }; @@ -346,6 +361,6 @@ void PrintSizesQCBOR(OutputStringCB pfOutput, void *pOutCtx) PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx); PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx); PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx); - PrintSize("sizeof(TagSpecification)", (uint32_t)sizeof(TagSpecification), pfOutput, pOutCtx); + PrintSize("sizeof(TagSpecification)", (uint32_t)sizeof(QCBOR_Private_TagSpec),pfOutput, pOutCtx); (*pfOutput)("", pOutCtx, 1); } diff --git a/3rdparty/exported/QCBOR/test/run_tests.h b/3rdparty/exported/QCBOR/test/run_tests.h index ce44673fd48e..370558aae086 100644 --- a/3rdparty/exported/QCBOR/test/run_tests.h +++ b/3rdparty/exported/QCBOR/test/run_tests.h @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created 9/30/18 =============================================================================*/ @@ -60,7 +60,7 @@ int RunTestsQCBOR(const char *szTestNames[], /** - @brief Print sizes of encoder / decoder contexts. + @brief Print sizes of encoder-decoder contexts. @param[in] pfOutput Function that is called to output text strings. @param[in] pOutCtx Context pointer passed to output function. diff --git a/3rdparty/exported/QCBOR/ub-example.c b/3rdparty/exported/QCBOR/ub-example.c index 996cf3a9071e..ec776dca366a 100644 --- a/3rdparty/exported/QCBOR/ub-example.c +++ b/3rdparty/exported/QCBOR/ub-example.c @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 4/8/22 ========================================================================== */ diff --git a/3rdparty/exported/QCBOR/ub-example.h b/3rdparty/exported/QCBOR/ub-example.h index 131c807668ab..93449f4a3323 100644 --- a/3rdparty/exported/QCBOR/ub-example.h +++ b/3rdparty/exported/QCBOR/ub-example.h @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 4/8/22 ========================================================================== */ diff --git a/3rdparty/exported/t_cose/CMakeLists.txt b/3rdparty/exported/t_cose/CMakeLists.txt index 4f0c8682c63b..aca76d525407 100644 --- a/3rdparty/exported/t_cose/CMakeLists.txt +++ b/3rdparty/exported/t_cose/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12) project(t_cose DESCRIPTION "t_cose" LANGUAGES C - VERSION 1.0.1) + VERSION 1.1.3) # Constants set(CRYPTO_PROVIDERS "OpenSSL" "MbedTLS" "Test") diff --git a/3rdparty/exported/t_cose/CONTRIBUTING.md b/3rdparty/exported/t_cose/CONTRIBUTING.md index e4c069eb9814..4aa1ffc3c747 100644 --- a/3rdparty/exported/t_cose/CONTRIBUTING.md +++ b/3rdparty/exported/t_cose/CONTRIBUTING.md @@ -16,19 +16,33 @@ will be merged. ### Basic tests -Running the standard make will produce `t_cose_test` for a particular -crypto library. It runs a thorough set of tests. +Make will produce the executable t_cose_test. Running it will perform +all the regression tests. When new features are added regression tests +for them must be added here. + +However, it only runs with one crypto library, one compiler and one +set of #defines at a time. See tdv/b.sh for that. ### CI tests -GitHub CI is used to build and test against several crypto libraries. +GitHub CI is used to provide the general benefit of CI. It gives test +fanout for the standard major crypto libraries and versions, plus +build environments. It does NOT give full fanout for #define +configurations or for other special configurations. See tdv/b.sh for +that. + +The time GitHub CI takes to run must be kept to a few minutes so as to +not cause excess delay in the commit/merge cycle and disrupt the +human workflow. This is the main reason testing done by it is +limited. The full fanout from tdv/b.sh takes tens of minutes so +it can't be run during CI. ### tdv/b.sh tests In the "tdv" repository there are some makes files and build scripts -that do some more thorough testing. They are too large and take too -long to run to make them part of normal CI. Here's a few things they -do: +run the full configuration fan out testing. They are too large and +take too long to run to make them part of normal CI. Here's a few +things they do: * Build with a fairly maximal set of compiler warning flags set (e.g., -Wall) @@ -83,3 +97,84 @@ guidelines](https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/doc resulting in code with mixed styles. For better or worse, an Arm-style version of UsefulBuf is created and used and so there is a duplicate of UsefulBuf. The two are identical. They just have different names. + + +## Features and conditionality + +The goal is for t_cose's use of #defines to be much simpler than most other libraries. + +A couple of principles govern feature variation and conditional compiliation: + +* A #define is NOT required to enable features. All features are "on" by + default. + +* The internal function link dependency of t_cose is designed to work + well with the compiler -dead_strip option so linked object code is + minimized. + +* Attempts to call t_cose APIs or use t_cose features which are not + supported by the crypto library often result in an error code being + returned and sometimes in a link error. + +* The primary use of #defines is to disable features to reduce object + code size for use cases that need small code size. + +### Users of t_cose + +Most users of t_cose do not need to be concerned with #defines as they +are not needed to enable features in the library. All the features are +already enabled. + +Users may find that sometimes they get error codes indicating a +feature isn't supported. This will usually be because the underlying +crypto library they are linking against doesn't support the feature, +not because the feature needs to be enabled in t_cose. + +Users may also find that sometimes they get a link error reporting an +undefined symbol. This will again usually be because the underlying +crypto library being linked against doesn't support the feature. + +For example, t_cose works with several versions of MbedTLS older +versions of which don't support AES key wrap. You can use t_cose with +these older versions just fine as long as you don't call any t_cose +APIs or use any t_cose features that need key wrap. If you do, you'll +probably get a T_COSE_ERR_UNSUPPORTED_XX error. + +If your use case needs small object code, then it may be time to make +use of T_COSE_DISABLE_XXXX #defines and recompile the t_cose library. +But it also might be that the minimized link dependency and +-dead_strip does everything you need too. + + +### Contributing to t_cose + +If you are adding a feature to t_cose don't assume that a #define will +be needed and try hard to avoid one. + +Try to implement with minimal symbol/link dependency. One way to do +this is to create a new signer or recipient object just for the +feature. This might involve a new function in the crypto adaptor layer +for a new feature from the crypto library put to use. The new function +is only linked when the new feature is used. + +The crypto layer has a facility for listing and discovering crypto +algorithms that are supported by a particular crypto library. This +facility is mostly used to know what to test, but not exclusively. + +If a feature can work in multiple modes or have multiple behaviors, +don't control that with a #define. Instead control that with an option +flag or with some API methods. That makes install and configuration of +the library simpler. It also works much better for a shared library +because different users of it can use different modes. + +Then, in the end, the only reason to use a #ifdef should be to reduce +object code if there's no other way. + +When an #fdef has to be used, it should be in the least intrusive way +and it shouldn't make the code hard to read. Maybe even restructure +the code a little so the #ifdef is cleaner. + + + + + diff --git a/3rdparty/exported/t_cose/Makefile.ossl b/3rdparty/exported/t_cose/Makefile.ossl index 1df2d06a26d9..da00b226e034 100644 --- a/3rdparty/exported/t_cose/Makefile.ossl +++ b/3rdparty/exported/t_cose/Makefile.ossl @@ -58,8 +58,8 @@ TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test # ---- the main body that is invariant ---- -INC=-I inc -I test -I src -ALL_INC=$(INC) $(CRYPTO_INC) $(QCBOR_INC) +T_COSE_INC=-I inc -I test -I src +ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o diff --git a/3rdparty/exported/t_cose/Makefile.psa b/3rdparty/exported/t_cose/Makefile.psa index 3f9c28f1b4f3..3604beb0eefb 100644 --- a/3rdparty/exported/t_cose/Makefile.psa +++ b/3rdparty/exported/t_cose/Makefile.psa @@ -60,8 +60,8 @@ TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test # ---- the main body that is invariant ---- -INC=-I inc -I test -I src -ALL_INC=$(INC) $(CRYPTO_INC) $(QCBOR_INC) +T_COSE_INC=-I inc -I test -I src +ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o diff --git a/3rdparty/exported/t_cose/Makefile.test b/3rdparty/exported/t_cose/Makefile.test index 7a233758c3b4..c5d40049bfcb 100644 --- a/3rdparty/exported/t_cose/Makefile.test +++ b/3rdparty/exported/t_cose/Makefile.test @@ -16,8 +16,10 @@ # ---- QCBOR location ---- # Adjust this to the location of QCBOR in your build environment -#QCBOR_INC= -I ../../QCBOR/master/inc -#QCBOR_LIB=../../QCBOR/master/libqcbor.a +#QCBOR_DIR=../../QCBOR/master +#QCBOR_INC=-I $(QCBOR_DIR)/inc +#QCBOR_LIB=$(QCBOR_DIR)/libqcbor.a + QCBOR_INC= -I/usr/include -I/usr/local/include QCBOR_LIB= -l qcbor @@ -42,8 +44,8 @@ TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_make_test_messages.o $( # ---- the main body that is invariant ---- -INC=-I inc -I test -I src -ALL_INC=$(INC) $(CRYPTO_INC) $(QCBOR_INC) +T_COSE_INC=-I inc -I test -I src +ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o diff --git a/3rdparty/exported/t_cose/README.md b/3rdparty/exported/t_cose/README.md index ba5c473e1969..56452d4c2e2f 100644 --- a/3rdparty/exported/t_cose/README.md +++ b/3rdparty/exported/t_cose/README.md @@ -30,7 +30,7 @@ useful for embedded implementations that have to run in small fixed memory. ## Documentation -[API documentation is here](https://laurencelundblade.github.io/t_cose/) +[API documentation is here](https://www.securitytheory.com/t_cose-docs) ## Code Status @@ -45,17 +45,16 @@ fully supported. t_cose 1.0 only supports COSE Sign1, signing with one recipeint. -## Future Work +## t_cose 2.0 -As of March 2022, work is underway to support encryption, MAC and -other COSE features. When a good set of these are complete to -commercial quality, a 2.0 version of t_cose will be released. - -Note that there is no committed time line to complete t_cose -2.0. t_cose is mostly implemented on a volunteer basis. You can -volunteer! Work like adding support for more algorithms is not too -difficult and is nicely framed up. +As of August 2022, there are alpha releases of t_cose 2.0. It supports: +* COSE_Sign +* Multiple signatures +* COSE_MAC0 +* COSE_Encrypt and COSE_Encrypt0 +* Encryption with ECDH per RFC 9053 +See the dev branch and the releases. ## Building and Dependencies @@ -71,6 +70,9 @@ If QCBOR is installed in /usr/local, then the makefiles should find it. If not then QCBOR may need to be downloaded. The makefiles can be modified to reference it other than in /usr/local. +This works with both QCBOR v1 and v2. When running with v2 it +uses the QCBOR v1 compatibility mode for tag decoding. + ### Supported Cryptographic Libraries Here's three crypto library configurations that are supported. Others diff --git a/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h b/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h index 501c480a48fe..93a975ef2d12 100644 --- a/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h +++ b/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h @@ -1,7 +1,7 @@ /* * t_cose_common.h * - * Copyright 2019-2022, Laurence Lundblade + * Copyright 2019-2024, Laurence Lundblade * * SPDX-License-Identifier: BSD-3-Clause * @@ -59,6 +59,14 @@ extern "C" { */ +/** + * Semantic versioning for t_cose x.y.z. Note that these were not defined + * for some releases of t_cose 1.x so !defined(T_COSE_VERSION_MAJOR) + * indicates t_cose 1.x. + */ +#define T_COSE_VERSION_MAJOR 1 +#define T_COSE_VERSION_MINOR 1 +#define T_COSE_VERSION_PATCH 3 /** diff --git a/3rdparty/exported/t_cose/mainpage.dox b/3rdparty/exported/t_cose/mainpage.dox new file mode 100644 index 000000000000..0fb69c71f88c --- /dev/null +++ b/3rdparty/exported/t_cose/mainpage.dox @@ -0,0 +1,18 @@ +/*! @mainpage t_cose Documentation + +t_cose 1.x is available for download [here on github](http://github.com/laurencelundblade/t_cose) +(alpha release of t_cose 2.x which supports encryption, multiple signature and mac is also available). + +This documentation is for t_cose 1.x. + +@par Table of Contents + +API Reference: +- Common + - Error codes and common constants: @ref inc/t_cose/t_cose_common.h "t_cose_common.h" +- Signing + - Main/Basic signing functions: @ref inc/t_cose/t_cose_sign1_sign.h "t_cose_sign1_sign.h" +- Verification + - Main/Basic verification functions: @ref inc/t_cose/t_cose_sign1_verify.h "t_cose_sign1_verify.h" + +*/ diff --git a/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c b/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c index 9aca0e88fab7..18c8f9209ded 100644 --- a/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c +++ b/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c @@ -1,7 +1,7 @@ /* * t_cose_sign1_sign.c * - * Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -15,11 +15,13 @@ #include "t_cose_util.h" #include "t_cose_short_circuit.h" -#ifndef QCBOR_1_1 -// The OpenBytes API we use was only added in 1.1. + +#if !(defined(QCBOR_1_1) || QCBOR_VERSION_MAJOR >= 2 || (QCBOR_VERSION_MAJOR == 1 && QCBOR_VERSION_MINOR >= 1)) +/* The OpenBytes API we use was only added in 1.1. */ #error t_cose requires QCBOR 1.1 or greater #endif + /** * \file t_cose_sign1_sign.c * diff --git a/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c b/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c index e4d004acac13..c332089c9984 100644 --- a/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c +++ b/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c @@ -389,9 +389,14 @@ t_cose_sign1_verify_internal(struct t_cose_sign1_verify_ctx *me, clear_label_list(&critical_parameter_labels); clear_cose_parameters(¶meters); +#if QCBOR_VERSION_MAJOR >= 2 + const int decode_config = QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS; +#else + const int decode_config = QCBOR_DECODE_MODE_NORMAL; +#endif /* === Decoding of the array of four starts here === */ - QCBORDecode_Init(&decode_context, cose_sign1, QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_Init(&decode_context, cose_sign1, decode_config); /* --- The array of 4 and tags --- */ QCBORDecode_EnterArray(&decode_context, NULL); diff --git a/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj b/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj index 2b4a0423306f..9f50be993a31 100644 --- a/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj +++ b/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj @@ -812,7 +812,7 @@ CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; @@ -878,7 +878,7 @@ CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; diff --git a/cgmanifest.json b/cgmanifest.json index e448c442b7a6..18a17434c579 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -123,7 +123,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/laurencelundblade/QCBOR", - "commitHash": "92d3f89030baff4af7be8396c563e6c8ef263622" + "commitHash": "24cd62a415161c2851327e96a023b47bb0897e64" } } }, @@ -132,7 +132,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/laurencelundblade/t_cose", - "commitHash": "7d1b6686990e5bf6b84df422f93fb7f547669012" + "commitHash": "64fbc64dd5982a7f75834d2b9a2a8c9ba8207776" } } },