├── inc ├── qcbor.h ├── UsefulBuf.h └── qcbor │ ├── qcbor.h │ ├── qcbor_private.h │ └── qcbor_common.h ├── doc ├── DocReadMe.txt ├── TimeTag1FAQ.md └── Tagging.md ├── example.h ├── ub-example.h ├── .gitignore ├── test ├── half_to_double_from_rfc7049.h ├── float_tests.h ├── half_to_double_from_rfc7049.c ├── CMakeLists.txt ├── run_tests.h ├── UsefulBuf_Tests.h ├── qcbor_encode_tests.h ├── qcbor_decode_tests.h ├── run_tests.c └── not_well_formed_cbor.h ├── SECURITY.md ├── cmd_line_main.c ├── LICENSE ├── pkg └── qcbor.spec ├── .github └── workflows │ └── ci.yml ├── CMakeLists.txt ├── src ├── qcbor_err_to_str.c ├── ieee754.h └── UsefulBuf.c ├── Makefile ├── ub-example.c ├── example.c └── README.md /inc/qcbor.h: -------------------------------------------------------------------------------- 1 | #include "qcbor/qcbor.h" 2 | -------------------------------------------------------------------------------- /inc/UsefulBuf.h: -------------------------------------------------------------------------------- 1 | #include "qcbor/UsefulBuf.h" 2 | -------------------------------------------------------------------------------- /doc/DocReadMe.txt: -------------------------------------------------------------------------------- 1 | Most documentation is in the header files in ../inc/qcbor/. 2 | The files here are additional articles. 3 | There is cross-referencing between these articles and the header files. 4 | 5 | -------------------------------------------------------------------------------- /example.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | example.h -- QCBOR encode and decode example 3 | 4 | Copyright (c) 2020, Laurence Lundblade. All rights reserved. 5 | 6 | SPDX-License-Identifier: BSD-3-Clause 7 | 8 | See BSD-3-Clause license in file named "LICENSE" 9 | 10 | Created on 6/30/20 11 | =============================================================================*/ 12 | 13 | #ifndef qcborExample_h 14 | #define qcborExample_h 15 | 16 | #include 17 | 18 | int32_t RunQCborExample(void); 19 | 20 | #endif /* qcborExample_h */ 21 | -------------------------------------------------------------------------------- /ub-example.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | ub-example.h -- Example code for UsefulBuf 3 | 4 | Copyright (c) 2022, Laurence Lundblade. All rights reserved. 5 | 6 | SPDX-License-Identifier: BSD-3-Clause 7 | 8 | See BSD-3-Clause license in file named "LICENSE" 9 | 10 | Created on 4/8/22 11 | ========================================================================== */ 12 | #ifndef ub_example_h 13 | #define ub_example_h 14 | 15 | #include 16 | 17 | int32_t RunUsefulBufExample(void); 18 | 19 | #endif /* ub_example_h */ 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Compiled binaries 55 | qcbortest 56 | qcbormin 57 | 58 | -------------------------------------------------------------------------------- /test/half_to_double_from_rfc7049.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | half_to_double_from_rfc7049.h -- interface to IETF float conversion code. 3 | 4 | Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. 5 | Copyright (c) 2021, Arm Limited. All rights reserved. 6 | 7 | SPDX-License-Identifier: BSD-3-Clause 8 | 9 | See BSD-3-Clause license in file named "LICENSE" 10 | 11 | Created on 9/23/18 12 | ============================================================================*/ 13 | 14 | #ifndef half_to_double_from_rfc7049_h 15 | #define half_to_double_from_rfc7049_h 16 | 17 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 18 | double decode_half(const unsigned char *halfp); 19 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 20 | 21 | #endif /* half_to_double_from_rfc7049_h */ 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please report security vulnerabilities by sending email to lgl@island-resort.com. 6 | Please include "QCBOR SECURITY" in the subject line. 7 | 8 | In most cases the vulnerability should not be reported by filing an issue in GitHub as this 9 | will publically disclose the issue before a fix is available. 10 | 11 | Laurence Lundblade maintains this code and will respond in a day or two with an initial 12 | evaluation. 13 | 14 | Security fixes will be prioritized over other work. 15 | 16 | Vulnerabilities will be fixed promptly, but some may be more complex than others 17 | and take longer. If the fix is quick, it will usually be turned around in a 18 | few days. 19 | 20 | ## Availability of Fixes 21 | 22 | When the fix has been created, it will be privately verified with the party that reported it. 23 | Only after the fix has been verified and the reporter has had a chance to integrate the fix, 24 | will it be made available as a public commit in GitHub. 25 | 26 | If the reporter doesn't respond or can't integrate the fix, it will be made public after 30 days. 27 | 28 | -------------------------------------------------------------------------------- /cmd_line_main.c: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | cmd_line_mainc.c -- Runs tests for QCBOR encoder-decoder 3 | 4 | Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. 5 | 6 | SPDX-License-Identifier: BSD-3-Clause 7 | 8 | See BSD-3-Clause license in file named "LICENSE" 9 | 10 | Created on 9/13/18 11 | =============================================================================*/ 12 | 13 | #include 14 | #include "run_tests.h" 15 | #include "example.h" 16 | #include "ub-example.h" 17 | 18 | 19 | /* 20 | This is an implementation of OutputStringCB built using stdio. If 21 | you don't have stdio, replaces this. 22 | */ 23 | static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine) 24 | { 25 | fputs(szString, (FILE *)pOutCtx); 26 | if(bNewLine) { 27 | fputs("\n", pOutCtx); 28 | } 29 | } 30 | 31 | 32 | int main(int argc, const char * argv[]) 33 | { 34 | (void)argc; // Avoid unused parameter error 35 | 36 | RunQCborExample(); 37 | RunUsefulBufExample(); 38 | 39 | 40 | // This call prints out sizes of data structures to remind us 41 | // to keep them small. 42 | PrintSizesQCBOR(&fputs_wrapper, stdout); 43 | 44 | // This runs all the tests 45 | return RunTestsQCBOR(argv+1, &fputs_wrapper, stdout, NULL); 46 | } 47 | -------------------------------------------------------------------------------- /test/float_tests.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | float_tests.h -- tests for floats and conversion to/from half-precision 3 | 4 | Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. 5 | 6 | SPDX-License-Identifier: BSD-3-Clause 7 | 8 | See BSD-3-Clause license in file named "LICENSE" 9 | 10 | Created on 9/19/18 11 | =============================================================================*/ 12 | 13 | #ifndef float_tests_h 14 | #define float_tests_h 15 | 16 | #include 17 | 18 | #ifndef QCBOR_DISABLE_PREFERRED_FLOAT 19 | 20 | /* This tests a large number half-precision values 21 | * in the conversion to/from half/double against 22 | * the sample code in the CBOR RFC. */ 23 | int32_t HalfPrecisionAgainstRFCCodeTest(void); 24 | 25 | #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ 26 | 27 | 28 | /* 29 | * This tests floating point encoding, decoding 30 | * and conversion for lots of different values. 31 | * It covers Preferred Serialization processing 32 | * of floating point. It's focus is on the numbers 33 | * not the encode/decode functions. 34 | */ 35 | int32_t FloatValuesTests(void); 36 | 37 | 38 | /* 39 | * This calls each and every method for encoding 40 | * floating-point numbers. 41 | */ 42 | int32_t GeneralFloatEncodeTests(void); 43 | 44 | 45 | /* 46 | * Tests float decoding, including error codes in scenarios 47 | * where various float features are disabled. This also 48 | * tests decoding using spiffy decode methods. 49 | */ 50 | int32_t GeneralFloatDecodeTests(void); 51 | 52 | 53 | #endif /* float_tests_h */ 54 | -------------------------------------------------------------------------------- /test/half_to_double_from_rfc7049.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2013 IETF Trust and the persons identified as the 4 | document authors. All rights reserved. 5 | 6 | Copyright (c) 2021, Arm Limited. All rights reserved. 7 | 8 | This document is subject to BCP 78 and the IETF Trust's Legal 9 | Provisions Relating to IETF Documents 10 | (http://trustee.ietf.org/license-info) in effect on the date of 11 | publication of this document. Please review these documents 12 | carefully, as they describe your rights and restrictions with respect 13 | to this document. Code Components extracted from this document must 14 | include Simplified BSD License text as described in Section 4.e of 15 | the Trust Legal Provisions and are provided without warranty as 16 | described in the Simplified BSD License. 17 | 18 | */ 19 | 20 | /* 21 | This code is from RFC 7049/8949. It is not used in the main implementation 22 | because: 23 | a) it adds a dependency on and ldexp(). 24 | b) the license may be an issue 25 | 26 | QCBOR does support half-precision, but rather than using 27 | floating-point math like this, it does it with bit shifting 28 | and masking. 29 | 30 | This code is here to test that code. 31 | 32 | */ 33 | 34 | #include "half_to_double_from_rfc7049.h" 35 | 36 | #include 37 | 38 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 39 | double decode_half(const unsigned char *halfp) { 40 | int half = (halfp[0] << 8) + halfp[1]; 41 | int exp = (half >> 10) & 0x1f; 42 | int mant = half & 0x3ff; 43 | double val; 44 | if (exp == 0) val = ldexp(mant, -24); 45 | else if (exp != 31) val = ldexp(mant + 1024, exp - 25); 46 | else val = mant == 0 ? INFINITY : NAN; 47 | return half & 0x8000 ? -val : val; 48 | } 49 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | QCBOR is available under what is essentially the 3-Clause BSD License. 2 | 3 | Files created inside Qualcomm and open-sourced through CAF (The Code 4 | Aurora Forum) have a slightly modified 3-Clause BSD License. The 5 | modification additionally disclaims NON-INFRINGEMENT. 6 | 7 | Files created after release to CAF use the standard 3-Clause BSD 8 | License with no modification. These files have the SPDX license 9 | identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. 10 | 11 | 12 | BSD 3-Clause License 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | 17 | 1. Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | 20 | 2. Redistributions in binary form must reproduce the above copyright notice, 21 | this list of conditions and the following disclaimer in the documentation 22 | and/or other materials provided with the distribution. 23 | 24 | 3. Neither the name of the copyright holder nor the names of its 25 | contributors may be used to endorse or promote products derived from 26 | this software without specific prior written permission. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 32 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | -------------------------------------------------------------------------------- /inc/qcbor/qcbor.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | Copyright (c) 2016-2018, The Linux Foundation. 3 | Copyright (c) 2018-2020, Laurence Lundblade. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | * Neither the name of The Linux Foundation nor the names of its 16 | contributors, nor the name "Laurence Lundblade" may be used to 17 | endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 21 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 24 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 30 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | =============================================================================*/ 32 | 33 | /** 34 | * @file qcbor.h 35 | * 36 | * Backwards compatibility for includers of qcbor.h (which has been split 37 | * into four include files). 38 | */ 39 | 40 | #include "qcbor_encode.h" 41 | #include "qcbor_decode.h" 42 | -------------------------------------------------------------------------------- /pkg/qcbor.spec: -------------------------------------------------------------------------------- 1 | # Guidelines from https://docs.fedoraproject.org/en-US/packaging-guidelines/CMake/ 2 | 3 | Name: qcbor 4 | Version: 1.6 5 | Release: 0%{?dist} 6 | Summary: A CBOR encoder/decoder library 7 | URL: https://github.com/laurencelundblade/QCBOR 8 | License: BSD-3-Clause 9 | Source0: %{URL}/archive/refs/tags/v1.5.3.tar.gz 10 | 11 | BuildRequires: cmake 12 | BuildRequires: gcc 13 | 14 | %description 15 | Comprehensive, powerful, commercial-quality CBOR encoder and decoder 16 | that is still suited for small devices. 17 | 18 | 19 | %package devel 20 | Summary: Development files for the QCBOR library 21 | Requires: %{name}%{?_isa} = %{version} 22 | %description devel 23 | Development files needed to build and link to the QCBOR library. 24 | 25 | 26 | %prep 27 | %setup -q -n QCBOR-1.5.3 28 | %cmake -DBUILD_QCBOR_TEST=APP 29 | 30 | 31 | %build 32 | %cmake_build 33 | 34 | %install 35 | %cmake_install 36 | 37 | 38 | %check 39 | # TODO use %ctest when supported by QCBOR config 40 | ./%{_vpath_builddir}/test/qcbortest 41 | 42 | 43 | %files 44 | %license LICENSE 45 | %doc README.md 46 | %{_libdir}/*.so.* 47 | 48 | %files devel 49 | %license LICENSE 50 | %doc README.md 51 | %{_includedir}/qcbor 52 | %{_libdir}/*.so 53 | 54 | 55 | %changelog 56 | * Nov 12 2026 Laurence Lundblade - 1.6 57 | - Better Windows/MSVC support 58 | - Bug fix for GetArray() and GetMap() 59 | - Fix gcc warnings 60 | - Bug fix for OpenBstr on empty map at end of input 61 | - Bug fix for floating-point NaN payload conversion for preferred serialization 62 | - Don't use strcpy() 63 | * Jun 16 2025 Laurence Lundblade - 1.5.3 64 | - Bug fix for GetArray() from empty map 65 | - Increase test coverage 66 | - Documentation improvements 67 | * Jun 16 2025 Laurence Lundblade - 1.5.2 68 | - Bug fix for QCBORDecode_GetMap() and QCBORDecode_GetArray() 69 | - Fix warning for compilers compliant with C23 standard 70 | - Minor documentation fix 71 | - Fix for embedded platforms with partial implementations of llround() 72 | * Jan 8 2024 Laurence Lundblade - 1.5.1 73 | - Initial library RPM packaging. 74 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # Copyright (c) 2022-2023, Arm Limited. All rights reserved. 3 | # 4 | # SPDX-License-Identifier: BSD-3-Clause 5 | # 6 | # See BSD-3-Clause license in README.md 7 | #------------------------------------------------------------------------------- 8 | 9 | cmake_minimum_required(VERSION 3.15) 10 | 11 | # Validate value of BUILD_QCBOR_TEST config option 12 | if ((NOT BUILD_QCBOR_TEST STREQUAL "LIB") AND (NOT BUILD_QCBOR_TEST STREQUAL "APP")) 13 | message(FATAL_ERROR "QCBOR | Invalid Config: BUILD_QCBOR_TEST=${BUILD_QCBOR_TEST}") 14 | endif() 15 | 16 | add_library(qcbor_test STATIC) 17 | 18 | target_sources(qcbor_test 19 | PRIVATE 20 | float_tests.c 21 | half_to_double_from_rfc7049.c 22 | qcbor_decode_tests.c 23 | qcbor_encode_tests.c 24 | run_tests.c 25 | UsefulBuf_Tests.c 26 | ) 27 | 28 | target_include_directories(qcbor_test 29 | PUBLIC 30 | . 31 | PRIVATE 32 | ../inc 33 | ) 34 | 35 | target_compile_definitions(qcbor_test 36 | PUBLIC 37 | $<$:QCBOR_DISABLE_FLOAT_HW_USE> 38 | $<$:QCBOR_DISABLE_PREFERRED_FLOAT> 39 | $<$:USEFULBUF_DISABLE_ALL_FLOAT> 40 | ) 41 | 42 | target_link_libraries(qcbor_test 43 | PRIVATE 44 | qcbor 45 | # The math library is needed for floating-point support. 46 | # To avoid need for it #define QCBOR_DISABLE_FLOAT_HW_USE 47 | # Using GCC 48 | $<$,$>>:m> 49 | ) 50 | 51 | if (BUILD_QCBOR_TEST STREQUAL "APP") 52 | add_executable(qcbortest) 53 | 54 | target_sources(qcbortest 55 | PRIVATE 56 | ../cmd_line_main.c 57 | ../example.c 58 | ../ub-example.c 59 | ) 60 | 61 | target_include_directories(qcbortest 62 | PRIVATE 63 | ../ 64 | ) 65 | 66 | target_link_libraries(qcbortest 67 | PRIVATE 68 | qcbor 69 | qcbor_test 70 | ) 71 | 72 | message(STATUS "Adding test qcbortest") 73 | add_test( 74 | NAME qcbortest 75 | COMMAND qcbortest 76 | ) 77 | endif() 78 | -------------------------------------------------------------------------------- /test/run_tests.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | run_tests.h -- test aggregator and results reporting 3 | 4 | Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. 5 | 6 | SPDX-License-Identifier: BSD-3-Clause 7 | 8 | See BSD-3-Clause license in file named "LICENSE" 9 | 10 | Created 9/30/18 11 | =============================================================================*/ 12 | 13 | /** 14 | @file run_tests.h 15 | */ 16 | 17 | /** 18 | @brief Type for function to output a text string 19 | 20 | @param[in] szString The string to output 21 | @param[in] pOutCtx A context pointer; NULL if not needed 22 | @param[in] bNewline If non-zero, output a newline after the string 23 | 24 | This is a prototype of a function to be passed to RunTests() to 25 | output text strings. 26 | 27 | This can be implemented with stdio (if available) using a straight 28 | call to fputs() where the FILE * is passed as the pOutCtx as shown in 29 | the example code below. This code is for Linux where the newline is 30 | a \\n. Windows usually prefers \\r\\n. 31 | 32 | @code 33 | static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine) 34 | { 35 | fputs(szString, (FILE *)pOutCtx); 36 | if(bNewLine) { 37 | fputs("\n", pOutCtx); 38 | } 39 | } 40 | @endcode 41 | */ 42 | typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline); 43 | 44 | 45 | /** 46 | @brief Runs the QCBOR tests. 47 | 48 | @param[in] szTestNames An argv-style list of test names to run. If 49 | empty, all are run. 50 | @param[in] pfOutput Function that is called to output text strings. 51 | @param[in] pOutCtx Context pointer passed to output function. 52 | @param[out] pNumTestsRun Returns the number of tests run. May be NULL. 53 | 54 | @return The number of tests that failed. Zero means overall success. 55 | */ 56 | int RunTestsQCBOR(const char *szTestNames[], 57 | OutputStringCB pfOutput, 58 | void *pOutCtx, 59 | int *pNumTestsRun); 60 | 61 | 62 | /** 63 | @brief Print sizes of encoder-decoder contexts. 64 | 65 | @param[in] pfOutput Function that is called to output text strings. 66 | @param[in] pOutCtx Context pointer passed to output function. 67 | */ 68 | void PrintSizesQCBOR(OutputStringCB pfOutput, void *pOutCtx); 69 | 70 | -------------------------------------------------------------------------------- /test/UsefulBuf_Tests.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | * Copyright (c) 2016-2018, The Linux Foundation. 3 | * Copyright (c) 2018, Laurence Lundblade. 4 | * Copyright (c) 2021, Arm Limited. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are 9 | * met: 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above 13 | * copyright notice, this list of conditions and the following 14 | * disclaimer in the documentation and/or other materials provided 15 | * with the distribution. 16 | * * Neither the name of The Linux Foundation nor the names of its 17 | * contributors, nor the name "Laurence Lundblade" may be used to 18 | * endorse or promote products derived from this software without 19 | * specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 31 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * ========================================================================= */ 33 | 34 | #ifndef UsefulBuf_UsefulBuf_Tests_h 35 | #define UsefulBuf_UsefulBuf_Tests_h 36 | 37 | const char * UOBTest_NonAdversarial(void); 38 | 39 | const char * TestBasicSanity(void); 40 | 41 | const char * UOBTest_BoundaryConditionsTest(void); 42 | 43 | const char * UBMacroConversionsTest(void); 44 | 45 | const char * UBUtilTests(void); 46 | 47 | const char * UIBTest_IntegerFormat(void); 48 | 49 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 50 | const char * UBUTest_CopyUtil(void); 51 | #endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ 52 | 53 | const char * UBAdvanceTest(void); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | # Fan out for the two compilers 6 | # Fan out disabling on feature at a time -- too slow to do the full combo fan out 7 | jobs: 8 | main: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | c-compiler: [gcc, clang] 13 | 14 | ifdef: ["", -DQCBOR_DISABLE_NON_INTEGER_LABELS, -DQCBOR_DISABLE_TAGS, 15 | -DUSEFULBUF_DISABLE_ALL_FLOAT, -DQCBOR_DISABLE_FLOAT_HW_USE, 16 | -DQCBOR_DISABLE_PREFERRED_FLOAT, -DQCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, 17 | -DQCBOR_DISABLE_ENCODE_USAGE_GUARDS, -DQCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS, 18 | -DQCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS ] 19 | 20 | config: 21 | - os-image: ubuntu-latest 22 | container: ubuntu:22.04 23 | 24 | name: ${{ matrix.ifdef }} • ${{ matrix.c-compiler }} • ${{ matrix.config.container }} 25 | 26 | runs-on: ${{ matrix.config.os-image }} 27 | container: ${{ matrix.config.container }} 28 | 29 | steps: 30 | - uses: actions/checkout@v3 31 | 32 | - name: Install build tools 33 | run: | 34 | set -ex 35 | export DEBIAN_FRONTEND=noninteractive 36 | apt-get update 37 | apt-get install -y build-essential cmake ${{ matrix.c-compiler }} 38 | echo "CC=${{ matrix.c-compiler }}" >> $GITHUB_ENV 39 | 40 | 41 | - name: Build QCBOR 42 | run: | 43 | set -ex 44 | make warn CMD_LINE=${{ matrix.ifdef }} 45 | 46 | - name: Run tests 47 | run: ./qcbortest 48 | 49 | msvc: 50 | name: ${{ matrix.ifdef }} • msvc • windows-latest 51 | runs-on: windows-latest 52 | 53 | strategy: 54 | fail-fast: false 55 | matrix: 56 | 57 | ifdef: ["", -DQCBOR_DISABLE_NON_INTEGER_LABELS, -DQCBOR_DISABLE_TAGS, 58 | -DUSEFULBUF_DISABLE_ALL_FLOAT, -DQCBOR_DISABLE_FLOAT_HW_USE, 59 | -DQCBOR_DISABLE_PREFERRED_FLOAT, -DQCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, 60 | -DQCBOR_DISABLE_ENCODE_USAGE_GUARDS, -DQCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS, 61 | -DQCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS ] 62 | 63 | env: 64 | ARCH: x64 65 | 66 | steps: 67 | - uses: actions/checkout@v4 68 | 69 | # Optional: ensures Dev Cmd environment; the VS generator usually finds MSVC without this, 70 | # but keeping it makes detection deterministic. 71 | - name: Set up MSVC DevCmd 72 | uses: ilammy/msvc-dev-cmd@v1 73 | with: 74 | arch: ${{ env.ARCH }} 75 | 76 | - name: Configure (CMake → VS solution) 77 | shell: bash 78 | run: | 79 | cmake -S . -B build -DBUILD_QCBOR_TEST=APP \ 80 | -G "Visual Studio 17 2022" -A ${{ env.ARCH }} \ 81 | -DCMAKE_C_FLAGS="${{ matrix.ifdef }}" \ 82 | -DCMAKE_CXX_FLAGS="${{ matrix.ifdef }}" 83 | 84 | - name: Build 85 | run: cmake --build build 86 | shell: pwsh 87 | 88 | - name: Run tests 89 | shell: pwsh 90 | run: | 91 | $exe = "build/test/Debug/qcbortest.exe" 92 | if (!(Test-Path $exe)) { 93 | Write-Error "Test binary not found: $exe" 94 | } 95 | & $exe 96 | 97 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # Copyright (c) 2022-2023, Arm Limited. All rights reserved. 3 | # Copyright (c) 2025, Laurence Lundblade All rights reserved. 4 | # 5 | # SPDX-License-Identifier: BSD-3-Clause 6 | # 7 | # See BSD-3-Clause license in README.md 8 | #------------------------------------------------------------------------------- 9 | 10 | cmake_minimum_required(VERSION 3.15) 11 | 12 | project(qcbor 13 | DESCRIPTION "QCBOR" 14 | LANGUAGES C 15 | VERSION 1.6 16 | ) 17 | 18 | set(BUILD_QCBOR_TEST "OFF" CACHE STRING "Build QCBOR test suite [OFF, LIB, APP]") 19 | set(BUILD_QCBOR_WARN OFF CACHE BOOL "Compile with the warning flags used in the QCBOR release process") 20 | # BUILD_SHARED_LIBS is a built-in global CMake flag 21 | # The shared library is not made by default because of platform 22 | # variability For example MacOS and Linux behave differently and some 23 | # IoT OS's don't support them at all. 24 | set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries instead of static ones") 25 | 26 | # Configuration: 27 | # Floating-point support (see README.md for more information) 28 | set(QCBOR_OPT_DISABLE_FLOAT_HW_USE OFF CACHE BOOL "Eliminate dependency on FP hardware and FP instructions") 29 | set(QCBOR_OPT_DISABLE_FLOAT_PREFERRED OFF CACHE BOOL "Eliminate support for half-precision and CBOR preferred serialization") 30 | set(QCBOR_OPT_DISABLE_FLOAT_ALL OFF CACHE BOOL "Eliminate floating-point support completely") 31 | 32 | if (BUILD_QCBOR_WARN) 33 | # Compile options applying to all targets in current directory and below 34 | add_compile_options(-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual) 35 | endif() 36 | 37 | add_library(qcbor) 38 | 39 | target_sources(qcbor 40 | PRIVATE 41 | src/ieee754.c 42 | src/qcbor_decode.c 43 | src/qcbor_encode.c 44 | src/qcbor_err_to_str.c 45 | src/UsefulBuf.c 46 | ) 47 | 48 | target_include_directories(qcbor 49 | PUBLIC 50 | inc 51 | PRIVATE 52 | src 53 | ) 54 | 55 | target_compile_definitions(qcbor 56 | PRIVATE 57 | $<$:QCBOR_DISABLE_FLOAT_HW_USE> 58 | $<$:QCBOR_DISABLE_PREFERRED_FLOAT> 59 | $<$:USEFULBUF_DISABLE_ALL_FLOAT> 60 | ) 61 | 62 | if (BUILD_SHARED_LIBS) 63 | target_compile_options(qcbor PRIVATE -Os -fPIC) 64 | endif() 65 | 66 | # The math library is needed for floating-point support. 67 | # To avoid need for it #define QCBOR_DISABLE_FLOAT_HW_USE 68 | if (CMAKE_C_COMPILER_ID STREQUAL "GNU") 69 | # Using GCC 70 | target_link_libraries(qcbor 71 | PRIVATE 72 | $<$>:m> 73 | ) 74 | endif() 75 | 76 | set(HEADERS 77 | inc/qcbor/qcbor.h 78 | inc/qcbor/qcbor_common.h 79 | inc/qcbor/qcbor_private.h 80 | inc/qcbor/qcbor_encode.h 81 | inc/qcbor/qcbor_decode.h 82 | inc/qcbor/qcbor_spiffy_decode.h 83 | inc/qcbor/UsefulBuf.h 84 | ) 85 | set_target_properties( 86 | qcbor PROPERTIES 87 | VERSION ${PROJECT_VERSION} 88 | SOVERSION ${PROJECT_VERSION_MAJOR} 89 | PUBLIC_HEADER "${HEADERS}" 90 | ) 91 | include(GNUInstallDirs) 92 | install( 93 | TARGETS qcbor 94 | PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/qcbor" 95 | ) 96 | 97 | if (NOT BUILD_QCBOR_TEST STREQUAL "OFF") 98 | enable_testing() 99 | add_subdirectory(test) 100 | endif() 101 | -------------------------------------------------------------------------------- /src/qcbor_err_to_str.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | * err_to_str.c -- strings names for errors 3 | * 4 | * Copyright (c) 2020, Patrick Uiterwijk. All rights reserved. 5 | * Copyright (c) 2020,2024, Laurence Lundblade. 6 | * Copyright (c) 2021, Arm Limited. All rights reserved. 7 | * 8 | * SPDX-License-Identifier: BSD-3-Clause 9 | * 10 | * See BSD-3-Clause license in file named "LICENSE" 11 | * 12 | * Created on 3/21/20 13 | * ========================================================================== */ 14 | 15 | #include "qcbor/qcbor_common.h" 16 | #include "UsefulBuf.h" 17 | 18 | #define ERR_TO_STR_CASE(errpart) case errpart: return #errpart; 19 | 20 | 21 | const char * 22 | qcbor_err_to_str(const QCBORError uErr) { 23 | switch (uErr) { 24 | ERR_TO_STR_CASE(QCBOR_SUCCESS) 25 | ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_SMALL) 26 | ERR_TO_STR_CASE(QCBOR_ERR_ENCODE_UNSUPPORTED) 27 | ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_LARGE) 28 | ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) 29 | ERR_TO_STR_CASE(QCBOR_ERR_CLOSE_MISMATCH) 30 | ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_TOO_LONG) 31 | ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_CLOSES) 32 | ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) 33 | ERR_TO_STR_CASE(QCBOR_ERR_OPEN_BYTE_STRING) 34 | ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_CANCEL) 35 | ERR_TO_STR_CASE(QCBOR_ERR_BAD_TYPE_7) 36 | ERR_TO_STR_CASE(QCBOR_ERR_EXTRA_BYTES) 37 | ERR_TO_STR_CASE(QCBOR_ERR_UNSUPPORTED) 38 | ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) 39 | ERR_TO_STR_CASE(QCBOR_ERR_BAD_INT) 40 | ERR_TO_STR_CASE(QCBOR_ERR_INDEFINITE_STRING_CHUNK) 41 | ERR_TO_STR_CASE(QCBOR_ERR_HIT_END) 42 | ERR_TO_STR_CASE(QCBOR_ERR_BAD_BREAK) 43 | ERR_TO_STR_CASE(QCBOR_ERR_INPUT_TOO_LARGE) 44 | ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) 45 | ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_TOO_LONG) 46 | ERR_TO_STR_CASE(QCBOR_ERR_STRING_TOO_LONG) 47 | ERR_TO_STR_CASE(QCBOR_ERR_BAD_EXP_AND_MANTISSA) 48 | ERR_TO_STR_CASE(QCBOR_ERR_NO_STRING_ALLOCATOR) 49 | ERR_TO_STR_CASE(QCBOR_ERR_STRING_ALLOCATE) 50 | ERR_TO_STR_CASE(QCBOR_ERR_MAP_LABEL_TYPE) 51 | ERR_TO_STR_CASE(QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) 52 | ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED) 53 | ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) 54 | ERR_TO_STR_CASE(QCBOR_ERR_TAGS_DISABLED) 55 | ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_TAGS) 56 | ERR_TO_STR_CASE(QCBOR_ERR_UNEXPECTED_TYPE) 57 | ERR_TO_STR_CASE(QCBOR_ERR_DUPLICATE_LABEL) 58 | ERR_TO_STR_CASE(QCBOR_ERR_MEM_POOL_SIZE) 59 | ERR_TO_STR_CASE(QCBOR_ERR_INT_OVERFLOW) 60 | ERR_TO_STR_CASE(QCBOR_ERR_DATE_OVERFLOW) 61 | ERR_TO_STR_CASE(QCBOR_ERR_EXIT_MISMATCH) 62 | ERR_TO_STR_CASE(QCBOR_ERR_NO_MORE_ITEMS) 63 | ERR_TO_STR_CASE(QCBOR_ERR_LABEL_NOT_FOUND) 64 | ERR_TO_STR_CASE(QCBOR_ERR_NUMBER_SIGN_CONVERSION) 65 | ERR_TO_STR_CASE(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) 66 | ERR_TO_STR_CASE(QCBOR_ERR_MAP_NOT_ENTERED) 67 | ERR_TO_STR_CASE(QCBOR_ERR_CALLBACK_FAIL) 68 | ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_DATE_DISABLED) 69 | ERR_TO_STR_CASE(QCBOR_ERR_HALF_PRECISION_DISABLED) 70 | ERR_TO_STR_CASE(QCBOR_ERR_HW_FLOAT_DISABLED) 71 | ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_EXCEPTION) 72 | ERR_TO_STR_CASE(QCBOR_ERR_ALL_FLOAT_DISABLED) 73 | ERR_TO_STR_CASE(QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT) 74 | ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) 75 | 76 | default: 77 | if(uErr >= QCBOR_ERR_FIRST_USER_DEFINED && uErr <= QCBOR_ERR_LAST_USER_DEFINED) { 78 | /* Static buffer is not thread safe, but this is only a diagnostic */ 79 | static char buf[20]; 80 | UsefulOutBuf OB; 81 | 82 | /* Make NULL-terminated string "USER_DEFINED_NNN" using UsefulOutBuf */ 83 | UsefulOutBuf_Init(&OB, UsefulBuf_FROM_BYTE_ARRAY(buf)); 84 | UsefulOutBuf_AppendString(&OB, "USER_DEFINED_"); 85 | UsefulOutBuf_AppendByte(&OB, (uint8_t)(uErr/100 + '0')); 86 | UsefulOutBuf_AppendByte(&OB, (uint8_t)(((uErr/10) % 10) + '0')); 87 | UsefulOutBuf_AppendByte(&OB, (uint8_t)(((uErr/10) % 10) + '0')); 88 | UsefulOutBuf_AppendByte(&OB, 0x00); 89 | 90 | return buf; 91 | } else { 92 | return "Unidentified QCBOR error"; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile -- UNIX-style make for qcbor as a lib and command line test 2 | # 3 | # Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. 4 | # 5 | # SPDX-License-Identifier: BSD-3-Clause 6 | # 7 | # See BSD-3-Clause license in README.md 8 | # 9 | 10 | 11 | # The math library is needed for floating-point support. To 12 | # avoid need for it #define QCBOR_DISABLE_FLOAT_HW_USE 13 | LIBS=-lm 14 | 15 | 16 | # The QCBOR makefile uses a minimum of compiler flags so that it will 17 | # work out-of-the-box with a wide variety of compilers. For example, 18 | # some compilers error out on some of the warnings flags gcc supports. 19 | # The $(CMD_LINE) variable allows passing in extra flags. This is 20 | # used on the stringent build script that is in 21 | # https://github.com/laurencelundblade/qdv. This script is used 22 | # before pushes to master (though not yet through an automated build 23 | # process). See "warn:" below. 24 | CFLAGS=$(CMD_LINE) -I inc -I test -Os -fPIC 25 | 26 | 27 | QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o src/qcbor_err_to_str.o 28 | 29 | TEST_OBJ=test/UsefulBuf_Tests.o test/qcbor_encode_tests.o \ 30 | test/qcbor_decode_tests.o test/run_tests.o \ 31 | test/float_tests.o test/half_to_double_from_rfc7049.o example.o ub-example.o 32 | 33 | .PHONY: all so install uninstall clean warn 34 | 35 | all: qcbortest libqcbor.a 36 | 37 | so: libqcbor.so 38 | 39 | qcbortest: libqcbor.a $(TEST_OBJ) cmd_line_main.o 40 | $(CC) -o $@ $^ libqcbor.a $(LIBS) 41 | 42 | libqcbor.a: $(QCBOR_OBJ) 43 | ar -r $@ $^ 44 | 45 | # run "make warn" as a handy way to compile with the warning flags 46 | # used in the QCBOR release process. See CFLAGS above. 47 | warn: 48 | make CMD_LINE="$(CMD_LINE) -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual" 49 | 50 | 51 | # The shared library is not made by default because of platform 52 | # variability For example MacOS and Linux behave differently and some 53 | # IoT OS's don't support them at all. 54 | libqcbor.so: $(QCBOR_OBJ) 55 | $(CC) -shared $^ $(CFLAGS) -o $@ 56 | 57 | PUBLIC_INTERFACE=inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_encode.h inc/qcbor/qcbor_decode.h inc/qcbor/qcbor_spiffy_decode.h 58 | 59 | src/UsefulBuf.o: inc/qcbor/UsefulBuf.h 60 | src/qcbor_decode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_decode.h inc/qcbor/qcbor_spiffy_decode.h src/ieee754.h 61 | src/qcbor_encode.o: inc/qcbor/UsefulBuf.h inc/qcbor/qcbor_private.h inc/qcbor/qcbor_common.h inc/qcbor/qcbor_encode.h src/ieee754.h 62 | src/iee754.o: src/ieee754.h 63 | src/qcbor_err_to_str.o: inc/qcbor/qcbor_common.h 64 | 65 | example.o: $(PUBLIC_INTERFACE) 66 | ub-example.o: $(PUBLIC_INTERFACE) 67 | 68 | test/run_tests.o: test/UsefulBuf_Tests.h test/float_tests.h test/run_tests.h test/qcbor_encode_tests.h test/qcbor_decode_tests.h inc/qcbor/qcbor_private.h 69 | test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor/UsefulBuf.h 70 | test/qcbor_encode_tests.o: test/qcbor_encode_tests.h $(PUBLIC_INTERFACE) 71 | test/qcbor_decode_tests.o: test/qcbor_decode_tests.h $(PUBLIC_INTERFACE) 72 | test/float_tests.o: test/float_tests.h test/half_to_double_from_rfc7049.h $(PUBLIC_INTERFACE) 73 | test/half_to_double_from_rfc7049.o: test/half_to_double_from_rfc7049.h 74 | 75 | cmd_line_main.o: test/run_tests.h $(PUBLIC_INTERFACE) 76 | 77 | 78 | ifeq ($(PREFIX),) 79 | PREFIX := /usr/local 80 | endif 81 | 82 | install: libqcbor.a $(PUBLIC_INTERFACE) 83 | install -d $(DESTDIR)$(PREFIX)/lib/ 84 | install -m 644 libqcbor.a $(DESTDIR)$(PREFIX)/lib/ 85 | install -d $(DESTDIR)$(PREFIX)/include/qcbor 86 | install -m 644 inc/qcbor/qcbor.h $(DESTDIR)$(PREFIX)/include/qcbor 87 | install -m 644 inc/qcbor/qcbor_private.h $(DESTDIR)$(PREFIX)/include/qcbor 88 | install -m 644 inc/qcbor/qcbor_common.h $(DESTDIR)$(PREFIX)/include/qcbor 89 | install -m 644 inc/qcbor/qcbor_decode.h $(DESTDIR)$(PREFIX)/include/qcbor 90 | install -m 644 inc/qcbor/qcbor_spiffy_decode.h $(DESTDIR)$(PREFIX)/include/qcbor 91 | install -m 644 inc/qcbor/qcbor_encode.h $(DESTDIR)$(PREFIX)/include/qcbor 92 | install -m 644 inc/qcbor/UsefulBuf.h $(DESTDIR)$(PREFIX)/include/qcbor 93 | 94 | install_so: libqcbor.so 95 | install -m 755 libqcbor.so $(DESTDIR)$(PREFIX)/lib/libqcbor.so.1.0.0 96 | ln -sf libqcbor.so.1 $(DESTDIR)$(PREFIX)/lib/libqcbor.so 97 | ln -sf libqcbor.so.1.0.0 $(DESTDIR)$(PREFIX)/lib/libqcbor.so.1 98 | 99 | uninstall: libqcbor.a $(PUBLIC_INTERFACE) 100 | $(RM) -d $(DESTDIR)$(PREFIX)/include/qcbor/* 101 | $(RM) -d $(DESTDIR)$(PREFIX)/include/qcbor/ 102 | $(RM) $(addprefix $(DESTDIR)$(PREFIX)/lib/, \ 103 | libqcbor.a libqcbor.so libqcbor.so.1 libqcbor.so.1.0.0) 104 | 105 | clean: 106 | rm -f $(QCBOR_OBJ) $(TEST_OBJ) libqcbor.a cmd_line_main.o libqcbor.a libqcbor.so qcbormin qcbortest 107 | -------------------------------------------------------------------------------- /src/ieee754.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | * ieee754.h -- Conversion between half, double & single-precision floats 3 | * 4 | * Copyright (c) 2018-2025, Laurence Lundblade. All rights reserved. 5 | * 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | * 8 | * See BSD-3-Clause license in file named "LICENSE" 9 | * 10 | * Created on 7/23/18 11 | * ========================================================================== */ 12 | 13 | #ifndef QCBOR_DISABLE_PREFERRED_FLOAT 14 | 15 | #ifndef ieee754_h 16 | #define ieee754_h 17 | 18 | #include 19 | 20 | 21 | /** @file ieee754.h 22 | * 23 | * This implements floating-point conversion between half, single and 24 | * double precision floating-point numbers, in particular conversion to 25 | * smaller representation (e.g., double to single) that does not lose 26 | * precision for CBOR preferred serialization. 27 | * 28 | * This implementation works entirely with shifts and masks and does 29 | * not require any floating-point HW or library. 30 | * 31 | * This conforms to IEEE 754-2008, but note that it doesn't specify 32 | * conversions, just the encodings. 33 | * 34 | * This is complete, supporting +/- infinity, +/- zero, subnormals and 35 | * NaN payloads. NaN significands, which contain the NaN payload, are 36 | * shortened by dropping the right most bits if they are zero and 37 | * shifting to the right. If the rightmost bits are not zero the 38 | * shortening is not performed. When converting from smaller to 39 | * larger, the significand is shifted left and zero-padded. This is 40 | * what is specified by CBOR preferred serialization. There is no 41 | * special handling of silent and quiet NaNs. They are treated as 42 | * part of the significand. 43 | * 44 | * A previous version of this was usable as a general library for 45 | * conversion. This version is reduced to what is needed for CBOR. 46 | */ 47 | 48 | 49 | /** 50 | * @brief Convert half-precision float to double-precision float. 51 | * 52 | * @param[in] uHalfPrecision Half-precision number to convert. 53 | * 54 | * @returns double-precision value. 55 | * 56 | * This is a lossless conversion because every half-precision value 57 | * can be represented as a double. There is no error condition. 58 | * 59 | * There is no half-precision type in C, so it is represented here as 60 | * a @c uint16_t. The bits of @c uHalfPrecision are as described for 61 | * half-precision by IEEE 754. 62 | */ 63 | double 64 | IEEE754_HalfToDouble(uint16_t uHalfPrecision); 65 | 66 | 67 | /** 68 | * @brief Convert single-precision float to double-precision float. 69 | * 70 | * @param[in] uSingle float bits copied to a uint32_t. 71 | * 72 | * @returns double-precision value. 73 | * 74 | * This is a lossless conversion because every single-precision value 75 | * can be represented as a double. There is no error condition. 76 | * 77 | * This is in lieu of a cast that usually results in CPU instructions 78 | * that convert. These instructions don't reliably handle NaN payloads. 79 | * This does. 80 | */ 81 | double 82 | IEEE754_SingleToDouble(uint32_t uSingle); 83 | 84 | 85 | /** Holds a floating-point value that could be half, single or 86 | * double-precision. The value is in a @c uint64_t that may be copied 87 | * to a float or double. Simply casting uValue will usually work but 88 | * may generate compiler or static analyzer warnings. Using 89 | * UsefulBufUtil_CopyUint64ToDouble() or 90 | * UsefulBufUtil_CopyUint32ToFloat() will not (and will not generate 91 | * any extra code). 92 | */ 93 | typedef struct { 94 | enum {IEEE754_UNION_IS_HALF = 2, 95 | IEEE754_UNION_IS_SINGLE = 4, 96 | IEEE754_UNION_IS_DOUBLE = 8, 97 | } uSize; /* Size of uValue */ 98 | uint64_t uValue; 99 | } IEEE754_union; 100 | 101 | 102 | /** 103 | * @brief Convert a double to either single or half-precision. 104 | * 105 | * @param[in] d The value to convert. 106 | * @param[in] bAllowHalfPrecision If true, convert to either half or 107 | * single precision. 108 | * 109 | * @returns Unconverted value, or value converted to single or half-precision. 110 | * 111 | * This always succeeds. If the value cannot be converted without the 112 | * loss of precision, it is not converted. 113 | * 114 | * This handles all subnormals and NaN payloads. 115 | */ 116 | IEEE754_union 117 | IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision); 118 | 119 | 120 | /** 121 | * @brief Convert a single-precision float to half-precision. 122 | * 123 | * @param[in] f The value to convert. 124 | * 125 | * @returns Either unconverted value or value converted to half-precision. 126 | * 127 | * This always succeeds. If the value cannot be converted without the 128 | * loss of precision, it is not converted. 129 | * 130 | * This handles all subnormals and NaN payloads. 131 | */ 132 | IEEE754_union 133 | IEEE754_SingleToHalf(float f); 134 | 135 | 136 | #endif /* ieee754_h */ 137 | 138 | #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ 139 | -------------------------------------------------------------------------------- /doc/TimeTag1FAQ.md: -------------------------------------------------------------------------------- 1 | 2 | # Tag 1 Implementator’s FAQ 3 | 4 | +-------------------------------+---------------------+------------------------+ 5 | | | 1 second resolution | microsecond resolution | 6 | +-------------------------------+---------------------+------------------------+ 7 | | Recent Human Time Scale | 32-bit unsigned | double | 8 | | 1970 - 2106 | | | 9 | +-------------------------------+---------------------+------------------------+ 10 | | Recent Human Past | 32-bit negative | double | 11 | | 1834 - 1970 | | | 12 | +-------------------------------+---------------------+------------------------+ 13 | | Universal Scale, Now & Future | 64-bit unsigned | double | 14 | | 1970 - 500 billion years | | | 15 | +-------------------------------+---------------------+------------------------+ 16 | | Universal Scale, Past | 64-bit negative | double | 17 | | 500 billion years ago - 1969 | | | 18 | +-------------------------------+---------------------+------------------------+ 19 | 20 | 21 | Q: I just want to implement the minimum, what should I do? 22 | A: You should support 64-bit unsigned encoding. This will cover just about every use case because it works from 1970 until over 500 billion years in the future and 1 second resolution is enough for most human activity. The earth is only 4.5 billion years old. Note that time values up to 2106 will be encoded as 32-bit integers even though 64-bit integers are supported because only 32-bits are needed to count seconds up to the year 2106. 23 | 24 | Q: I’m implementing on an 8-bit CPU and 64-bit integers are really a problem. 25 | A: You can support just 32-bit integers, but they will stop working in 2106. 26 | 27 | Q: Why 2106 and not 2038? 28 | A: Because CBOR encodes positive and negative integers with different major types and thus is able to use the full 32-bits for positive integers. 29 | 30 | Q: What if I need time values before 1970? 31 | A: Implement 64 or 32-bit negative time values, but note that there is no clear standard for this as POSIX and UTC time are not defined for this time period. If your implementation assumes every days is 86,400 seconds and follow the rules for leap years, you should have accuracy to within hours, if not minutes. 32 | 33 | Q: Is Tag 1 better than Tag 0 for time values? 34 | A: In a lot of ways it is, because it is just a simple integer. It takes up a lot less space. It is a lot simpler to parse. Most OS’s have the ability to turn POSIX time into a structure of month, day, year, hour, minute and second. Note however that POSIX time has a discontinuity of about once every year for leap second adjustment. 35 | 36 | Q: What is a leap second? 37 | A: It actually takes the earth about 1 year and 1 second to revolve around the sun, so 1 extra second has to be added almost every year. UTC Time handles this by counting the seconds from 0-60 (not 0-59) in the last minute of the year. This standard uses POSIX time which can be said to handle this by the clock stopping for 1 second in the last minute of the year. 38 | 39 | Q: Do I have to implement floating point time? 40 | A: No. There are not many use cases that need it. However, for maximal interoperability, it is good to support it. 41 | 42 | Q: When should I use floating point? 43 | A: Only if you need time resolution greater than one second. There is no benefit otherwise. 64-bit time can represent time +/-500 billion years in the same number of bits, so floating point time is unnecessary for very large times scales. 44 | 45 | Q: What resolution do I get with floating point? 46 | A: It varies over the years. For 1970 to 1971 you get almost nanosecond accuracy. For the current century, 2000-2099, you get microsecond accuracy. 285 million years from now, it will be less than a second and the 64-bit unsigned representation will have more resolution. This is because a double only has 52 bits of resolution. 47 | 48 | Q: Should I implement single or double floating point? 49 | A: If you are going to use floating point you should always implement double. Single has no advantage over 32-bit integers. It provides less range and less precision. It has only 23 bits of resolution. It is of course good to support decoding of single in case someone sends you one, but there no point to ever sending a tag 1 encoded time value as a single. 50 | 51 | Q: Can I disallow floating point time in the definition of my protocol? 52 | A: Yes. This is a good idea if you do not need resolution less than one second. It will make implementations simpler and more compact. Note that while most CPUs do support IEEE 754 floating point, particularly small ones do not. 53 | 54 | Q: What if I’m transmitting thousands of time stamps and space is a problem? 55 | A: If you want to maintain 1 second resolution, there is really no more compact way to transmit time than tag 1 with 32-bit or 64-bit integer. If you wish reduce resolution, use a different time, perhaps one that counts days rather than seconds. 56 | 57 | -------------------------------------------------------------------------------- /test/qcbor_encode_tests.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | Copyright (c) 2016-2018, The Linux Foundation. 3 | Copyright (c) 2018-2022, Laurence Lundblade. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | * Neither the name of The Linux Foundation nor the names of its 16 | contributors, nor the name "Laurence Lundblade" may be used to 17 | endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 21 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 24 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 30 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | =============================================================================*/ 32 | 33 | #ifndef __QCBOR__qcbor_encode_tests__ 34 | #define __QCBOR__qcbor_encode_tests__ 35 | 36 | #include 37 | 38 | /* 39 | Notes: 40 | 41 | - All the functions in qcbor_encode.h are called once in the aggregation of all 42 | the tests below. 43 | 44 | */ 45 | 46 | 47 | /* 48 | Most basic test. 49 | */ 50 | int32_t BasicEncodeTest(void); 51 | 52 | 53 | /* 54 | Encode lots of integer values, particularly around the boundary and 55 | make sure they Match the expected binary output. Primarily an 56 | encoding test. 57 | */ 58 | int32_t IntegerValuesTest1(void); 59 | 60 | 61 | /* 62 | Create nested arrays to the max depth allowed and make sure it 63 | succeeds. This is an encoding test. 64 | */ 65 | int32_t ArrayNestingTest1(void); 66 | 67 | 68 | /* 69 | Create nested arrays to one more than the meax depth and make sure it 70 | fails. This is an encoding test. 71 | */ 72 | int32_t ArrayNestingTest2(void); 73 | 74 | 75 | /* 76 | Encoding test. Create arrays to max depth and close one extra time 77 | and look for correct error code 78 | */ 79 | int32_t ArrayNestingTest3(void); 80 | 81 | 82 | /* 83 | This tests the QCBOREncode_AddRaw() function by adding two chunks of 84 | raw CBOR to an array and comparing with expected values. 85 | */ 86 | int32_t EncodeRawTest(void); 87 | 88 | 89 | /* 90 | This creates a somewhat complicated CBOR MAP and verifies it against 91 | expected data. This is an encoding test. 92 | */ 93 | int32_t MapEncodeTest(void); 94 | 95 | 96 | /* 97 | Encodes a goodly number of floats and doubles and checks encoding is right 98 | */ 99 | int32_t FloatValuesTest1(void); 100 | 101 | 102 | /* 103 | Encodes true, false and the like 104 | */ 105 | int32_t SimpleValuesTest1(void); 106 | 107 | 108 | /* 109 | Encodes basic maps and arrays with indefinite length 110 | */ 111 | int32_t IndefiniteLengthTest(void); 112 | 113 | 114 | /* 115 | Indefinite length arrays and maps use the 'magic' number 31, verify 116 | that everything with length 31 still works properly 117 | */ 118 | int32_t EncodeLengthThirtyoneTest(void); 119 | 120 | 121 | /* 122 | * Tests Encoding most data formats that are supported. 123 | */ 124 | int32_t EncodeDateTest(void); 125 | 126 | 127 | /* 128 | Encodes particular data structure that a particular app will need... 129 | */ 130 | int32_t RTICResultsTest(void); 131 | 132 | 133 | /* 134 | Calls all public encode methods in qcbor_encode.h once. 135 | */ 136 | int32_t AllAddMethodsTest(void); 137 | 138 | 139 | /* 140 | The binary string wrapping of maps and arrays used by COSE 141 | */ 142 | int32_t BstrWrapTest(void); 143 | 144 | 145 | /* 146 | Test error cases for bstr wrapping encoding such as closing an open 147 | array with CloseBstrWrap 148 | */ 149 | int32_t BstrWrapErrorTest(void); 150 | 151 | 152 | /* 153 | Test complicated nested bstr wrapping 154 | */ 155 | int32_t BstrWrapNestTest(void); 156 | 157 | 158 | /* 159 | Test encoding a COSE_Sign1 with bstr wrapping 160 | */ 161 | int32_t CoseSign1TBSTest(void); 162 | 163 | 164 | #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA 165 | /* 166 | Test encoding of decimal fractions and big floats, both of which are 167 | made up of an exponent and mantissa 168 | */ 169 | int32_t ExponentAndMantissaEncodeTests(void); 170 | #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ 171 | 172 | 173 | /* 174 | Test the error cases when encoding CBOR such as buffer too large, 175 | buffer too small, array nesting too deep. Aims to cover the error 176 | codes returned when encoding CBOR 177 | */ 178 | int32_t EncodeErrorTests(void); 179 | 180 | 181 | /* 182 | Test QCBOREncode_EncodeHead(). This is a minimal test because every other 183 | test here exercises it in some way. 184 | */ 185 | int32_t QCBORHeadTest(void); 186 | 187 | 188 | /* Fully test QCBOREncode_OpenBytes(), QCBOREncode_CloseBytes() 189 | * and friends. 190 | */ 191 | int32_t OpenCloseBytesTest(void); 192 | 193 | 194 | int32_t SubStringTest(void); 195 | 196 | 197 | #endif /* defined(__QCBOR__qcbor_encode_tests__) */ 198 | -------------------------------------------------------------------------------- /test/qcbor_decode_tests.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | Copyright (c) 2016-2018, The Linux Foundation. 3 | Copyright (c) 2018-2021, Laurence Lundblade. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | * Neither the name of The Linux Foundation nor the names of its 16 | contributors, nor the name "Laurence Lundblade" may be used to 17 | endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 21 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 24 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 30 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | ============================================================================*/ 32 | 33 | #ifndef __QCBOR__qcbort_decode_tests__ 34 | #define __QCBOR__qcbort_decode_tests__ 35 | 36 | #include 37 | 38 | /* 39 | Notes: 40 | 41 | - All the functions in qcbor_decode.h are called once in the aggregation 42 | of all the tests below. 43 | 44 | - All the types that are supported are given as input and parsed by these tests 45 | 46 | - There is some hostile input such as invalid lengths and CBOR too complex 47 | and types this parser doesn't handle 48 | 49 | */ 50 | 51 | 52 | /* 53 | Parse a well-known set of integers including those around the boundaries and 54 | make sure the expected values come out 55 | */ 56 | int32_t IntegerValuesParseTest(void); 57 | 58 | 59 | /* 60 | Decode a simple CBOR encoded array and make sure it returns all the correct values. 61 | This is a decode test. 62 | */ 63 | int32_t SimpleArrayTest(void); 64 | 65 | 66 | /* 67 | Tests with empty maps and arrays 68 | */ 69 | int32_t EmptyMapsAndArraysTest(void); 70 | 71 | 72 | /* 73 | Make sure a maximally deep array can be parsed and that the 74 | reported nesting level is correct. This uses test vector 75 | of CBOR encoded data with a depth of 10. This a parse test. 76 | */ 77 | int32_t ParseDeepArrayTest(void); 78 | 79 | 80 | /* 81 | See that the correct error is reported when parsing 82 | an array of depth 11, one too large. 83 | */ 84 | int32_t ParseTooDeepArrayTest(void); 85 | 86 | 87 | /* 88 | Try to parse some legit CBOR types that this parsers 89 | doesn't support. 90 | */ 91 | int32_t UnsupportedCBORDecodeTest(void); 92 | 93 | 94 | /* 95 | This takes the encoded CBOR integers used in the above test and parses 96 | it over and over with one more byte less each time. It should fail 97 | every time on incorrect CBOR input. This is a hostile input decode test. 98 | */ 99 | int32_t ShortBufferParseTest(void); 100 | 101 | 102 | /* 103 | Same as ShortBufferParseTest, but with a different encoded CBOR input. 104 | It is another hostile input test 105 | */ 106 | int32_t ShortBufferParseTest2(void); 107 | 108 | 109 | /* 110 | Parses the somewhat complicated CBOR MAP and makes sure all the correct 111 | values parse out. About 15 values are tested. This is a decode test. 112 | */ 113 | int32_t ParseMapTest(void); 114 | 115 | /* 116 | Parses a map that contains a zero-length map as value. 117 | */ 118 | int32_t ParseEmptyMapInMapTest(void); 119 | 120 | /* 121 | Test the decoder mode where maps are treated as arrays. 122 | */ 123 | int32_t ParseMapAsArrayTest(void); 124 | 125 | 126 | /* 127 | Test parsing of some simple values like true, false, null... 128 | */ 129 | int32_t SimpleValueDecodeTests(void); 130 | 131 | 132 | /* 133 | This tests all the not-well-formed CBOR from the CBOR RFC. 134 | (This is the CBORbis RFC which is not yet published at the 135 | time this test was added). 136 | */ 137 | int32_t NotWellFormedTests(void); 138 | 139 | 140 | /* 141 | Tests a number of failure cases on bad CBOR to get the right error code 142 | */ 143 | int32_t DecodeFailureTests(void); 144 | 145 | 146 | /* 147 | Parses all possible inputs that are two bytes long. Main point 148 | is that the test doesn't crash as it doesn't evaluate the 149 | input for correctness in any way. 150 | 151 | (Parsing all possible 3 byte strings takes too long on all but 152 | very fast machines). 153 | */ 154 | int32_t ComprehensiveInputTest(void); 155 | 156 | 157 | /* 158 | Parses all possible inputs that are four bytes long. Main point 159 | is that the test doesn't crash as it doesn't evaluate the 160 | input for correctness in any way. This runs very slow, so it 161 | is only practical as a once-in-a-while regression test on 162 | fast machines. 163 | */ 164 | int32_t BigComprehensiveInputTest(void); 165 | 166 | 167 | /* 168 | Test the date types -- epoch and strings 169 | */ 170 | int32_t DateParseTest(void); 171 | 172 | 173 | /* 174 | Test spiffy date decoding functions 175 | */ 176 | int32_t SpiffyDateDecodeTest(void); 177 | 178 | 179 | /* 180 | Test decode of CBOR tagging like the CBOR magic number and many others. 181 | */ 182 | int32_t OptTagParseTest(void); 183 | 184 | 185 | /* 186 | Parse some big numbers, positive and negative 187 | */ 188 | int32_t BignumParseTest(void); 189 | 190 | 191 | /* 192 | Test of mode where only string labels are allowed 193 | */ 194 | int32_t StringDecoderModeFailTest(void); 195 | 196 | 197 | /* 198 | Parse some nested maps 199 | */ 200 | int32_t NestedMapTest(void); 201 | 202 | 203 | /* 204 | Parse maps with indefinite lengths 205 | */ 206 | int32_t NestedMapTestIndefLen(void); 207 | 208 | 209 | /* 210 | Parse some maps and arrays with indefinite lengths. 211 | Includes some error cases. 212 | */ 213 | int32_t IndefiniteLengthArrayMapTest(void); 214 | 215 | 216 | /* 217 | Parse indefinite length strings. Uses 218 | MemPool. Includes error cases. 219 | */ 220 | int32_t IndefiniteLengthStringTest(void); 221 | 222 | 223 | /* 224 | Test deep nesting of indefinite length 225 | maps and arrays including too deep. 226 | */ 227 | int32_t IndefiniteLengthNestTest(void); 228 | 229 | 230 | /* 231 | Test parsing strings were all strings, not 232 | just indefinite length strings, are 233 | allocated. Includes error test cases. 234 | */ 235 | int32_t AllocAllStringsTest(void); 236 | 237 | 238 | /* 239 | Direct test of MemPool string allocator 240 | */ 241 | int32_t MemPoolTest(void); 242 | 243 | 244 | /* 245 | Test the setting up of an external string allocator. 246 | */ 247 | int32_t SetUpAllocatorTest(void); 248 | 249 | 250 | #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA 251 | /* 252 | Test decoding of decimal fractions and big floats, both of which are 253 | made up of an exponent and mantissa. 254 | */ 255 | int32_t ExponentAndMantissaDecodeTests(void); 256 | 257 | 258 | /* 259 | Hostile input tests for decimal fractions and big floats. 260 | */ 261 | int32_t ExponentAndMantissaDecodeFailTests(void); 262 | #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ 263 | 264 | 265 | int32_t EnterMapTest(void); 266 | 267 | int32_t IntegerConvertTest(void); 268 | /* 269 | Tests decoding of CBOR Sequences defined in RFC 8742 270 | */ 271 | int32_t CBORSequenceDecodeTests(void); 272 | 273 | 274 | /* 275 | Tests for functions to safely convert integer types. 276 | */ 277 | int32_t IntToTests(void); 278 | 279 | 280 | /* 281 | Test the decoding of bstr-wrapped CBOR. 282 | */ 283 | int32_t EnterBstrTest(void); 284 | 285 | 286 | /* 287 | Test decoding of tagged types like UUID 288 | */ 289 | int32_t DecodeTaggedTypeTests(void); 290 | 291 | 292 | /* 293 | Test the detection of input that is too large. Requires 294 | a special build that makes QCBOR_MAX_DECODE_INPUT_SIZE small. 295 | */ 296 | int32_t TooLargeInputTest(void); 297 | 298 | 299 | /* 300 | Test spiffy decoding of indefinite length strings. 301 | */ 302 | int32_t SpiffyIndefiniteLengthStringsTests(void); 303 | 304 | 305 | /* 306 | Test PeekNext(). 307 | */ 308 | int32_t PeekAndRewindTest(void); 309 | 310 | 311 | /* 312 | Test decoding of booleans 313 | */ 314 | int32_t BoolTest(void); 315 | 316 | /* 317 | Test GitHub issue #134: decode an indefinite-length string with a zero-length first chunk. 318 | */ 319 | int32_t CBORTestIssue134(void); 320 | 321 | 322 | 323 | int32_t ErrorHandlingTests(void); 324 | 325 | 326 | /* 327 | * Test QCBORDecode_GetArray and QCBORDecode_GetMap 328 | */ 329 | int32_t GetMapAndArrayTest(void); 330 | 331 | int32_t TellTests(void); 332 | 333 | 334 | #endif /* defined(__QCBOR__qcbort_decode_tests__) */ 335 | -------------------------------------------------------------------------------- /ub-example.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | ub-example.c -- Example code for UsefulBuf 3 | 4 | Copyright (c) 2022, Laurence Lundblade. All rights reserved. 5 | 6 | SPDX-License-Identifier: BSD-3-Clause 7 | 8 | See BSD-3-Clause license in file named "LICENSE" 9 | 10 | Created on 4/8/22 11 | ========================================================================== */ 12 | 13 | #include "ub-example.h" 14 | 15 | #include "UsefulBuf.h" 16 | 17 | 18 | /* 19 | * A considerable number of the security issues with C code come from 20 | * mistakes made with pointers and lengths. UsefulBuf adopts a 21 | * convention that a pointer and length *always* go together to help 22 | * mitigate this. With UsefulBuf there are never pointers without 23 | * lengths, so you always know how big a buffer or some binary data 24 | * is. 25 | * 26 | * C99 allows passing structures so a structure is used. Compilers are 27 | * smart these days so the object code produced is little different 28 | * than passing two separate parameters. Passing structures also makes 29 | * the interfaces prettier. Assignments of structures also can make 30 | * code prettier. 31 | * 32 | * ALong with the UsefulBuf structure, there are a bunch of (tested!) 33 | * functions to manipulate them so code using it may have no pointer 34 | * manipulation at all. 35 | * 36 | * Constness is also a useful and desirous thing. See 37 | * https://stackoverflow.com/questions/117293/use-of-const-for-function-parameters 38 | * Keeping const distinct from non-const is helpful when reading the 39 | * code and helps avoid some coding mistakes. In this example the 40 | * buffers filled in with data are const and the ones that are 41 | * to-be-filled in are not const. 42 | * 43 | * This contrived example copies data from input to output expanding 44 | * bytes with the value 'x' to 'xx'. 45 | * 46 | * Input -- This is the pointer and length of the input, the bytes to 47 | * copy. Note that UsefulBufC.ptr is a const void * indicating that 48 | * input data won't be changed by this function. There is a "C" in 49 | * "UsefulBufC "to indicate the value is const. The length here is 50 | * the length of the valid input data. Note also that the parameter 51 | * Input is const, so this is fully const and clearly an [in] 52 | * parameter. 53 | * 54 | * OutputBuffer -- This is a pointer and length of the memory to be 55 | * used to store the output. The correct length here is critical for 56 | * code security. Note that UsefulBuf.ptr is void *, it is not const 57 | * indicating data can be written to it. Note that the parameter 58 | * itself *is* const indicating that the code below will not point 59 | * this to some other buffer or change the length and clearly marking 60 | * it as an [in] parameter. 61 | * 62 | * Output -- This is the interesting and unusual one. To stay 63 | * consistent with always pairing a length and a pointer, this is 64 | * returned as a UsefulBuC. Also, to stay consistent with valid data 65 | * being const, it is a UsefulBufC, not a UsefulBuf. It is however, an 66 | * [out] parameter so the parameter is a pointer to a UsefulBufC. 67 | * 68 | * In this case and most cases, the pointer in Output->ptr will be the 69 | * same as OutputBuffer.ptr. This may seem redundant, but there are a 70 | * few reasons for it. First, is the goal of always pairing a pointer 71 | * and a length. Second is being more strict and correct with 72 | * constness. Third is the code hygiene and clarity of having 73 | * variables for to-be-filled buffers be distinct from those 74 | * containing valid data. Fourth, there are no [in,out] parameters, 75 | * only [in] parameters and [out] parameters (the to-be-filled-in 76 | * buffer is considered an [in] parameter). 77 | * 78 | * Note that the compiler will be smart and should generate pretty 79 | * much the same code as for a traditional interface. On x86 with 80 | * gcc-11 and no stack guards, the UB code is 81 bytes and the 81 | * traditional code is 77 bytes. 82 | * 83 | * Finally, this supports computing of the length of the would-be 84 | * output without actually doing any outputting. Pass {NULL, SIZE_MAX} 85 | * for the OutputBuffer and the length will be returned in Output. 86 | */ 87 | int 88 | ExpandxUB(const UsefulBufC Input, 89 | const UsefulBuf OutputBuffer, 90 | UsefulBufC *Output) 91 | { 92 | size_t uInputPosition; 93 | size_t uOutputPosition; 94 | 95 | uOutputPosition = 0; 96 | 97 | /* Loop over all the bytes in Input */ 98 | for(uInputPosition = 0; uInputPosition < Input.len; uInputPosition++) { 99 | const uint8_t uInputByte = ((const uint8_t*)Input.ptr)[uInputPosition]; 100 | 101 | /* Copy every byte */ 102 | if(OutputBuffer.ptr != NULL) { 103 | ((uint8_t *)OutputBuffer.ptr)[uOutputPosition] = uInputByte; 104 | } 105 | uOutputPosition++; 106 | if(uOutputPosition >= OutputBuffer.len) { 107 | return -1; 108 | } 109 | 110 | /* Double output 'x' because that is what this contrived example does */ 111 | if(uInputByte== 'x') { 112 | if(OutputBuffer.ptr != NULL) { 113 | ((uint8_t *)OutputBuffer.ptr)[uOutputPosition] = 'x'; 114 | } 115 | uOutputPosition++; 116 | if(uOutputPosition >= OutputBuffer.len) { 117 | return -1; 118 | } 119 | } 120 | } 121 | 122 | *Output = (UsefulBufC){OutputBuffer.ptr, uOutputPosition}; 123 | 124 | return 0; /* success */ 125 | } 126 | 127 | 128 | /* This is the more tradional way to implement this. */ 129 | int 130 | ExpandxTraditional(const uint8_t *pInputPointer, 131 | const size_t uInputLength, 132 | uint8_t *pOutputBuffer, 133 | const size_t uOutputBufferLength, 134 | size_t *puOutputLength) 135 | { 136 | size_t uInputPosition; 137 | size_t uOutputPosition; 138 | 139 | uOutputPosition = 0; 140 | 141 | /* Loop over all the bytes in Input */ 142 | for(uInputPosition = 0; uInputPosition < uInputLength; uInputPosition++) { 143 | const uint8_t uInputByte = ((const uint8_t*)pInputPointer)[uInputPosition]; 144 | 145 | /* Copy every byte */ 146 | if(pOutputBuffer != NULL) { 147 | ((uint8_t *)pOutputBuffer)[uOutputPosition] = uInputByte; 148 | } 149 | uOutputPosition++; 150 | if(uOutputPosition >= uOutputBufferLength) { 151 | return -1; 152 | } 153 | 154 | /* Double output 'x' because that is what this contrived example does */ 155 | if(uInputByte== 'x') { 156 | if(pOutputBuffer != NULL) { 157 | ((uint8_t *)pOutputBuffer)[uOutputPosition] = 'x'; 158 | } 159 | uOutputPosition++; 160 | if(uOutputPosition >= uOutputBufferLength) { 161 | return -1; 162 | } 163 | } 164 | } 165 | 166 | *puOutputLength = uOutputPosition; 167 | 168 | return 0; /* success */ 169 | } 170 | 171 | 172 | /* 173 | * Here's an example of going from a traditional interface 174 | * interface to a UsefulBuf interface. 175 | */ 176 | int 177 | ExpandxTraditionalAdaptor(const uint8_t *pInputPointer, 178 | size_t uInputLength, 179 | uint8_t *pOutputBuffer, 180 | size_t uOutputBufferLength, 181 | size_t *puOutputLength) 182 | { 183 | UsefulBufC Input; 184 | UsefulBuf OutputBuffer; 185 | UsefulBufC Output; 186 | int nReturn; 187 | 188 | Input = (UsefulBufC){pInputPointer, uInputLength}; 189 | OutputBuffer = (UsefulBuf){pOutputBuffer, uOutputBufferLength}; 190 | 191 | nReturn = ExpandxUB(Input, OutputBuffer, &Output); 192 | 193 | *puOutputLength = Output.len; 194 | 195 | return nReturn; 196 | } 197 | 198 | 199 | /* Here's an example for going from a UsefulBuf interface 200 | to a traditional interface. */ 201 | int 202 | ExpandxUBAdaptor(const UsefulBufC Input, 203 | const UsefulBuf OutputBuffer, 204 | UsefulBufC *Output) 205 | { 206 | Output->ptr = OutputBuffer.ptr; 207 | 208 | return ExpandxTraditional(Input.ptr, Input.len, 209 | OutputBuffer.ptr, OutputBuffer.len, 210 | &(Output->len)); 211 | } 212 | 213 | 214 | 215 | #define INPUT "xyz123xyz" 216 | 217 | int32_t RunUsefulBufExample(void) 218 | { 219 | /* ------------ UsefulBuf examples ------------- */ 220 | UsefulBufC Input = UsefulBuf_FROM_SZ_LITERAL(INPUT); 221 | 222 | /* This macros makes a 20 byte buffer on the stack. It also makes 223 | * a UsefulBuf on the stack. It sets up the UsefulBuf to point to 224 | * the 20 byte buffer and sets it's length to 20 bytes. This 225 | * is the empty, to-be-filled in memory for the output. It is not 226 | * const. */ 227 | MakeUsefulBufOnStack(OutBuf, sizeof(INPUT) * 2); 228 | 229 | /* This is were the pointer and the length of the completed output 230 | * will be placed. Output.ptr is a pointer to const bytes. */ 231 | UsefulBufC Output; 232 | 233 | ExpandxUB(Input, OutBuf, &Output); 234 | 235 | ExpandxUBAdaptor(Input, OutBuf, &Output); 236 | 237 | 238 | 239 | /* ------ Get Size example -------- */ 240 | ExpandxUB(Input, (UsefulBuf){NULL, SIZE_MAX}, &Output); 241 | 242 | /* Size is in Output.len */ 243 | 244 | 245 | 246 | /* ---------- Traditional examples (for comparison) --------- */ 247 | uint8_t puBuffer[sizeof(INPUT) * 2]; 248 | size_t uOutputSize; 249 | 250 | ExpandxTraditional((const uint8_t *)INPUT, sizeof(INPUT), 251 | puBuffer, sizeof(puBuffer), 252 | &uOutputSize); 253 | 254 | 255 | ExpandxTraditionalAdaptor((const uint8_t *)INPUT, sizeof(INPUT), 256 | puBuffer, sizeof(puBuffer), 257 | &uOutputSize); 258 | 259 | return 0; 260 | } 261 | -------------------------------------------------------------------------------- /doc/Tagging.md: -------------------------------------------------------------------------------- 1 | @file Tagging.md 2 | 3 | @anchor CBORTags 4 | 5 | # Types and Tagging in CBOR 6 | 7 | ## New Types 8 | 9 | CBOR provides a means for defining new data types beyond the primitive 10 | types like integers and strings. These new types can be the simple 11 | association of some further semantics with a primitive type or they 12 | can be large complex aggregations. 13 | 14 | The explicit means for identifying these new types as called tagging. 15 | It uses a simple unsigned integer known as the tag number to indicate 16 | that the following CBOR is of that type. Officially speaking, a "tag" 17 | is made up of exactly a tag number and tag content. The tag content 18 | is exactly a single data item, but note that a single data item can be 19 | a map or an array which contains further nested maps and arrays and 20 | thus arbitrarily complex. 21 | 22 | The tag numbers can be up to UINT64_MAX, so there are a lot of them. 23 | Some defined in standards and registered in the IANA CBOR Tag 24 | Registry. A very large range is available for proprietary tags. 25 | 26 | ## Are Tags "Optional"? 27 | 28 | The description of tags in 29 | [RFC 7049] (https://tools.ietf.org/html/rfc7049) and in some other 30 | places can lead one to think they are optional prefixes that can be 31 | ignored at times. This is not true. 32 | 33 | As stated above, a tag is exactly a tag number and a single data item 34 | that is the tag content. Its purpose in the encoded CBOR is to 35 | indicate something is of a data type. Ignoring it would be like 36 | ignoring a typedef or struct in C. 37 | 38 | However, it is common in CBOR-based protocols to use the format, 39 | semantics or definition of the tag content without it actually being a 40 | *tag*. One can think of this as *borrowing* the tag content or implied 41 | type information. 42 | 43 | For example, [RFC 8392] (https://tools.ietf.org/html/rfc8392) which 44 | defines a CBOR Web Token, a CWT, says that the NumericDate field is 45 | represented as a CBOR numeric date described as tag 1 in the CBOR 46 | standard, but with the tag number 1 omitted from the encoding. A 47 | NumericDate is thus not a tag. It just borrows the content format and 48 | semantics from tag 1. 49 | 50 | This borrowing of the content makes a lot of sense for data items that 51 | are labeled members of a map where the type of the data can be easily 52 | inferred by the label and the full use of a tag with a tag number 53 | would be redundant. 54 | 55 | There is another way that tags are "optional". RFC 8392 serves again 56 | as an example. A CWT is officially defined as a COSE-secured map 57 | containing a bunch of claims where each claim is a labeled data 58 | item. This COSE-secured map-of-claims is the definition of a *CWT* and 59 | stands on its own as the definition of a protocol message. One can say 60 | that some protocol message is a *CWT* without ever mention the word 61 | tag or the *CWT Tag*. 62 | 63 | Then RFC 8392 goes on to define a *CWT Tag* as a tag with tag number 64 | of 61 and tag content being a *CWT*. The content format definition 65 | comes first and stands on it's own. 66 | 67 | To recap, the tags defined in RFC 7049 such as the date formats define 68 | the content type of the tag only in the context of the tag itself. To 69 | use the content formats outside of the tag, the content format must be 70 | borrowed. By contrast some definitions first define the content 71 | format in an independent way, then they define a tag to enclose that 72 | particular content format. A CWT is of the later sort. 73 | 74 | Finally, every CBOR protocol should explicitly spell out how it is 75 | using each tag, borrowing tag content and such. If the protocol you 76 | are trying to implement doesn't, ask the designer. Generally, 77 | protocols designs should not allow for some data item to optional be 78 | either a tag or to be the borrowed tag content. While allowing this 79 | tag optionality is a form of Postel's law, "be liberal in what you 80 | accept", current wisdom is somewhat the opposite. 81 | 82 | 83 | ## Types and Tags in QCBOR 84 | 85 | QCBOR explicitly supports all the tags defined in 86 | [RFC 7049] (https://tools.ietf.org/html/rfc7049). It has specific APIs 87 | and data structures for encoding and decoding them. 88 | 89 | These APIs and structures can support either the full and proper tag 90 | form or the borrowed content form that is not a tag. 91 | 92 | The original QCBOR APIs for encoding tags did not allow for encoding 93 | the borrowed content format. They only support the proper tag 94 | format. With spiffy decode, a second set of APIs was added that takes 95 | and argument to indicate whether the proper tag should be output or 96 | just the borrowed content format should be output. The first set are 97 | the "AddXxxx" functions and the second the "AddTXxxx" functions. 98 | 99 | When decoding with QCBORDecode_GetNext(), the non-spiffy decode API, 100 | the proper tag form is automatically recognized by the tag number and 101 | decoded into QCBORItem. This decoding API however cannot recognize 102 | borrowed content format. The caller must tell QCBOR when borrowed 103 | content format is expected. 104 | 105 | The spiffy decode APIs for the particular tags are the way the caller 106 | tells QCBOR to expect borrowed content format. These spiffy decode 107 | APIs can also decode the proper tag as well. When asked to decode a 108 | proper tag and the input CBOR is not, it is a decode validity 109 | error. These APIs take an argument which says whether to expect the 110 | proper tag or just the borrowed content. They can also be told to 111 | allow either to "be liberal in what you accept", but this is not 112 | recommended. 113 | 114 | 115 | ## Nested Tags 116 | 117 | CBOR tags are an enclosing or encapsulating format. When one tag 118 | encloses another, the enclosed tag is the content for the enclosing 119 | tag. 120 | 121 | Encoding nested tags is easy with QCBOREncode_AddTag(). Just call it 122 | several times before calling the functions to encode the tag content. 123 | 124 | When QCBOR decodes tags it does so by first completely processing the 125 | built-in tags that it knows how to process. It returns that processed 126 | item. 127 | 128 | If tags occur that QCBOR doesn't know how to process, it will return 129 | the tag content as a @ref QCBORItem and list the tags that 130 | encapsulate. The caller then has the information it needs to process 131 | tag that QCBOR did not. 132 | 133 | Nesting of tags is certainly used in CBOR protocols, but deep nesting 134 | is less common so QCBOR has an implementation limit of 4 levels of tag 135 | encapsulation on some tag content. (This can be increased by changing 136 | QCBOR_MAX_TAGS_PER_ITEM, but it will increase stack memory use by 137 | increasing the size of a QCBORItem). 138 | 139 | QCBOR also saves memory by mapping the tag values larger than 140 | UINT16_MAX, so the tags have to fetched through an accessor function. 141 | 142 | When decoding with QCBORDecode_GetNext(), the encapsulating tags are 143 | listed in the QCBORItem returned. When decoding with spiffy decoding 144 | functions the tags encapsulating the last-decoded item are saved in 145 | the decode context and have to be fetched with 146 | QCBORDecode_GetNthTagOfLast(). 147 | 148 | ## Tags for Encapsulated CBOR 149 | 150 | Tag 24 and 63 deserve special mention. The content of these tags is a 151 | byte string containing encoded CBOR. The content of tag 24 is a single 152 | CBOR data item and the content of tag 63 is a CBOR sequence, more than 153 | one data item. Said another way, with tag 24 you can have deeply 154 | nested complex structures, but the if you do the one data item must be 155 | either a map or an array or a tag that defined to be complex and 156 | nested. With tag 63, the content can be a sequence of integers not 157 | held together in a map or array. Tag 63 is defined in 158 | [RFC 8742] (https://tools.ietf.org/html/rfc8742). 159 | 160 | The point of encapsulating CBOR this way is often so it can be 161 | cryptographically signed. It works well with off-the-shelf encoders 162 | and decoders to sign and verify CBOR this way because the decoder can 163 | just get the byte string that it needs to hash in a normal way, then 164 | feed the content back into another instance of the CBOR decoder. 165 | 166 | It is also a way to break up complex CBOR structures so they can be 167 | decoded in layers. Usually, with CBOR one error will render the whole 168 | structure un-decodable because there is little redundancy in the 169 | encoding. By nesting like this, an error in the wrapped CBOR will not 170 | cause decoding error in the wrapping CBOR. 171 | 172 | QCBOR can be asked to treat these two tags as nesting like maps and 173 | arrays are nesting with the spiffy decode 174 | QCBORDecode_EnterBstrWrapped() decoding function. It is kind of like 175 | entering an array with one item, but with the difference that the end 176 | is defined by the end of the byte string not the end of the array. 177 | 178 | These tags work like others in that they can be the proper tag or they 179 | can be the borrowed content. The QCBOR API supports this as any other 180 | tag. 181 | 182 | Finally, the payload and protected headers of COSE are worth 183 | mentioning here. Neither are officially tag 24 or 63 though they look 184 | like it and QCBORs decode APIs can be used on them. 185 | 186 | The protected headers are a CBOR byte string that always contains 187 | encoded CBOR. It could have been described as tag 24 borrowed content. 188 | 189 | The payload is always a byte string, but only sometimes contains 190 | encoded CBOR. It never could have been defined as tag 24. When the 191 | payload is known to contain CBOR, like the case of a CWT, then QCBOR's 192 | QCBORDecode_EnterBstrWrapped() can be used to decode it. 193 | 194 | ## Tags that Can be Ignored 195 | 196 | There are a few specially defined tags that can actually be 197 | ignored. These are the following: 198 | 199 | 21 Hint that content should be base64url encoded 200 | 22 Hint that content should be base64 encoded 201 | 23 Hint that content should be base16 encoded 202 | 57799 Tag that serves as a CBOR magic number 203 | 204 | The content format for all these tags is that it can be any valid 205 | CBOR. Decoding of these tags doesn't have to check the content format. 206 | 207 | Tag 55799 is not really for consumption by the CBOR decoder. Rather it 208 | is for file format checkers and such. The other tags are just hints 209 | in how to process the content. They don't really create new data types 210 | with new semantics. 211 | 212 | Other than these four, just about every other tag defined thus far 213 | requires the content to be of a specific type and results in a new 214 | data type that a protocol decoder must understand. 215 | 216 | 217 | ## Standard Tags and the Tags Registry 218 | 219 | Tags used in CBOR protocols should at least be registered in the 220 | [IANA CBOR Tags Registry] (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 221 | A small number of tags (0-23), are full IETF standards. Further, tags 222 | 24-255 require published documentation, but are not full IETF 223 | standards. Beyond tag 255, the tags are first come first served. 224 | 225 | There is no range for private use, so any tag used in a CBOR protocol 226 | should be registered. The range of tag values is very large to 227 | accommodate this. 228 | 229 | As described above, It is common to use data types from the registry 230 | in a CBOR protocol without the explicit tag, so in a way the registry 231 | is a registry of data types. 232 | 233 | 234 | ## See Also 235 | 236 | See @ref Tags-Overview and @ref Tag-Usage. 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /test/run_tests.c: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | run_tests.c -- test aggregator and results reporting 3 | 4 | Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. 5 | Copyright (c) 2021, Arm Limited. All rights reserved. 6 | 7 | SPDX-License-Identifier: BSD-3-Clause 8 | 9 | See BSD-3-Clause license in file named "LICENSE" 10 | 11 | Created on 9/30/18 12 | =============================================================================*/ 13 | 14 | #include "run_tests.h" 15 | #include "UsefulBuf.h" 16 | #include 17 | 18 | #include "float_tests.h" 19 | #include "qcbor_decode_tests.h" 20 | #include "qcbor_encode_tests.h" 21 | #include "UsefulBuf_Tests.h" 22 | 23 | 24 | 25 | // For size printing and some conditionals 26 | #include "qcbor/qcbor_encode.h" 27 | #include "qcbor/qcbor_decode.h" 28 | #include "qcbor/qcbor_spiffy_decode.h" 29 | 30 | /* 31 | Test configuration 32 | */ 33 | 34 | typedef int32_t (test_fun_t)(void); 35 | typedef const char * (test_fun2_t)(void); 36 | 37 | 38 | #define TEST_ENTRY(test_name) {#test_name, test_name, true} 39 | #define TEST_ENTRY_DISABLED(test_name) {#test_name, test_name, false} 40 | 41 | typedef struct { 42 | const char *szTestName; 43 | test_fun_t *test_fun; 44 | bool bEnabled; 45 | } test_entry; 46 | 47 | typedef struct { 48 | const char *szTestName; 49 | test_fun2_t *test_fun; 50 | bool bEnabled; 51 | } test_entry2; 52 | 53 | 54 | static test_entry2 s_tests2[] = { 55 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 56 | TEST_ENTRY(UBUTest_CopyUtil), 57 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 58 | TEST_ENTRY(UOBTest_NonAdversarial), 59 | TEST_ENTRY(TestBasicSanity), 60 | TEST_ENTRY(UOBTest_BoundaryConditionsTest), 61 | TEST_ENTRY(UBMacroConversionsTest), 62 | TEST_ENTRY(UBUtilTests), 63 | TEST_ENTRY(UIBTest_IntegerFormat), 64 | TEST_ENTRY(UBAdvanceTest) 65 | }; 66 | 67 | 68 | static test_entry s_tests[] = { 69 | #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS 70 | TEST_ENTRY(GetMapAndArrayTest), 71 | TEST_ENTRY(TellTests), 72 | TEST_ENTRY(ParseMapAsArrayTest), 73 | TEST_ENTRY(SpiffyDateDecodeTest), 74 | #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ 75 | TEST_ENTRY(ErrorHandlingTests), 76 | TEST_ENTRY(OpenCloseBytesTest), 77 | TEST_ENTRY(EnterBstrTest), 78 | TEST_ENTRY(IntegerConvertTest), 79 | TEST_ENTRY(EnterMapTest), 80 | TEST_ENTRY(QCBORHeadTest), 81 | TEST_ENTRY(EmptyMapsAndArraysTest), 82 | TEST_ENTRY(NotWellFormedTests), 83 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS 84 | TEST_ENTRY(IndefiniteLengthNestTest), 85 | TEST_ENTRY(IndefiniteLengthArrayMapTest), 86 | TEST_ENTRY(NestedMapTestIndefLen), 87 | #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ 88 | TEST_ENTRY(SimpleValueDecodeTests), 89 | TEST_ENTRY(DecodeFailureTests), 90 | TEST_ENTRY(EncodeRawTest), 91 | TEST_ENTRY(RTICResultsTest), 92 | TEST_ENTRY(MapEncodeTest), 93 | TEST_ENTRY(ArrayNestingTest1), 94 | TEST_ENTRY(ArrayNestingTest2), 95 | #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS 96 | TEST_ENTRY(ArrayNestingTest3), 97 | #endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ 98 | TEST_ENTRY(EncodeDateTest), 99 | TEST_ENTRY(SimpleValuesTest1), 100 | TEST_ENTRY(IntegerValuesTest1), 101 | TEST_ENTRY(AllAddMethodsTest), 102 | TEST_ENTRY(ParseTooDeepArrayTest), 103 | TEST_ENTRY(ComprehensiveInputTest), 104 | #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS 105 | TEST_ENTRY(ParseMapTest), 106 | #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ 107 | TEST_ENTRY(BasicEncodeTest), 108 | TEST_ENTRY(NestedMapTest), 109 | TEST_ENTRY(BignumParseTest), 110 | #ifndef QCBOR_DISABLE_TAGS 111 | TEST_ENTRY(OptTagParseTest), 112 | TEST_ENTRY(DateParseTest), 113 | TEST_ENTRY(DecodeTaggedTypeTests), 114 | #endif /* QCBOR_DISABLE_TAGS */ 115 | TEST_ENTRY(ShortBufferParseTest2), 116 | TEST_ENTRY(ShortBufferParseTest), 117 | TEST_ENTRY(ParseDeepArrayTest), 118 | TEST_ENTRY(SimpleArrayTest), 119 | TEST_ENTRY(IntegerValuesParseTest), 120 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS 121 | TEST_ENTRY(AllocAllStringsTest), 122 | TEST_ENTRY(MemPoolTest), 123 | TEST_ENTRY(IndefiniteLengthStringTest), 124 | #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS 125 | TEST_ENTRY(SpiffyIndefiniteLengthStringsTests), 126 | #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ 127 | TEST_ENTRY(SetUpAllocatorTest), 128 | TEST_ENTRY(CBORTestIssue134), 129 | #endif /* #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ 130 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 131 | #ifndef QCBOR_DISABLE_PREFERRED_FLOAT 132 | TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), 133 | TEST_ENTRY(FloatValuesTests), 134 | #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ 135 | TEST_ENTRY(GeneralFloatEncodeTests), 136 | TEST_ENTRY(GeneralFloatDecodeTests), 137 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 138 | TEST_ENTRY(BstrWrapTest), 139 | TEST_ENTRY(BstrWrapErrorTest), 140 | TEST_ENTRY(BstrWrapNestTest), 141 | TEST_ENTRY(CoseSign1TBSTest), 142 | #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS 143 | TEST_ENTRY(StringDecoderModeFailTest), 144 | #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ 145 | TEST_ENTRY_DISABLED(BigComprehensiveInputTest), 146 | TEST_ENTRY_DISABLED(TooLargeInputTest), 147 | TEST_ENTRY(EncodeErrorTests), 148 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS 149 | TEST_ENTRY(IndefiniteLengthTest), 150 | #endif 151 | TEST_ENTRY(EncodeLengthThirtyoneTest), 152 | TEST_ENTRY(CBORSequenceDecodeTests), 153 | TEST_ENTRY(IntToTests), 154 | #ifndef QCBOR_DISABLE_NON_INTEGER_LABELS 155 | TEST_ENTRY(PeekAndRewindTest), 156 | #endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ 157 | #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA 158 | TEST_ENTRY(ExponentAndMantissaDecodeTests), 159 | #ifndef QCBOR_DISABLE_TAGS 160 | TEST_ENTRY(ExponentAndMantissaDecodeFailTests), 161 | #endif /* QCBOR_DISABLE_TAGS */ 162 | TEST_ENTRY(ExponentAndMantissaEncodeTests), 163 | #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ 164 | TEST_ENTRY(ParseEmptyMapInMapTest), 165 | TEST_ENTRY(SubStringTest), 166 | TEST_ENTRY(BoolTest) 167 | }; 168 | 169 | 170 | 171 | 172 | /* 173 | Convert a number up to 999999999 to a string. This is so sprintf doesn't 174 | have to be linked in so as to minimized dependencies even in test code. 175 | 176 | StringMem should be 12 bytes long, 9 for digits, 1 for minus and 177 | 1 for \0 termination. 178 | */ 179 | static const char *NumToString(int32_t nNum, UsefulBuf StringMem) 180 | { 181 | const int32_t nMax = 1000000000; 182 | 183 | UsefulOutBuf OutBuf; 184 | UsefulOutBuf_Init(&OutBuf, StringMem); 185 | 186 | if(nNum < 0) { 187 | UsefulOutBuf_AppendByte(&OutBuf, '-'); 188 | nNum = -nNum; 189 | } 190 | if(nNum > nMax-1) { 191 | return "XXX"; 192 | } 193 | 194 | bool bDidSomeOutput = false; 195 | for(int32_t n = nMax; n > 0; n/=10) { 196 | int nDigitValue = nNum/n; 197 | if(nDigitValue || bDidSomeOutput){ 198 | bDidSomeOutput = true; 199 | UsefulOutBuf_AppendByte(&OutBuf, (uint8_t)('0' + nDigitValue)); 200 | nNum -= nDigitValue * n; 201 | } 202 | } 203 | if(!bDidSomeOutput){ 204 | UsefulOutBuf_AppendByte(&OutBuf, '0'); 205 | } 206 | UsefulOutBuf_AppendByte(&OutBuf, '\0'); 207 | 208 | return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr; 209 | } 210 | 211 | 212 | /* 213 | Public function. See run_test.h. 214 | */ 215 | int RunTestsQCBOR(const char *szTestNames[], 216 | OutputStringCB pfOutput, 217 | void *poutCtx, 218 | int *pNumTestsRun) 219 | { 220 | int nTestsFailed = 0; 221 | int nTestsRun = 0; 222 | 223 | UsefulBuf_MAKE_STACK_UB(StringStorage, 12); 224 | 225 | test_entry2 *t2; 226 | const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2); 227 | 228 | for(t2 = s_tests2; t2 < s_tests2_end; t2++) { 229 | if(szTestNames[0]) { 230 | // Some tests have been named 231 | const char **szRequestedNames; 232 | for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { 233 | if(!strcmp(t2->szTestName, *szRequestedNames)) { 234 | break; // Name matched 235 | } 236 | } 237 | if(*szRequestedNames == NULL) { 238 | // Didn't match this test 239 | continue; 240 | } 241 | } else { 242 | // no tests named, but don't run "disabled" tests 243 | if(!t2->bEnabled) { 244 | // Don't run disabled tests when all tests are being run 245 | // as indicated by no specific test names being given 246 | continue; 247 | } 248 | } 249 | 250 | const char * szTestResult = (t2->test_fun)(); 251 | nTestsRun++; 252 | if(pfOutput) { 253 | (*pfOutput)(t2->szTestName, poutCtx, 0); 254 | } 255 | 256 | if(szTestResult) { 257 | if(pfOutput) { 258 | (*pfOutput)(" FAILED (returned ", poutCtx, 0); 259 | (*pfOutput)(szTestResult, poutCtx, 0); 260 | (*pfOutput)(")", poutCtx, 1); 261 | } 262 | nTestsFailed++; 263 | } else { 264 | if(pfOutput) { 265 | (*pfOutput)( " PASSED", poutCtx, 1); 266 | } 267 | } 268 | } 269 | 270 | 271 | test_entry *t; 272 | const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry); 273 | 274 | for(t = s_tests; t < s_tests_end; t++) { 275 | if(szTestNames[0]) { 276 | // Some tests have been named 277 | const char **szRequestedNames; 278 | for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { 279 | if(!strcmp(t->szTestName, *szRequestedNames)) { 280 | break; // Name matched 281 | } 282 | } 283 | if(*szRequestedNames == NULL) { 284 | // Didn't match this test 285 | continue; 286 | } 287 | } else { 288 | // no tests named, but don't run "disabled" tests 289 | if(!t->bEnabled) { 290 | // Don't run disabled tests when all tests are being run 291 | // as indicated by no specific test names being given 292 | continue; 293 | } 294 | } 295 | 296 | int32_t nTestResult = (t->test_fun)(); 297 | nTestsRun++; 298 | if(pfOutput) { 299 | (*pfOutput)(t->szTestName, poutCtx, 0); 300 | } 301 | 302 | if(nTestResult) { 303 | if(pfOutput) { 304 | (*pfOutput)(" FAILED (returned ", poutCtx, 0); 305 | (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx, 0); 306 | (*pfOutput)(")", poutCtx, 1); 307 | } 308 | nTestsFailed++; 309 | } else { 310 | if(pfOutput) { 311 | (*pfOutput)( " PASSED", poutCtx, 1); 312 | } 313 | } 314 | } 315 | 316 | if(pNumTestsRun) { 317 | *pNumTestsRun = nTestsRun; 318 | } 319 | 320 | if(pfOutput) { 321 | (*pfOutput)( "SUMMARY: ", poutCtx, 0); 322 | (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx, 0); 323 | (*pfOutput)( " tests run; ", poutCtx, 0); 324 | (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx, 0); 325 | (*pfOutput)( " tests failed", poutCtx, 1); 326 | } 327 | 328 | return nTestsFailed; 329 | } 330 | 331 | 332 | 333 | 334 | /* 335 | Public function. See run_test.h. 336 | */ 337 | static void PrintSize(const char *szWhat, 338 | uint32_t uSize, 339 | OutputStringCB pfOutput, 340 | void *pOutCtx) 341 | { 342 | UsefulBuf_MAKE_STACK_UB(buffer, 20); 343 | 344 | (*pfOutput)(szWhat, pOutCtx, 0); 345 | (*pfOutput)(" ", pOutCtx, 0); 346 | (*pfOutput)(NumToString((int32_t)uSize, buffer), pOutCtx, 0); 347 | (*pfOutput)("", pOutCtx, 1); 348 | } 349 | 350 | 351 | /* 352 | Public function. See run_test.h. 353 | */ 354 | void PrintSizesQCBOR(OutputStringCB pfOutput, void *pOutCtx) 355 | { 356 | // These will never be large so cast is safe 357 | PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx); 358 | PrintSize("sizeof(QCBOREncodeContext)", (uint32_t)sizeof(QCBOREncodeContext), pfOutput, pOutCtx); 359 | PrintSize("sizeof(QCBORDecodeNesting)", (uint32_t)sizeof(QCBORDecodeNesting), pfOutput, pOutCtx); 360 | PrintSize("sizeof(QCBORDecodeContext)", (uint32_t)sizeof(QCBORDecodeContext), pfOutput, pOutCtx); 361 | PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx); 362 | PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx); 363 | PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx); 364 | PrintSize("sizeof(TagSpecification)", (uint32_t)sizeof(QCBOR_Private_TagSpec),pfOutput, pOutCtx); 365 | (*pfOutput)("", pOutCtx, 1); 366 | } 367 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | example.c -- Example code for QCBOR 3 | 4 | Copyright (c) 2020-2021, Laurence Lundblade. All rights reserved. 5 | Copyright (c) 2021, Arm Limited. All rights reserved. 6 | 7 | SPDX-License-Identifier: BSD-3-Clause 8 | 9 | See BSD-3-Clause license in file named "LICENSE" 10 | 11 | Created on 6/30/2020 12 | ========================================================================== */ 13 | 14 | #include 15 | #include "example.h" 16 | #include "qcbor/qcbor_encode.h" 17 | #include "qcbor/qcbor_decode.h" 18 | #include "qcbor/qcbor_spiffy_decode.h" 19 | 20 | 21 | /** 22 | * This is a simple example of encoding and decoding some CBOR from 23 | * and to a C structure. 24 | * 25 | * This also includes a comparison between the original structure 26 | * and the one decoded from the CBOR to confirm correctness. 27 | */ 28 | 29 | 30 | #define MAX_CYLINDERS 16 31 | 32 | /** 33 | * The data structure representing a car engine that is encoded and 34 | * decoded in this example. 35 | */ 36 | typedef struct 37 | { 38 | UsefulBufC Manufacturer; 39 | int64_t uDisplacement; 40 | int64_t uHorsePower; 41 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 42 | double dDesignedCompresion; 43 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 44 | int64_t uNumCylinders; 45 | bool bTurboCharged; 46 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 47 | struct { 48 | double dMeasuredCompression; 49 | } cylinders[MAX_CYLINDERS]; 50 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 51 | } CarEngine; 52 | 53 | 54 | /** 55 | * @brief Initialize the Engine data structure with values to encode. 56 | * 57 | * @param[out] pE The Engine structure to fill in 58 | */ 59 | void EngineInit(CarEngine *pE) 60 | { 61 | pE->Manufacturer = UsefulBuf_FROM_SZ_LITERAL("Porsche"); 62 | pE->uDisplacement = 3296; 63 | pE->uHorsePower = 210; 64 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 65 | pE->dDesignedCompresion = 9.1; 66 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 67 | pE->uNumCylinders = 6; 68 | pE->bTurboCharged = false; 69 | 70 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 71 | pE->cylinders[0].dMeasuredCompression = 9.0; 72 | pE->cylinders[1].dMeasuredCompression = 9.2; 73 | pE->cylinders[2].dMeasuredCompression = 8.9; 74 | pE->cylinders[3].dMeasuredCompression = 8.9; 75 | pE->cylinders[4].dMeasuredCompression = 9.1; 76 | pE->cylinders[5].dMeasuredCompression = 9.0; 77 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 78 | } 79 | 80 | 81 | /** 82 | * @brief Compare two Engine structure for equality. 83 | * 84 | * @param[in] pE1 First Engine to compare. 85 | * @param[in] pE2 Second Engine to compare. 86 | * 87 | * @retval Return @c true if the two Engine data structures are exactly the 88 | * same. 89 | */ 90 | static bool EngineCompare(const CarEngine *pE1, const CarEngine *pE2) 91 | { 92 | if(pE1->uNumCylinders != pE2->uNumCylinders) { 93 | return false; 94 | } 95 | if(pE1->bTurboCharged != pE2->bTurboCharged) { 96 | return false; 97 | } 98 | if(pE1->uDisplacement != pE2->uDisplacement) { 99 | return false; 100 | } 101 | if(pE1->uHorsePower != pE2->uHorsePower) { 102 | return false; 103 | } 104 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 105 | if(pE1->dDesignedCompresion != pE2->dDesignedCompresion) { 106 | return false; 107 | } 108 | for(int64_t i = 0; i < pE2->uNumCylinders; i++) { 109 | if(pE1->cylinders[i].dMeasuredCompression != 110 | pE2->cylinders[i].dMeasuredCompression) { 111 | return false; 112 | } 113 | } 114 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 115 | 116 | if(UsefulBuf_Compare(pE1->Manufacturer, pE2->Manufacturer)) { 117 | return false; 118 | } 119 | 120 | return true; 121 | } 122 | 123 | 124 | /** 125 | * @brief Encode an initialized CarEngine data structure in CBOR. 126 | * 127 | * @param[in] pEngine The data structure to encode. 128 | * @param[in] Buffer Pointer and length of buffer to output to. 129 | * 130 | * @return The pointer and length of the encoded CBOR or 131 | * @ref NULLUsefulBufC on error. 132 | * 133 | * This encodes the input structure @c pEngine as a CBOR map of 134 | * label-value pairs. An array of float is one of the items in the 135 | * map. 136 | * 137 | * This uses the UsefulBuf convention of passing in a non-const empty 138 | * buffer to be filled in and returning a filled in const buffer. The 139 | * buffer to write into is given as a pointer and length in a 140 | * UsefulBuf. The buffer returned with the encoded CBOR is a 141 | * UsefulBufC also a pointer and length. In this implementation the 142 | * pointer to the returned data is exactly the same as that of the 143 | * empty buffer. The returned length will be smaller than or equal to 144 | * that of the empty buffer. This gives correct const-ness for the 145 | * buffer passed in and the data returned. 146 | * 147 | * @c Buffer must be big enough to hold the output. If it is not @ref 148 | * NULLUsefulBufC will be returned. @ref NULLUsefulBufC will be 149 | * returned for any other encoding errors. 150 | * 151 | * This can be called with @c Buffer set to @ref SizeCalculateUsefulBuf 152 | * in which case the size of the encoded engine will be calculated, 153 | * but no actual encoded CBOR will be output. The calculated size is 154 | * in @c .len of the returned @ref UsefulBufC. 155 | */ 156 | UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer) 157 | { 158 | /* Set up the encoding context with the output buffer */ 159 | QCBOREncodeContext EncodeCtx; 160 | QCBOREncode_Init(&EncodeCtx, Buffer); 161 | 162 | /* Proceed to output all the items, letting the internal error 163 | * tracking do its work */ 164 | QCBOREncode_OpenMap(&EncodeCtx); 165 | QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pEngine->Manufacturer); 166 | QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders); 167 | QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pEngine->uDisplacement); 168 | QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pEngine->uHorsePower); 169 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 170 | QCBOREncode_AddDoubleToMapSZ(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion); 171 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 172 | QCBOREncode_OpenArrayInMapSZ(&EncodeCtx, "Cylinders"); 173 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 174 | for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) { 175 | QCBOREncode_AddDouble(&EncodeCtx, 176 | pEngine->cylinders[i].dMeasuredCompression); 177 | } 178 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 179 | QCBOREncode_CloseArray(&EncodeCtx); 180 | QCBOREncode_AddBoolToMapSZ(&EncodeCtx, "Turbo", pEngine->bTurboCharged); 181 | QCBOREncode_CloseMap(&EncodeCtx); 182 | 183 | /* Get the pointer and length of the encoded output. If there was 184 | * any encoding error, it will be returned here */ 185 | UsefulBufC EncodedCBOR; 186 | QCBORError uErr; 187 | uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR); 188 | if(uErr != QCBOR_SUCCESS) { 189 | return NULLUsefulBufC; 190 | } else { 191 | return EncodedCBOR; 192 | } 193 | } 194 | 195 | 196 | /** 197 | * Error results when decoding an Engine data structure. 198 | */ 199 | typedef enum { 200 | EngineSuccess, 201 | CBORNotWellFormed, 202 | TooManyCylinders, 203 | EngineProtocolerror, 204 | WrongNumberOfCylinders 205 | } EngineDecodeErrors; 206 | 207 | 208 | /** 209 | * Convert @ref QCBORError to @ref EngineDecodeErrors. 210 | */ 211 | static EngineDecodeErrors ConvertError(QCBORError uErr) 212 | { 213 | EngineDecodeErrors uReturn; 214 | 215 | switch(uErr) 216 | { 217 | case QCBOR_SUCCESS: 218 | uReturn = EngineSuccess; 219 | break; 220 | 221 | case QCBOR_ERR_HIT_END: 222 | uReturn = CBORNotWellFormed; 223 | break; 224 | 225 | default: 226 | uReturn = EngineProtocolerror; 227 | break; 228 | } 229 | 230 | return uReturn; 231 | } 232 | 233 | 234 | /** 235 | * @brief Simplest engine decode using spiffy decode features. 236 | * 237 | * @param[in] EncodedEngine Pointer and length of CBOR-encoded engine. 238 | * @param[out] pE The structure filled in from the decoding. 239 | * 240 | * @return The decode error or success. 241 | * 242 | * This decodes the CBOR into the engine structure. 243 | * 244 | * As QCBOR automatically supports both definite and indefinite maps 245 | * and arrays, this will decode either. 246 | * 247 | * This uses QCBOR's spiffy decode functions, so the implementation is 248 | * simple and closely parallels the encode implementation in 249 | * EncodeEngineDefiniteLength(). 250 | * 251 | * Another way to decode without using spiffy decode functions is to 252 | * use QCBORDecode_GetNext() to traverse the whole tree. This 253 | * requires a more complex implementation, but is faster and will pull 254 | * in less code from the CBOR library. The speed advantage is likely 255 | * of consequence when decoding much much larger CBOR on slow small 256 | * CPUs. 257 | * 258 | * A middle way is to use the spiffy decode 259 | * QCBORDecode_GetItemsInMap(). The implementation has middle 260 | * complexity and uses less CPU. 261 | */ 262 | EngineDecodeErrors DecodeEngineSpiffy(UsefulBufC EncodedEngine, CarEngine *pE) 263 | { 264 | QCBORError uErr; 265 | QCBORDecodeContext DecodeCtx; 266 | 267 | /* Let QCBORDecode internal error tracking do its work. */ 268 | QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL); 269 | QCBORDecode_EnterMap(&DecodeCtx, NULL); 270 | QCBORDecode_GetTextStringInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer)); 271 | QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement)); 272 | QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower)); 273 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 274 | QCBORDecode_GetDoubleInMapSZ(&DecodeCtx, "DesignedCompression", &(pE->dDesignedCompresion)); 275 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 276 | QCBORDecode_GetBoolInMapSZ(&DecodeCtx, "Turbo", &(pE->bTurboCharged)); 277 | 278 | QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "NumCylinders", &(pE->uNumCylinders)); 279 | 280 | /* Check the internal tracked error now before going on to 281 | * reference any of the decoded data, particularly 282 | * pE->uNumCylinders */ 283 | uErr = QCBORDecode_GetError(&DecodeCtx); 284 | if(uErr != QCBOR_SUCCESS) { 285 | goto Done; 286 | } 287 | 288 | if(pE->uNumCylinders > MAX_CYLINDERS) { 289 | return TooManyCylinders; 290 | } 291 | 292 | QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders"); 293 | #ifndef USEFULBUF_DISABLE_ALL_FLOAT 294 | for(int64_t i = 0; i < pE->uNumCylinders; i++) { 295 | QCBORDecode_GetDouble(&DecodeCtx, 296 | &(pE->cylinders[i].dMeasuredCompression)); 297 | } 298 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 299 | QCBORDecode_ExitArray(&DecodeCtx); 300 | QCBORDecode_ExitMap(&DecodeCtx); 301 | 302 | /* Catch further decoding error here */ 303 | uErr = QCBORDecode_Finish(&DecodeCtx); 304 | 305 | Done: 306 | return ConvertError(uErr); 307 | } 308 | 309 | 310 | int32_t RunQCborExample(void) 311 | { 312 | CarEngine InitialEngine; 313 | CarEngine DecodedEngine; 314 | 315 | /* For every buffer used by QCBOR a pointer and a length are always 316 | * carried in a UsefulBuf. This is a secure coding and hygene 317 | * practice to help make sure code never runs off the end of a 318 | * buffer. 319 | * 320 | * UsefulBuf structures are passed as a stack parameter to make the 321 | * code prettier. The object code generated isn't much different 322 | * from passing a pointer parameter and a length parameter. 323 | * 324 | * This macro is equivalent to: 325 | * uint8_t __pBufEngineBuffer[300]; 326 | * UsefulBuf EngineBuffer = {__pBufEngineBuffer, 300}; 327 | */ 328 | UsefulBuf_MAKE_STACK_UB( EngineBuffer, 300); 329 | 330 | /* The pointer in UsefulBuf is not const and used for representing 331 | * a buffer to be written to. For UsefulbufC, the pointer is const 332 | * and is used to represent a buffer that has been written to. 333 | */ 334 | UsefulBufC EncodedEngine; 335 | EngineDecodeErrors uErr; 336 | 337 | /* Initialize the structure with some values. */ 338 | EngineInit(&InitialEngine); 339 | 340 | /* Encode the engine structure. */ 341 | EncodedEngine = EncodeEngine(&InitialEngine, EngineBuffer); 342 | if(UsefulBuf_IsNULLC(EncodedEngine)) { 343 | printf("Engine encode failed\n"); 344 | goto Done; 345 | } 346 | printf("Example: Definite Length Engine Encoded in %zu bytes\n", 347 | EncodedEngine.len); 348 | 349 | /* Decode the CBOR */ 350 | uErr = DecodeEngineSpiffy(EncodedEngine, &DecodedEngine); 351 | printf("Example: Spiffy Engine Decode Result: %d\n", uErr); 352 | if(uErr) { 353 | goto Done; 354 | } 355 | 356 | /* Check the results */ 357 | if(!EngineCompare(&InitialEngine, &DecodedEngine)) { 358 | printf("Example: Spiffy Engine Decode comparison fail\n"); 359 | } 360 | 361 | 362 | /* Further example of how to calculate the encoded size, then allocate */ 363 | UsefulBufC EncodedEngineSize; 364 | EncodedEngineSize = EncodeEngine(&InitialEngine, SizeCalculateUsefulBuf); 365 | if(UsefulBuf_IsNULLC(EncodedEngine)) { 366 | printf("Engine encode size calculation failed\n"); 367 | goto Done; 368 | } 369 | (void)EncodedEngineSize; /* Supress unsed variable warning */ 370 | /* Here malloc could be called to allocate a buffer. Then 371 | * EncodeEngine() can be called a second time to actually 372 | * encode. (The actual code is not live here to avoid a 373 | * dependency on malloc()). 374 | * UsefulBuf MallocedBuffer; 375 | * MallocedBuffer.len = EncodedEngineSize.len; 376 | * MallocedBuffer.ptr = malloc(EncodedEngineSize.len); 377 | * EncodedEngine = EncodeEngine(&InitialEngine, MallocedBuffer); 378 | */ 379 | 380 | Done: 381 | printf("\n"); 382 | 383 | return 0; 384 | } 385 | -------------------------------------------------------------------------------- /test/not_well_formed_cbor.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | not_well_formed_cbor.h -- vectors to test for handling of not-well-formed CBOR 3 | 4 | This is part of QCBOR -- https://github.com/laurencelundblade/QCBOR 5 | 6 | Copyright (c) 2019, Laurence Lundblade. All rights reserved. 7 | 8 | SPDX-License-Identifier: BSD-3-Clause 9 | 10 | See BSD-3-Clause license in file named "LICENSE" 11 | 12 | Created on 7/27/19 13 | ==============================================================================*/ 14 | 15 | #ifndef not_well_formed_cbor_h 16 | #define not_well_formed_cbor_h 17 | 18 | #include // for size_t 19 | #include // for uint8_t 20 | 21 | 22 | struct someBinaryBytes { 23 | const uint8_t *p; // Pointer to the bytes 24 | size_t n; // Length of the bytes 25 | }; 26 | 27 | 28 | static const struct someBinaryBytes paNotWellFormedCBOR[] = { 29 | 30 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS 31 | // Indefinite length strings must be closed off 32 | 33 | // An indefinite length byte string not closed off 34 | {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, 35 | // An indefinite length text string not closed off 36 | {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, 37 | 38 | 39 | // All the chunks in an indefinite length string must be of the 40 | // type of indefinite length string and indefinite 41 | 42 | // indefinite length byte string with text string chunk 43 | {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, 44 | // indefinite length text string with a byte string chunk 45 | {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, 46 | // indefinite length byte string with an positive integer chunk 47 | {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, 48 | // indefinite length byte string with an negative integer chunk 49 | {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, 50 | // indefinite length byte string with an array chunk 51 | {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, 52 | // indefinite length byte string with an map chunk 53 | {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, 54 | #ifndef QCBOR_DISABLE_TAGS 55 | // indefinite length byte string with tagged integer chunk 56 | {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, 57 | #endif /* QCBOR_DISABLE_TAGS */ 58 | // indefinite length byte string with an simple type chunk 59 | {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, 60 | // indefinite length byte string with indefinite string inside 61 | {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, 62 | // indefinite length text string with indefinite string inside 63 | {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, 64 | 65 | #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ 66 | 67 | // Definte length maps and arrays must be closed by having the 68 | // right number of items 69 | 70 | // A definte length array that is supposed to have 1 item, but has none 71 | {(uint8_t[]){0x81}, 1}, 72 | // A definte length array that is supposed to have 2 items, but has only 1 73 | {(uint8_t[]){0x82, 0x00}, 2}, 74 | // A definte length array that is supposed to have 511 items, but has only 1 75 | {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4}, 76 | // A definte length map that is supposed to have 1 item, but has none 77 | {(uint8_t[]){0xa1}, 1}, 78 | // A definte length map that is supposed to have s item, but has only 1 79 | {(uint8_t[]){0xa2, 0x01, 0x02}, 3}, 80 | 81 | 82 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS 83 | // Indefinte length maps and arrays must be ended by a break 84 | 85 | // Indefinite length array with zero items and no break 86 | {(uint8_t[]){0x9f}, 1}, 87 | // Indefinite length array with two items and no break 88 | {(uint8_t[]){0x9f, 0x01, 0x02}, 3}, 89 | // Indefinite length map with zero items and no break 90 | {(uint8_t[]){0xbf}, 1}, 91 | // Indefinite length map with two items and no break 92 | {(uint8_t[]){0xbf, 0x01, 0x02, 0x01, 0x02}, 5}, 93 | 94 | 95 | // Some extra test vectors for unclosed arrays and maps 96 | 97 | // Unclosed indefinite array containing a close definite array 98 | {(uint8_t[]){0x9f, 0x80, 0x00}, 3}, 99 | // Definite length array containing an unclosed indefinite array 100 | {(uint8_t[]){0x81, 0x9f}, 2}, 101 | // Deeply nested definite length arrays with deepest one unclosed 102 | {(uint8_t[]){0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81}, 9}, 103 | // Deeply nested indefinite length arrays with deepest one unclosed 104 | {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9}, 105 | // Mixed nesting with indefinite unclosed 106 | {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, 107 | // Mixed nesting with definite unclosed 108 | {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, 109 | #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ 110 | 111 | 112 | // The "argument" for the data item is missing bytes 113 | 114 | // Positive integer missing 1 byte argument 115 | {(uint8_t[]){0x18}, 1}, 116 | // Positive integer missing 2 byte argument 117 | {(uint8_t[]){0x19}, 1}, 118 | // Positive integer missing 4 byte argument 119 | {(uint8_t[]){0x1a}, 1}, 120 | // Positive integer missing 8 byte argument 121 | {(uint8_t[]){0x1b}, 1}, 122 | // Positive integer missing 1 byte of 2 byte argument 123 | {(uint8_t[]){0x19, 0x01}, 2}, 124 | // Positive integer missing 2 bytes of 4 byte argument 125 | {(uint8_t[]){0x1a, 0x01, 0x02}, 3}, 126 | // Positive integer missing 1 bytes of 7 byte argument 127 | {(uint8_t[]){0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8}, 128 | // Negative integer missing 1 byte argument 129 | {(uint8_t[]){0x38}, 1}, 130 | // Binary string missing 1 byte argument 131 | {(uint8_t[]){0x58}, 1}, 132 | // Text string missing 1 byte argument 133 | {(uint8_t[]){0x78}, 1}, 134 | // Array missing 1 byte argument 135 | {(uint8_t[]){0x98}, 1}, 136 | // Map missing 1 byte argument 137 | {(uint8_t[]){0xb8}, 1}, 138 | // Tag missing 1 byte argument 139 | {(uint8_t[]){0xd8}, 1}, 140 | // Simple missing 1 byte argument 141 | {(uint8_t[]){0xf8}, 1}, 142 | // Half-precision missing 1 byte 143 | {(uint8_t[]){0xf9, 0x00}, 2}, 144 | // Float missing 2 bytes 145 | {(uint8_t[]){0xfa, 0x00, 0x00}, 3}, 146 | // Double missing 5 bytes 147 | {(uint8_t[]){0xfb, 0x00, 0x00, 0x00}, 4}, 148 | 149 | // Breaks must not occur in definite length arrays and maps 150 | 151 | // Array of length 1 with sole member replaced by a break 152 | {(uint8_t[]){0x81, 0xff}, 2}, 153 | // Array of length 2 with 2nd member replaced by a break 154 | {(uint8_t[]){0x82, 0x00, 0xff}, 3}, 155 | // Map of length 1 with sole member label replaced by a break 156 | {(uint8_t[]){0xa1, 0xff}, 2}, 157 | // Map of length 1 with sole member label replaced by break 158 | // Alternate representation that some decoders handle difference 159 | {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, 160 | // Array of length 1 with 2nd member value replaced by a break 161 | {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, 162 | // Map of length 2 with 2nd entry label replaced by a break 163 | {(uint8_t[]){0xa2, 0x00, 0x00, 0xff, 0x00}, 5}, 164 | // Map of length 2 with 2nd entry value replaced by a break 165 | {(uint8_t[]){0xa2, 0x00, 0x00, 0x00, 0xff}, 5}, 166 | 167 | // Breaks must not occur on their own out of an indefinite length 168 | // data item 169 | 170 | // A bare break is not well formed 171 | {(uint8_t[]){0xff}, 1}, 172 | // A bare break after a zero length definite length array 173 | {(uint8_t[]){0x80, 0xff}, 2}, 174 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS 175 | // A bare break after a zero length indefinite length map 176 | {(uint8_t[]){0x9f, 0xff, 0xff}, 3}, 177 | #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ 178 | 179 | 180 | // Forbidden two-byte encodings of simple types 181 | 182 | // Must use 0xe0 instead 183 | {(uint8_t[]){0xf8, 0x00}, 2}, 184 | // Should use 0xe1 instead 185 | {(uint8_t[]){0xf8, 0x01}, 2}, 186 | // Should use 0xe2 instead 187 | {(uint8_t[]){0xf8, 0x02}, 2}, 188 | // Should use 0xe3 instead 189 | {(uint8_t[]){0xf8, 0x03}, 2}, 190 | // Should use 0xe4 instead 191 | {(uint8_t[]){0xf8, 0x04}, 2}, 192 | // Should use 0xe5 instead 193 | {(uint8_t[]){0xf8, 0x05}, 2}, 194 | // Should use 0xe6 instead 195 | {(uint8_t[]){0xf8, 0x06}, 2}, 196 | // Should use 0xe7 instead 197 | {(uint8_t[]){0xf8, 0x07}, 2}, 198 | // Should use 0xe8 instead 199 | {(uint8_t[]){0xf8, 0x08}, 2}, 200 | // Should use 0xe9 instead 201 | {(uint8_t[]){0xf8, 0x09}, 2}, 202 | // Should use 0xea instead 203 | {(uint8_t[]){0xf8, 0x0a}, 2}, 204 | // Should use 0xeb instead 205 | {(uint8_t[]){0xf8, 0x0b}, 2}, 206 | // Should use 0xec instead 207 | {(uint8_t[]){0xf8, 0x0c}, 2}, 208 | // Should use 0xed instead 209 | {(uint8_t[]){0xf8, 0x0d}, 2}, 210 | // Should use 0xee instead 211 | {(uint8_t[]){0xf8, 0x0e}, 2}, 212 | // Should use 0xef instead 213 | {(uint8_t[]){0xf8, 0x0f}, 2}, 214 | // Should use 0xf0 instead 215 | {(uint8_t[]){0xf8, 0x10}, 2}, 216 | // Should use 0xf1 instead 217 | {(uint8_t[]){0xf8, 0x11}, 2}, 218 | // Should use 0xf2 instead 219 | {(uint8_t[]){0xf8, 0x12}, 2}, 220 | // Must use 0xf3 instead 221 | {(uint8_t[]){0xf8, 0x13}, 2}, 222 | // Must use 0xf4 instead 223 | {(uint8_t[]){0xf8, 0x14}, 2}, 224 | // Must use 0xf5 instead 225 | {(uint8_t[]){0xf8, 0x15}, 2}, 226 | // Must use 0xf6 instead 227 | {(uint8_t[]){0xf8, 0x16}, 2}, 228 | // Must use 0xf7 instead 229 | {(uint8_t[]){0xf8, 0x17}, 2}, 230 | // Reserved (as defined in RFC 8126), considered not-well-formed 231 | {(uint8_t[]){0xf8, 0x18}, 2}, 232 | // Reserved (as defined in RFC 8126), considered not-well-formed 233 | {(uint8_t[]){0xf8, 0x19}, 2}, 234 | // Reserved (as defined in RFC 8126), considered not-well-formed 235 | {(uint8_t[]){0xf8, 0x1a}, 2}, 236 | // Reserved (as defined in RFC 8126), considered not-well-formed 237 | {(uint8_t[]){0xf8, 0x1b}, 2}, 238 | // Reserved (as defined in RFC 8126), considered not-well-formed 239 | {(uint8_t[]){0xf8, 0x1c}, 2}, 240 | // Reserved (as defined in RFC 8126), considered not-well-formed 241 | {(uint8_t[]){0xf8, 0x1d}, 2}, 242 | // Reserved (as defined in RFC 8126), considered not-well-formed 243 | {(uint8_t[]){0xf8, 0x1e}, 2}, 244 | // Reserved (as defined in RFC 8126), considered not-well-formed 245 | {(uint8_t[]){0xf8, 0x1f}, 2}, 246 | 247 | // Integers with "argument" equal to an indefinite length 248 | 249 | // Positive integer with "argument" an indefinite length 250 | {(uint8_t[]){0x1f}, 1}, 251 | // Negative integer with "argument" an indefinite length 252 | {(uint8_t[]){0x3f}, 1}, 253 | #ifndef QCBOR_DISABLE_TAGS 254 | // CBOR tag with "argument" an indefinite length 255 | {(uint8_t[]){0xdf, 0x00}, 2}, 256 | // CBOR tag with "argument" an indefinite length alternate vector 257 | {(uint8_t[]){0xdf}, 1}, 258 | #endif /* QCBOR_DISABLE_TAGS */ 259 | 260 | // Missing content bytes from a definite length string 261 | 262 | // A byte string is of length 1 without the 1 byte 263 | {(uint8_t[]){0x41}, 1}, 264 | // A text string is of length 1 without the 1 byte 265 | {(uint8_t[]){0x61}, 1}, 266 | // Byte string should have 65520 bytes, but has one 267 | {(uint8_t[]){0x59, 0xff, 0xf0, 0x00}, 6}, 268 | // Byte string should have 65520 bytes, but has one 269 | {(uint8_t[]){0x79, 0xff, 0xf0, 0x00}, 6}, 270 | 271 | 272 | // Use of unassigned additional information values 273 | 274 | // Major type positive integer with reserved value 28 275 | {(uint8_t[]){0x1c}, 1}, 276 | // Major type positive integer with reserved value 29 277 | {(uint8_t[]){0x1d}, 1}, 278 | // Major type positive integer with reserved value 30 279 | {(uint8_t[]){0x1e}, 1}, 280 | // Major type negative integer with reserved value 28 281 | {(uint8_t[]){0x3c}, 1}, 282 | // Major type negative integer with reserved value 29 283 | {(uint8_t[]){0x3d}, 1}, 284 | // Major type negative integer with reserved value 30 285 | {(uint8_t[]){0x3e}, 1}, 286 | // Major type byte string with reserved value 28 length 287 | {(uint8_t[]){0x5c}, 1}, 288 | // Major type byte string with reserved value 29 length 289 | {(uint8_t[]){0x5d}, 1}, 290 | // Major type byte string with reserved value 30 length 291 | {(uint8_t[]){0x5e}, 1}, 292 | // Major type text string with reserved value 28 length 293 | {(uint8_t[]){0x7c}, 1}, 294 | // Major type text string with reserved value 29 length 295 | {(uint8_t[]){0x7d}, 1}, 296 | // Major type text string with reserved value 30 length 297 | {(uint8_t[]){0x7e}, 1}, 298 | // Major type array with reserved value 28 length 299 | {(uint8_t[]){0x9c}, 1}, 300 | // Major type array with reserved value 29 length 301 | {(uint8_t[]){0x9d}, 1}, 302 | // Major type array with reserved value 30 length 303 | {(uint8_t[]){0x9e}, 1}, 304 | // Major type map with reserved value 28 length 305 | {(uint8_t[]){0xbc}, 1}, 306 | // Major type map with reserved value 29 length 307 | {(uint8_t[]){0xbd}, 1}, 308 | // Major type map with reserved value 30 length 309 | {(uint8_t[]){0xbe}, 1}, 310 | // Major type tag with reserved value 28 length 311 | {(uint8_t[]){0xdc}, 1}, 312 | // Major type tag with reserved value 29 length 313 | {(uint8_t[]){0xdd}, 1}, 314 | // Major type tag with reserved value 30 length 315 | {(uint8_t[]){0xde}, 1}, 316 | // Major type simple with reserved value 28 length 317 | {(uint8_t[]){0xfc}, 1}, 318 | // Major type simple with reserved value 29 length 319 | {(uint8_t[]){0xfd}, 1}, 320 | // Major type simple with reserved value 30 length 321 | {(uint8_t[]){0xfe}, 1}, 322 | 323 | 324 | // Maps must have an even number of data items (key & value) 325 | 326 | // Map with 1 item when it should have 2 327 | {(uint8_t[]){0xa1, 0x00}, 2}, 328 | // Map with 3 item when it should have 4 329 | {(uint8_t[]){0xa2, 0x00, 0x00, 0x00}, 2}, 330 | #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS 331 | // Map with 1 item when it should have 2 332 | {(uint8_t[]){0xbf, 0x00, 0xff}, 3}, 333 | // Map with 3 item when it should have 4 334 | {(uint8_t[]){0xbf, 0x00, 0x00, 0x00, 0xff}, 5}, 335 | #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ 336 | 337 | }; 338 | 339 | #endif /* not_well_formed_cbor_h */ 340 | -------------------------------------------------------------------------------- /inc/qcbor/qcbor_private.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | * Copyright (c) 2016-2018, The Linux Foundation. 3 | * Copyright (c) 2018-2024, Laurence Lundblade. 4 | * Copyright (c) 2021, Arm Limited. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are 9 | * met: 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above 13 | * copyright notice, this list of conditions and the following 14 | * disclaimer in the documentation and/or other materials provided 15 | * with the distribution. 16 | * * Neither the name of The Linux Foundation nor the names of its 17 | * contributors, nor the name "Laurence Lundblade" may be used to 18 | * endorse or promote products derived from this software without 19 | * specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 31 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * ========================================================================= */ 33 | 34 | 35 | #ifndef qcbor_private_h 36 | #define qcbor_private_h 37 | 38 | 39 | #include 40 | #include "UsefulBuf.h" 41 | #include "qcbor/qcbor_common.h" 42 | 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #if 0 47 | } // Keep editor indention formatting happy 48 | #endif 49 | #endif 50 | 51 | 52 | /* This was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, 53 | * but this is inconsistent with all the other QCBOR_DISABLE_ 54 | * #defines, so the name was changed and this was added for backwards 55 | * compatibility 56 | */ 57 | #ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA 58 | #define QCBOR_DISABLE_EXP_AND_MANTISSA 59 | #endif 60 | 61 | /* If USEFULBUF_DISABLE_ALL_FLOATis defined then define 62 | * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT 63 | */ 64 | #ifdef USEFULBUF_DISABLE_ALL_FLOAT 65 | #ifndef QCBOR_DISABLE_FLOAT_HW_USE 66 | #define QCBOR_DISABLE_FLOAT_HW_USE 67 | #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ 68 | #ifndef QCBOR_DISABLE_PREFERRED_FLOAT 69 | #define QCBOR_DISABLE_PREFERRED_FLOAT 70 | #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ 71 | #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ 72 | 73 | 74 | /* 75 | * Convenience macro for selecting the proper return value in case floating 76 | * point feature(s) are disabled. 77 | * 78 | * The macros: 79 | * 80 | * FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should 81 | * result error, and all other cases should return 82 | * 'x'. 83 | * 84 | * The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all 85 | * floating point is disabled. 86 | * 87 | * FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float 88 | * results in error, and all other cases should 89 | * return 'x'. 90 | * FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating 91 | * point results in error, and all other cases 92 | * should return 'x'. 93 | * FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled 94 | * preferred float or disabling 95 | * hardware floating point results in 96 | * error, and all other cases should 97 | * return 'x'. 98 | */ 99 | #ifdef USEFULBUF_DISABLE_ALL_FLOAT 100 | #define FLOAT_ERR_CODE_NO_FLOAT(x) QCBOR_ERR_ALL_FLOAT_DISABLED 101 | #define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_ALL_FLOAT_DISABLED 102 | #define FLOAT_ERR_CODE_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED 103 | #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED 104 | #else /* USEFULBUF_DISABLE_ALL_FLOAT*/ 105 | #define FLOAT_ERR_CODE_NO_FLOAT(x) x 106 | #ifdef QCBOR_DISABLE_PREFERRED_FLOAT 107 | #define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_HALF_PRECISION_DISABLED 108 | #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HALF_PRECISION_DISABLED 109 | #else /* QCBOR_DISABLE_PREFERRED_FLOAT */ 110 | #define FLOAT_ERR_CODE_NO_HALF_PREC(x) x 111 | #ifdef QCBOR_DISABLE_FLOAT_HW_USE 112 | #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED 113 | #else 114 | #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) x 115 | #endif 116 | #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ 117 | #ifdef QCBOR_DISABLE_FLOAT_HW_USE 118 | #define FLOAT_ERR_CODE_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED 119 | #else /* QCBOR_DISABLE_FLOAT_HW_USE */ 120 | #define FLOAT_ERR_CODE_NO_FLOAT_HW(x) x 121 | #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ 122 | #endif /*USEFULBUF_DISABLE_ALL_FLOAT*/ 123 | 124 | 125 | /* 126 | * These are special values for the AdditionalInfo bits that are part of 127 | * the first byte. Mostly they encode the length of the data item. 128 | */ 129 | #define LEN_IS_ONE_BYTE 24 130 | #define LEN_IS_TWO_BYTES 25 131 | #define LEN_IS_FOUR_BYTES 26 132 | #define LEN_IS_EIGHT_BYTES 27 133 | #define ADDINFO_RESERVED1 28 134 | #define ADDINFO_RESERVED2 29 135 | #define ADDINFO_RESERVED3 30 136 | #define LEN_IS_INDEFINITE 31 137 | 138 | 139 | /* 140 | * 24 is a special number for CBOR. Integers and lengths 141 | * less than it are encoded in the same byte as the major type. 142 | */ 143 | #define CBOR_TWENTY_FOUR 24 144 | 145 | 146 | /* 147 | * Values for the 5 bits for items of major type 7 148 | */ 149 | #define CBOR_SIMPLEV_FALSE 20 150 | #define CBOR_SIMPLEV_TRUE 21 151 | #define CBOR_SIMPLEV_NULL 22 152 | #define CBOR_SIMPLEV_UNDEF 23 153 | #define CBOR_SIMPLEV_ONEBYTE 24 154 | #define HALF_PREC_FLOAT 25 155 | #define SINGLE_PREC_FLOAT 26 156 | #define DOUBLE_PREC_FLOAT 27 157 | #define CBOR_SIMPLE_BREAK 31 158 | #define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE 159 | #define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK 160 | 161 | 162 | /* The largest offset to the start of an array or map. It is slightly 163 | * less than UINT32_MAX so the error condition can be tested on 32-bit 164 | * machines. UINT32_MAX comes from uStart in QCBORTrackNesting being 165 | * a uin32_t. 166 | * 167 | * This will cause trouble on a machine where size_t is less than 32-bits. 168 | */ 169 | #define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) 170 | 171 | 172 | /* The number of tags that are 16-bit or larger that can be handled 173 | * in a decode. 174 | */ 175 | #define QCBOR_NUM_MAPPED_TAGS 4 176 | 177 | /* The number of tags (of any size) recorded for an individual item. */ 178 | #define QCBOR_MAX_TAGS_PER_ITEM1 4 179 | 180 | 181 | 182 | 183 | /* 184 | * PRIVATE DATA STRUCTURE 185 | * 186 | * Holds the data for tracking array and map nesting during 187 | * encoding. Pairs up with the Nesting_xxx functions to make an 188 | * "object" to handle nesting encoding. 189 | * 190 | * uStart is a uint32_t instead of a size_t to keep the size of this 191 | * struct down so it can be on the stack without any concern. It 192 | * would be about double if size_t was used instead. 193 | * 194 | * Size approximation (varies with CPU/compiler): 195 | * 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes 196 | * 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes 197 | */ 198 | typedef struct __QCBORTrackNesting { 199 | /* PRIVATE DATA STRUCTURE */ 200 | struct { 201 | /* See QCBOREncode_OpenMapOrArray() for details on how this works */ 202 | uint32_t uStart; /* uStart is the position where the array starts */ 203 | uint16_t uCount; /* Number of items in the arrary or map; counts items 204 | * in a map, not pairs of items */ 205 | uint8_t uMajorType; /* Indicates if item is a map or an array */ 206 | } pArrays[QCBOR_MAX_ARRAY_NESTING+1], /* stored state for nesting levels */ 207 | *pCurrentNesting; /* the current nesting level */ 208 | } QCBORTrackNesting; 209 | 210 | 211 | /* 212 | * PRIVATE DATA STRUCTURE 213 | * 214 | * Context / data object for encoding some CBOR. Used by all encode 215 | * functions to form a public "object" that does the job of encdoing. 216 | * 217 | * Size approximation (varies with CPU/compiler): 218 | * 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes 219 | * 32-bit machine: 15 + 1 + 132 = 148 bytes 220 | */ 221 | struct _QCBOREncodeContext { 222 | /* PRIVATE DATA STRUCTURE */ 223 | UsefulOutBuf OutBuf; /* Pointer to output buffer, its length and 224 | * position in it. */ 225 | uint8_t uError; /* Error state, always from QCBORError enum */ 226 | QCBORTrackNesting nesting; /* Keep track of array and map nesting */ 227 | }; 228 | 229 | 230 | /* 231 | * PRIVATE DATA STRUCTURE 232 | * 233 | * Holds the data for array and map nesting for decoding work. This 234 | * structure and the DecodeNesting_Xxx() functions in qcbor_decode.c 235 | * form an "object" that does the work for arrays and maps. All access 236 | * to this structure is through DecodeNesting_Xxx() functions. 237 | * 238 | * 64-bit machine size 239 | * 128 = 16 * 8 for the two unions 240 | * 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment 241 | * 16 = 16 bytes for two pointers 242 | * 208 TOTAL 243 | * 244 | * 32-bit machine size is 200 bytes 245 | */ 246 | typedef struct __QCBORDecodeNesting { 247 | /* PRIVATE DATA STRUCTURE */ 248 | struct nesting_decode_level { 249 | /* 250 | * This keeps tracking info for each nesting level. There are two 251 | * main types of levels: 252 | * 1) Byte count tracking. This is for the top level input CBOR 253 | * which might be a single item or a CBOR sequence and byte 254 | * string wrapped encoded CBOR. 255 | * 2) Item count tracking. This is for maps and arrays. 256 | * 257 | * uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and 258 | * QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY 259 | * for 2). 260 | * 261 | * Item count tracking is either for definite or indefinite-length 262 | * maps/arrays. For definite lengths, the total count and items 263 | * unconsumed are tracked. For indefinite-length, uTotalCount is 264 | * QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and 265 | * there is no per-item count of members. For indefinite-length 266 | * maps and arrays, uCountCursor is UINT16_MAX if not consumed 267 | * and zero if it is consumed in the pre-order 268 | * traversal. Additionally, if entered in bounded mode, 269 | * uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate 270 | * it is empty. 271 | * 272 | * This also records whether a level is bounded or not. All 273 | * byte-count tracked levels (the top-level sequence and 274 | * bstr-wrapped CBOR) are bounded implicitly. Maps and arrays 275 | * may or may not be bounded. They are bounded if they were 276 | * Entered() and not if they were traversed with GetNext(). They 277 | * are marked as bounded by uStartOffset not being @c UINT32_MAX. 278 | */ 279 | /* 280 | * If uLevelType can put in a separately indexed array, the 281 | * union/struct will be 8 bytes rather than 9 and a lot of 282 | * wasted padding for alignment will be saved. 283 | */ 284 | uint8_t uLevelType; 285 | union { 286 | struct { 287 | #define QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH UINT16_MAX 288 | #define QCBOR_COUNT_INDICATES_ZERO_LENGTH UINT16_MAX-1 289 | uint16_t uCountTotal; 290 | uint16_t uCountCursor; 291 | #define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX 292 | /* The start of the array or map in bounded mode so 293 | * the input can be rewound for GetInMapXx() by label. */ 294 | uint32_t uStartOffset; 295 | } ma; /* for maps and arrays */ 296 | struct { 297 | /* The end of the input before the bstr was entered so that 298 | * it can be restored when the bstr is exited. */ 299 | uint32_t uSavedEndOffset; 300 | /* The beginning of the bstr so that it can be rewound. */ 301 | uint32_t uBstrStartOffset; 302 | } bs; /* for top-level sequence and bstr-wrapped CBOR */ 303 | } u; 304 | } pLevels[QCBOR_MAX_ARRAY_NESTING+1], 305 | *pCurrent, 306 | *pCurrentBounded; 307 | /* 308 | * pCurrent is for item-by-item pre-order traversal. 309 | * 310 | * pCurrentBounded points to the current bounding level or is NULL 311 | * if there isn't one. 312 | * 313 | * pCurrent must always be below pCurrentBounded as the pre-order 314 | * traversal is always bounded by the bounding level. 315 | * 316 | * When a bounded level is entered, the pre-order traversal is set 317 | * to the first item in the bounded level. When a bounded level is 318 | * exited, the pre-order traversl is set to the next item after the 319 | * map, array or bstr. This may be more than one level up, or even 320 | * the end of the input CBOR. 321 | */ 322 | } QCBORDecodeNesting; 323 | 324 | 325 | typedef struct { 326 | /* PRIVATE DATA STRUCTURE */ 327 | void *pAllocateCxt; 328 | UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize); 329 | } QCBORInternalAllocator; 330 | 331 | 332 | /* 333 | * PRIVATE DATA STRUCTURE 334 | * 335 | * The decode context. This data structure plus the public 336 | * QCBORDecode_xxx functions form an "object" that does CBOR decoding. 337 | * 338 | * Size approximation (varies with CPU/compiler): 339 | * 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes 340 | * 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes 341 | */ 342 | struct _QCBORDecodeContext { 343 | /* PRIVATE DATA STRUCTURE */ 344 | UsefulInputBuf InBuf; 345 | 346 | QCBORDecodeNesting nesting; 347 | 348 | /* If a string allocator is configured for indefinite-length 349 | * strings, it is configured here. 350 | */ 351 | QCBORInternalAllocator StringAllocator; 352 | 353 | /* These are special for the internal MemPool allocator. They are 354 | * not used otherwise. We tried packing these in the MemPool 355 | * itself, but there are issues with memory alignment. 356 | */ 357 | uint32_t uMemPoolSize; 358 | uint32_t uMemPoolFreeOffset; 359 | 360 | /* A cached offset to the end of the current map 0 if no value is 361 | * cached. 362 | */ 363 | #define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX 364 | uint32_t uMapEndOffsetCache; 365 | 366 | uint8_t uDecodeMode; 367 | uint8_t bStringAllocateAll; 368 | uint8_t uLastError; /* QCBORError stuffed into a uint8_t */ 369 | 370 | /* See MapTagNumber() for description of how tags are mapped. */ 371 | uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS]; 372 | 373 | uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1]; 374 | }; 375 | 376 | 377 | /* Used internally in the impementation here Must not conflict with 378 | * any of the official CBOR types 379 | */ 380 | #define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 381 | #define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12 382 | 383 | 384 | /* Add this to types to indicate they are to be encoded as indefinite lengths */ 385 | #define QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 0x80 386 | #define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN \ 387 | CBOR_MAJOR_TYPE_ARRAY + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 388 | #define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN \ 389 | CBOR_MAJOR_TYPE_MAP + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 390 | #define CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK \ 391 | CBOR_MAJOR_TYPE_SIMPLE + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 392 | 393 | 394 | /* Value of QCBORItem.val.string.len when the string length is 395 | * indefinite. Used temporarily in the implementation and never 396 | * returned in the public interface. 397 | */ 398 | #define QCBOR_STRING_LENGTH_INDEFINITE SIZE_MAX 399 | 400 | 401 | /* The number of elements in a C array of a particular type */ 402 | #define C_ARRAY_COUNT(array, type) (sizeof(array)/sizeof(type)) 403 | 404 | 405 | #ifdef __cplusplus 406 | } 407 | #endif 408 | 409 | #endif /* qcbor_private_h */ 410 | -------------------------------------------------------------------------------- /src/UsefulBuf.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | * Copyright (c) 2016-2018, The Linux Foundation. 3 | * Copyright (c) 2018-2024, Laurence Lundblade. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above 12 | * copyright notice, this list of conditions and the following 13 | * disclaimer in the documentation and/or other materials provided 14 | * with the distribution. 15 | * * Neither the name of The Linux Foundation nor the names of its 16 | * contributors, nor the name "Laurence Lundblade" may be used to 17 | * endorse or promote products derived from this software without 18 | * specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 21 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 29 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 30 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | * ========================================================================= */ 32 | 33 | 34 | 35 | /*============================================================================= 36 | FILE: UsefulBuf.c 37 | 38 | DESCRIPTION: General purpose input and output buffers 39 | 40 | EDIT HISTORY FOR FILE: 41 | 42 | This section contains comments describing changes made to the module. 43 | Notice that changes are listed in reverse chronological order. 44 | 45 | when who what, where, why 46 | -------- ---- --------------------------------------------------- 47 | 08/08/2024 llundblade Add UsefulOutBuf_SubString(). 48 | 21/05/2024 llundblade Comment formatting and some code tidiness. 49 | 19/12/2022 llundblade Don't pass NULL to memmove when adding empty data. 50 | 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf 51 | 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual 52 | 01/28/2020 llundblade Refine integer signedness to quiet static analysis. 53 | 01/08/2020 llundblade Documentation corrections & improved code formatting. 54 | 11/08/2019 llundblade Re check pointer math and update comments 55 | 3/6/2019 llundblade Add UsefulBuf_IsValue() 56 | 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off 57 | the end of memory when the bytes to find is longer 58 | than the bytes to search. 59 | 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison 60 | for < or > for unequal length buffers. Added 61 | UsefulBuf_Set() function. 62 | 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst 63 | 11/13/16 llundbla Initial Version. 64 | 65 | ============================================================================*/ 66 | 67 | #include "UsefulBuf.h" 68 | 69 | /* used to catch use of uninitialized or corrupted UsefulOutBuf */ 70 | #define USEFUL_OUT_BUF_MAGIC (0x0B0F) 71 | 72 | 73 | /* 74 | * Public function -- see UsefulBuf.h 75 | */ 76 | UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src) 77 | { 78 | /* Do this with subtraction so it doesn't give an erroneous 79 | * result if uOffset + Src.len overflows. Right side is equivalent to 80 | * uOffset + Src.len > Dest.len 81 | */ 82 | if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { 83 | return NULLUsefulBufC; 84 | } 85 | 86 | memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len); 87 | 88 | return (UsefulBufC){Dest.ptr, Src.len + uOffset}; 89 | } 90 | 91 | 92 | /* 93 | * Public function -- see UsefulBuf.h 94 | */ 95 | int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2) 96 | { 97 | /* Use comparisons rather than subtracting lengths to 98 | * return an int instead of a size_t 99 | */ 100 | if(UB1.len < UB2.len) { 101 | return -1; 102 | } else if (UB1.len > UB2.len) { 103 | return 1; 104 | } /* else UB1.len == UB2.len */ 105 | 106 | return memcmp(UB1.ptr, UB2.ptr, UB1.len); 107 | } 108 | 109 | 110 | /* 111 | * Public function -- see UsefulBuf.h 112 | */ 113 | size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) 114 | { 115 | if(UsefulBuf_IsNULLOrEmptyC(UB)) { 116 | /* Not a match */ 117 | return 0; 118 | } 119 | 120 | const uint8_t * const pEnd = (const uint8_t *)UB.ptr + UB.len; 121 | for(const uint8_t *p = UB.ptr; p < pEnd; p++) { 122 | if(*p != uValue) { 123 | /* Byte didn't match */ 124 | /* Cast from signed to unsigned. Safe because the loop increments.*/ 125 | return (size_t)(p - (const uint8_t *)UB.ptr); 126 | } 127 | } 128 | 129 | /* Success. All bytes matched */ 130 | return SIZE_MAX; 131 | } 132 | 133 | 134 | /* 135 | * Public function -- see UsefulBuf.h 136 | */ 137 | size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) 138 | { 139 | if(BytesToSearch.len < BytesToFind.len) { 140 | return SIZE_MAX; 141 | } 142 | 143 | for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) { 144 | UsefulBufC SearchNext; 145 | 146 | SearchNext.ptr = ((const uint8_t *)BytesToSearch.ptr) + uPos; 147 | SearchNext.len = BytesToFind.len; 148 | if(!UsefulBuf_Compare(SearchNext, BytesToFind)) { 149 | return uPos; 150 | } 151 | } 152 | 153 | return SIZE_MAX; 154 | } 155 | 156 | 157 | /* 158 | * Public function -- see UsefulBuf.h 159 | * 160 | * Code Reviewers: THIS FUNCTION DOES POINTER MATH 161 | */ 162 | void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) 163 | { 164 | pMe->magic = USEFUL_OUT_BUF_MAGIC; 165 | UsefulOutBuf_Reset(pMe); 166 | pMe->UB = Storage; 167 | 168 | #if 0 169 | /* This check is off by default. 170 | * 171 | * The following check fails on ThreadX 172 | * 173 | * Sanity check on the pointer and size to be sure we are not 174 | * passed a buffer that goes off the end of the address space. 175 | * Given this test, we know that all unsigned lengths less than 176 | * me->size are valid and won't wrap in any pointer additions 177 | * based off of pStorage in the rest of this code. 178 | */ 179 | const uintptr_t ptrM = UINTPTR_MAX - Storage.len; 180 | if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) /* Check #0 */ 181 | me->err = 1; 182 | #endif 183 | } 184 | 185 | 186 | 187 | /* 188 | * Public function -- see UsefulBuf.h 189 | * 190 | * The core of UsefulOutBuf -- put some bytes in the buffer without writing off 191 | * the end of it. 192 | * 193 | * Code Reviewers: THIS FUNCTION DOES POINTER MATH 194 | * 195 | * This function inserts the source buffer, NewData, into the destination 196 | * buffer, me->UB.ptr. 197 | * 198 | * Destination is represented as: 199 | * me->UB.ptr -- start of the buffer 200 | * me->UB.len -- size of the buffer UB.ptr 201 | * me->data_len -- length of value data in UB 202 | * 203 | * Source is data: 204 | * NewData.ptr -- start of source buffer 205 | * NewData.len -- length of source buffer 206 | * 207 | * Insertion point: 208 | * uInsertionPos. 209 | * 210 | * Steps: 211 | * 212 | * 0. Corruption checks on UsefulOutBuf 213 | * 214 | * 1. Figure out if the new data will fit or not 215 | * 216 | * 2. Is insertion position in the range of valid data? 217 | * 218 | * 3. If insertion point is not at the end, slide data to the right of the 219 | * insertion point to the right 220 | * 221 | * 4. Put the new data in at the insertion position. 222 | * 223 | */ 224 | void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos) 225 | { 226 | if(pMe->err) { 227 | /* Already in error state. */ 228 | return; 229 | } 230 | 231 | /* 0. Sanity check the UsefulOutBuf structure 232 | * A "counter measure". If magic number is not the right number it 233 | * probably means pMe was not initialized or it was corrupted. Attackers 234 | * can defeat this, but it is a hurdle and does good with very 235 | * little code. 236 | */ 237 | if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { 238 | pMe->err = 1; 239 | return; /* Magic number is wrong due to uninitalization or corrption */ 240 | } 241 | 242 | /* Make sure valid data is less than buffer size. This would only occur 243 | * if there was corruption of me, but it is also part of the checks to 244 | * be sure there is no pointer arithmatic under/overflow. 245 | */ 246 | if(pMe->data_len > pMe->UB.len) { /* Check #1 */ 247 | pMe->err = 1; 248 | /* Offset of valid data is off the end of the UsefulOutBuf due to 249 | * uninitialization or corruption 250 | */ 251 | return; 252 | } 253 | 254 | /* 1. Will it fit? 255 | * WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len) 256 | * Check #1 makes sure subtraction in RoomLeft will not wrap around 257 | */ 258 | if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { /* Check #2 */ 259 | /* The new data will not fit into the the buffer. */ 260 | pMe->err = 1; 261 | return; 262 | } 263 | 264 | /* 2. Check the Insertion Position 265 | * This, with Check #1, also confirms that uInsertionPos <= me->data_len and 266 | * that uInsertionPos + pMe->UB.ptr will not wrap around the end of the 267 | * address space. 268 | */ 269 | if(uInsertionPos > pMe->data_len) { /* Check #3 */ 270 | /* Off the end of the valid data in the buffer. */ 271 | pMe->err = 1; 272 | return; 273 | } 274 | 275 | /* 3. Slide existing data to the right */ 276 | if (!UsefulOutBuf_IsBufferNULL(pMe)) { 277 | uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; /* PtrMath #1 */ 278 | size_t uNumBytesToMove = pMe->data_len - uInsertionPos; /* PtrMath #2 */ 279 | uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; /* PtrMath #3*/ 280 | 281 | /* To know memmove won't go off end of destination, see PtrMath #4. 282 | * Use memove because it handles overlapping buffers 283 | */ 284 | memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove); 285 | 286 | /* 4. Put the new data in */ 287 | uint8_t *pInsertionPoint = pSourceOfMove; 288 | /* To know memmove won't go off end of destination, see PtrMath #5 */ 289 | if(NewData.ptr != NULL) { 290 | memmove(pInsertionPoint, NewData.ptr, NewData.len); 291 | } 292 | } 293 | 294 | pMe->data_len += NewData.len; 295 | } 296 | 297 | 298 | /* 299 | * Rationale that describes why the above pointer math is safe 300 | * 301 | * PtrMath #1 will never wrap around over because 302 | * Check #0 in UsefulOutBuf_Init that me->UB.ptr + me->UB.len doesn't wrap 303 | * Check #1 makes sure me->data_len is less than me->UB.len 304 | * Check #3 makes sure uInsertionPos is less than me->data_len 305 | * 306 | * PtrMath #2 will never wrap around under because 307 | * Check #3 makes sure uInsertionPos is less than me->data_len 308 | * 309 | * PtrMath #3 will never wrap around over because 310 | * PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len 311 | * Check #2 that NewData.len will fit in the unused space left in me->UB 312 | * 313 | * PtrMath #4 will never wrap under because 314 | * Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) 315 | * Check #3 makes sure uInsertionPos is less than me->data_len 316 | * Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) 317 | * This algebraically rearranges to me->size > uInsertionPos + NewData.len 318 | * 319 | * PtrMath #5 will never wrap under because 320 | * Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; 321 | * Check #1 makes sure me->data_len is less than me->size 322 | * Check #3 makes sure uInsertionPos is less than me->data_len 323 | */ 324 | 325 | 326 | /* 327 | * Public function for advancing data length. See qcbor/UsefulBuf.h 328 | */ 329 | void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount) 330 | { 331 | /* This function is a trimmed down version of 332 | * UsefulOutBuf_InsertUsefulBuf(). This could be combined with the 333 | * code in UsefulOutBuf_InsertUsefulBuf(), but that would make 334 | * UsefulOutBuf_InsertUsefulBuf() bigger and this will be very 335 | * rarely used. 336 | */ 337 | 338 | if(pMe->err) { 339 | /* Already in error state. */ 340 | return; 341 | } 342 | 343 | /* 0. Sanity check the UsefulOutBuf structure 344 | * 345 | * A "counter measure". If magic number is not the right number it 346 | * probably means me was not initialized or it was 347 | * corrupted. Attackers can defeat this, but it is a hurdle and 348 | * does good with very little code. 349 | */ 350 | if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { 351 | pMe->err = 1; 352 | return; /* Magic number is wrong due to uninitalization or corrption */ 353 | } 354 | 355 | /* Make sure valid data is less than buffer size. This would only 356 | * occur if there was corruption of me, but it is also part of the 357 | * checks to be sure there is no pointer arithmatic 358 | * under/overflow. 359 | */ 360 | if(pMe->data_len > pMe->UB.len) { /* Check #1 */ 361 | pMe->err = 1; 362 | /* Offset of valid data is off the end of the UsefulOutBuf due 363 | * to uninitialization or corruption. 364 | */ 365 | return; 366 | } 367 | 368 | /* 1. Will it fit? 369 | * 370 | * WillItFit() is the same as: NewData.len <= (me->UB.len - 371 | * me->data_len) Check #1 makes sure subtraction in RoomLeft will 372 | * not wrap around 373 | */ 374 | if(! UsefulOutBuf_WillItFit(pMe, uAmount)) { /* Check #2 */ 375 | /* The new data will not fit into the the buffer. */ 376 | pMe->err = 1; 377 | return; 378 | } 379 | 380 | pMe->data_len += uAmount; 381 | } 382 | 383 | 384 | /* 385 | * Public function -- see UsefulBuf.h 386 | */ 387 | UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe) 388 | { 389 | if(pMe->err) { 390 | return NULLUsefulBufC; 391 | } 392 | 393 | if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { 394 | pMe->err = 1; 395 | return NULLUsefulBufC; 396 | } 397 | 398 | return (UsefulBufC){pMe->UB.ptr, pMe->data_len}; 399 | } 400 | 401 | 402 | /* 403 | * Public function -- see UsefulBuf.h 404 | * 405 | * Copy out the data accumulated in to the output buffer. 406 | */ 407 | UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest) 408 | { 409 | const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe); 410 | if(UsefulBuf_IsNULLC(Tmp)) { 411 | return NULLUsefulBufC; 412 | } 413 | return UsefulBuf_Copy(pDest, Tmp); 414 | } 415 | 416 | 417 | /* 418 | * Public function -- see UsefulBuf.h 419 | * 420 | * Code Reviewers: THIS FUNCTION DOES POINTER MATH 421 | */ 422 | UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe, 423 | const size_t uStart, 424 | const size_t uLen) 425 | { 426 | const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe); 427 | 428 | if(UsefulBuf_IsNULLC(Tmp)) { 429 | return NULLUsefulBufC; 430 | } 431 | 432 | if(uStart > Tmp.len) { 433 | return NULLUsefulBufC; 434 | } 435 | 436 | if(Tmp.len - uStart < uLen) { 437 | return NULLUsefulBufC; 438 | } 439 | 440 | UsefulBufC SubString; 441 | SubString.ptr = (const uint8_t *)Tmp.ptr + uStart; 442 | SubString.len = uLen; 443 | 444 | return SubString; 445 | } 446 | 447 | 448 | /* 449 | * Public function -- see UsefulBuf.h 450 | * 451 | * The core of UsefulInputBuf -- consume bytes without going off end of buffer. 452 | * 453 | * Code Reviewers: THIS FUNCTION DOES POINTER MATH 454 | */ 455 | const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount) 456 | { 457 | /* Already in error state. Do nothing. */ 458 | if(pMe->err) { 459 | return NULL; 460 | } 461 | 462 | if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) { 463 | /* Number of bytes asked for is more than available */ 464 | pMe->err = 1; 465 | return NULL; 466 | } 467 | 468 | /* This is going to succeed */ 469 | const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor; 470 | /* Won't overflow because of check using UsefulInputBuf_BytesAvailable() */ 471 | pMe->cursor += uAmount; 472 | return result; 473 | } 474 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true) 2 | 3 | **QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that 4 | implements these RFCs: 5 | 6 | * [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything 7 | except sorting of encoded maps) 8 | * [RFC7049](https://tools.ietf.org/html/rfc7049) The previous CBOR standard. 9 | Replaced by RFC 8949. 10 | * [RFC8742](https://tools.ietf.org/html/rfc8742) CBOR Sequences 11 | * [RFC8943](https://tools.ietf.org/html/rfc8943) CBOR Dates 12 | 13 | ## QCBOR v2 alpha release 14 | 15 | Alpha releases of QCBOR 2.0 are available [here](https://github.com/laurencelundblade/QCBOR/tree/dev). 16 | It includes: 17 | 18 | * Better tag handling 19 | * Map sorting 20 | * Modes for CDE and Preferred Serialization 21 | * dCBOR support 22 | * Better big number support 23 | 24 | ## QCBOR Characteristics 25 | 26 | **Implemented in C with minimal dependency** – Dependent only 27 | on C99, , , and making 28 | it highly portable. and are used too, but their 29 | use can disabled. No #ifdefs or compiler options need to be set for 30 | QCBOR to run correctly. 31 | 32 | **Focused on C / native data representation** – Careful conversion of 33 | CBOR data types in to C data types, handling over and 34 | underflow, strict typing and such so the caller doesn't have to 35 | worry so much about this and so code using QCBOR passes static 36 | analyzers easier. Simpler code because there is no support for 37 | encoding/decoding to/from JSON, pretty printing, diagnostic 38 | notation... Only encoding from native C representations and decoding 39 | to native C representations is supported. 40 | 41 | **Small simple memory model** – Malloc is not needed. The encode 42 | context is 176 bytes, decode context is 312 bytes and the 43 | description of decoded data item is 56 bytes. Stack use is light and 44 | there is no recursion. The caller supplies the memory to hold the 45 | encoded CBOR and encode/decode contexts so caller has full control 46 | of memory usage making it good for embedded implementations that 47 | have to run in small fixed memory. 48 | 49 | **Easy decoding of maps** – The "spiffy decode" functions allow 50 | fetching map items directly by label. Detection of duplicate map 51 | items is automatically performed. This makes decoding of complex 52 | protocols much simpler, say when compared to TinyCBOR. 53 | 54 | **Supports most of RFC 8949** – With some size limits, all data types 55 | and formats in the specification are supported. Map sorting is main 56 | CBOR feature that is not supported. The same decoding API supports 57 | both definite and indefinite-length map and array decoding. Decoding 58 | indefinite length strings is supported but requires a string 59 | allocator be set up. Encoding of indefinite length strings is 60 | planned, but not yet supported. 61 | 62 | **Extensible and general** – Provides a way to handle data types that 63 | are not directly supported. 64 | 65 | **Secure coding style** – Uses a construct called UsefulBuf as a 66 | discipline for very safe coding and handling of binary data. 67 | 68 | **Small code size** – In the smallest configuration the object 69 | code is less than 4KB on 64-bit x86 CPUs. The design is such that 70 | object code for QCBOR APIs not used is not referenced. 71 | 72 | **Clear documented public interface** – The public interface is 73 | separated from the implementation. It can be put to use without 74 | reading the source. 75 | 76 | **Comprehensive test suite** – Easy to verify on a new platform or OS 77 | with the test suite. The test suite dependencies are minimal and the 78 | same as the library's. 79 | 80 | ## Documentation 81 | 82 | Full API documentation is at https://www.securitytheory.com/qcbor-docs/ 83 | 84 | 85 | ## Spiffy Decode 86 | 87 | These are functions to decode particular data types. They are an 88 | alternative to and built on top of QCBORDecode_GetNext(). They do type 89 | checking and in some cases sophisticated type conversion. 90 | 91 | Spiffy decode supports easier map and array decoding. A map can be 92 | descended into with QCBORDecode_EnterMap(). When a map has been 93 | entered, members can be retrieved by label. Detection of duplicate 94 | map labels, an error, is automatically performed. 95 | 96 | An internal error state is maintained. This simplifies the decode 97 | implementation as an error check is only needed at the end of the 98 | decode, rather than on every function. 99 | 100 | An outcome is that decoding implementations are simple and involve 101 | many fewer lines of code. They also tend to parallel the encoding 102 | implementations as seen in the following example. 103 | 104 | /* Encode */ 105 | QCBOREncode_Init(&EncodeCtx, Buffer); 106 | QCBOREncode_OpenMap(&EncodeCtx); 107 | QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pE->Manufacturer); 108 | QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pE->uDisplacement); 109 | QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pE->uHorsePower); 110 | QCBOREncode_CloseMap(&EncodeCtx); 111 | uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedEngine); 112 | 113 | /* Decode */ 114 | QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL); 115 | QCBORDecode_EnterMap(&DecodeCtx); 116 | QCBORDecode_GetTextStringInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer)); 117 | QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement)); 118 | QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower)); 119 | QCBORDecode_ExitMap(&DecodeCtx); 120 | uErr = QCBORDecode_Finish(&DecodeCtx); 121 | 122 | The spiffy decode functions will handle definite and indefinite length 123 | maps and arrays without the caller having to do anything. This 124 | includes mixed definite and indefinte maps and arrays. (Some work 125 | remains to support map searching with indefinite length strings.) 126 | 127 | ## Comparison to TinyCBOR 128 | 129 | TinyCBOR is a popular widely used implementation. Like QCBOR, 130 | it is a solid, well-maintained commercial quality implementation. This 131 | section is for folks trying to understand the difference in 132 | the approach between QCBOR and TinyCBOR. 133 | 134 | TinyCBOR's API is more minimalist and closer to the CBOR 135 | encoding mechanics than QCBOR's. QCBOR's API is at a somewhat higher 136 | level of abstraction. 137 | 138 | QCBOR really does implement just about everything described in 139 | RFC 8949. The main part missing is sorting of maps when encoding. 140 | TinyCBOR implements a smaller part of the standard. 141 | 142 | No detailed code size comparison has been made, but in a spot check 143 | that encodes and decodes a single integer shows QCBOR about 25% 144 | larger. QCBOR encoding is actually smaller, but QCBOR decoding is 145 | larger. This includes the code to call the library, which is about the 146 | same for both libraries, and the code linked from the libraries. QCBOR 147 | is a bit more powerful, so you get value for the extra code brought 148 | in, especially when decoding more complex protocols. 149 | 150 | QCBOR tracks encoding and decoding errors internally so the caller 151 | doesn't have to check the return code of every call to an encode or 152 | decode function. In many cases the error check is only needed as the 153 | last step or an encode or decode. TinyCBOR requires an error check on 154 | each call. 155 | 156 | QCBOR provides a substantial feature that allows searching for data 157 | items in a map by label. It works for integer and text string labels 158 | (and at some point byte-string labels). This includes detection of 159 | items with duplicate labels. This makes the code for decoding CBOR 160 | simpler, similar to the encoding code and easier to read. TinyCBOR 161 | supports search by string, but no integer, nor duplicate detection. 162 | 163 | QCBOR provides explicit support many of the registered CBOR tags. For 164 | example, QCBOR supports big numbers and decimal fractions including 165 | their conversion to floats, uint64_t and such. 166 | 167 | Generally, QCBOR supports safe conversion of most CBOR number formats 168 | into number formats supported in C. For example, a data item can be 169 | fetched and converted to a C uint64_t whether the input CBOR is an 170 | unsigned 64-bit integer, signed 64-bit integer, floating-point number, 171 | big number, decimal fraction or a big float. The conversion is 172 | performed with full proper error detection of overflow and underflow. 173 | 174 | QCBOR has a special feature for decoding byte-string wrapped CBOR. It 175 | treats this similar to entering an array with one item. This is 176 | particularly use for CBOR protocols like COSE that make use of 177 | byte-string wrapping. The implementation of these protocols is 178 | simpler and uses less memory. 179 | 180 | QCBOR's test suite is written in the same portable C that QCBOR is 181 | where TinyCBOR requires Qt for its test. QCBOR's test suite is 182 | designed to be able to run on small embedded devices the same as 183 | QCBOR. 184 | 185 | ## Code Status 186 | 187 | The official current release is version 1.6. Changes over the last few 188 | years have been only minor bug fixes, minor feature additions and 189 | documentation improvements. QCBOR 1.x is highly stable. 190 | 191 | Work on some larger feature additions is ongoing in "dev" branch. 192 | This includes more explicit support for preferred serialization and 193 | CDE (CBOR Deterministic Encoding). It will eventually be release as 194 | QCBOR 2.x. 195 | 196 | QCBOR was originally developed by Qualcomm. It was [open sourced 197 | through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a 198 | permissive Linux license, September 2018 (thanks Qualcomm!). 199 | 200 | ## Building 201 | 202 | There is a simple makefile for the UNIX style command line binary that 203 | compiles everything to run the tests. CMake is also available, please read 204 | the "Building with CMake" section for more information. 205 | 206 | These eleven files, the contents of the src and inc directories, make 207 | up the entire implementation. 208 | 209 | * inc 210 | * UsefulBuf.h 211 | * qcbor_private.h 212 | * qcbor_common.h 213 | * qcbor_encode.h 214 | * qcbor_decode.h 215 | * qcbor_spiffy_decode.h 216 | * src 217 | * UsefulBuf.c 218 | * qcbor_encode.c 219 | * qcbor_decode.c 220 | * ieee754.h 221 | * ieee754.c 222 | 223 | For most use cases you should just be able to add them to your 224 | project. Hopefully the easy portability of this implementation makes 225 | this work straight away, whatever your development environment is. 226 | 227 | The test directory includes the tests that are nearly as portable as 228 | the main implementation. If your development environment doesn't 229 | support UNIX style command line and make, you should be able to make a 230 | simple project and add the test files to it. Then just call 231 | RunTests() to invoke them all. 232 | 233 | While this code will run fine without configuration, there are several 234 | C pre processor macros that can be #defined in order to: 235 | 236 | * use a more efficient implementation 237 | * to reduce code size 238 | * to improve performance (a little) 239 | * remove features to reduce code size 240 | 241 | See the comment sections on "Configuration" in inc/UsefulBuf.h and 242 | the pre processor defines that start with QCBOR_DISABLE_XXX. 243 | 244 | ### Building with CMake 245 | 246 | CMake can also be used to build QCBOR and the test application. Having the root 247 | `CMakeLists.txt` file, QCBOR can be easily integrated with your project's 248 | existing CMake environment. The result of the build process is a static library, 249 | to build a shared library instead you must add the 250 | `-DBUILD_SHARED_LIBS=ON` option at the CMake configuration step. 251 | The tests can be built into a simple command line application to run them as it 252 | was mentioned before; or it can be built as a library to be integrated with your 253 | development environment. 254 | The `BUILD_QCBOR_TEST` CMake option can be used for building the tests, it can 255 | have three values: `APP`, `LIB` or `OFF` (default, test are not included in the 256 | build). 257 | 258 | Building the QCBOR library: 259 | 260 | ```bash 261 | cd 262 | # Configuring the project and generating a native build system 263 | cmake -S . -B 264 | # Building the project 265 | cmake --build 266 | ``` 267 | 268 | Building and running the QCBOR test app: 269 | ```bash 270 | cd 271 | # Configuring the project and generating a native build system 272 | cmake -S . -B -DBUILD_QCBOR_TEST=APP 273 | # Building the project 274 | cmake --build 275 | # Running the test app 276 | ./test/qcbortest 277 | ``` 278 | 279 | To enable all the compiler warnings that are used in the QCBOR release process 280 | you can use the `BUILD_QCBOR_WARN` option at the CMake configuration step: 281 | ```bash 282 | cmake -S . -B -DBUILD_QCBOR_WARN=ON 283 | ``` 284 | 285 | ### Floating Point Support & Configuration 286 | 287 | By default, all QCBOR floating-point features are enabled: 288 | 289 | * Encoding and decoding of basic float types, single and double-precision 290 | * Encoding and decoding of half-precision with conversion to/from single 291 | and double-precision 292 | * Preferred serialization of floating-point 293 | * Floating point dates 294 | * Methods that can convert big numbers, decimal fractions and other numbers 295 | to/from floating-point 296 | 297 | If full floating-point is not needed, the following #defines can be 298 | used to reduce object code size and dependency. 299 | 300 | See discussion in qcbor_encode.h for other details. 301 | 302 | #### #define QCBOR_DISABLE_FLOAT_HW_USE 303 | 304 | This removes dependency on: 305 | 306 | * Floating-point hardware and floating-point instructions 307 | * `` and `` 308 | * The math library (libm, -lm) 309 | 310 | For most limited environments, this removes enough floating-point 311 | dependencies to be able to compile and run QCBOR. 312 | 313 | Note that this does not remove use of the types double and float from 314 | QCBOR, but it limits QCBOR's use of them to converting the encoded 315 | byte stream to them and copying them. Converting and copying them 316 | usually don't require any hardware, libraries or includes. The C 317 | compiler takes care of it on its own. 318 | 319 | QCBOR uses its own implementation of half-precision float-pointing 320 | that doesn't depend on math libraries. It uses masks and shifts 321 | instead. Thus, even with this define, half-precision encoding and 322 | decoding works. 323 | 324 | When this is defined, the QCBOR functionality lost is minimal and only 325 | for decoding: 326 | 327 | * Decoding floating-point format dates are not handled 328 | * There is no conversion between floats and integers when decoding. For 329 | example, QCBORDecode_GetUInt64ConvertAll() will be unable to convert 330 | to and from float-point. 331 | * Floats will be unconverted to double when decoding. 332 | 333 | No interfaces are disabled or removed with this define. If input that 334 | requires floating-point conversion or functions are called that 335 | request floating-point conversion, an error code like 336 | `QCBOR_ERR_HW_FLOAT_DISABLED` will be returned. 337 | 338 | This saves only a small amount of object code. The primary purpose for 339 | defining this is to remove dependency on floating point hardware and 340 | libraries. 341 | 342 | #### #define QCBOR_DISABLE_PREFERRED_FLOAT 343 | 344 | This eliminates support for half-precision 345 | and CBOR preferred serialization by disabling 346 | QCBOR's shift and mask based implementation of 347 | half-precision floating-point. 348 | 349 | With this defined, single and double-precision floating-point 350 | numbers can still be encoded and decoded. Conversion 351 | of floating-point to and from integers, big numbers and 352 | such is also supported. Floating-point dates are still 353 | supported. 354 | 355 | The primary reason to define this is to save object code. 356 | Roughly 900 bytes are saved, though about half of this 357 | can be saved just by not calling any functions that 358 | encode floating-point numbers. 359 | 360 | #### #define USEFULBUF_DISABLE_ALL_FLOAT 361 | 362 | This eliminates floating point support completely (along with related function 363 | headers). This is useful if the compiler options deny the usage of floating 364 | point operations completely, and the usage soft floating point ABI is not 365 | possible. 366 | 367 | #### Compiler options 368 | 369 | Compilers support a number of options that control 370 | which float-point related code is generated. For example, 371 | it is usually possible to give options to the compiler to avoid all 372 | floating-point hardware and instructions, to use software 373 | and replacement libraries instead. These are usually 374 | bigger and slower, but these options may still be useful 375 | in getting QCBOR to run in some environments in 376 | combination with `QCBOR_DISABLE_FLOAT_HW_USE`. 377 | In particular, `-mfloat-abi=soft`, disables use of 378 | hardware instructions for the float and double 379 | types in C for some architectures. 380 | 381 | #### CMake options 382 | 383 | If you are using CMake, it can also be used to configure the floating-point 384 | support. These options can be enabled by adding them to the CMake configuration 385 | step and setting their value to 'ON' (True). The following table shows the 386 | available options and the associated #defines. 387 | 388 | | CMake option | #define | 389 | |-----------------------------------|-------------------------------| 390 | | QCBOR_OPT_DISABLE_FLOAT_HW_USE | QCBOR_DISABLE_FLOAT_HW_USE | 391 | | QCBOR_OPT_DISABLE_FLOAT_PREFERRED | QCBOR_DISABLE_PREFERRED_FLOAT | 392 | | QCBOR_OPT_DISABLE_FLOAT_ALL | USEFULBUF_DISABLE_ALL_FLOAT | 393 | 394 | ## Code Size 395 | 396 | These are approximate sizes on a 64-bit x86 CPU with the -Os optimization. 397 | All QCBOR_DISABLE_XXX are set and compiler stack frame checking is disabled 398 | for smallest but not for largest. Smallest is the library functions for a 399 | protocol with strings, integers, arrays, maps and Booleans, but not floats 400 | and standard tag types. 401 | 402 | | | smallest | largest | 403 | |---------------|----------|---------| 404 | | encode only | 850 | 2200 | 405 | | decode only | 1550 | 13300 | 406 | | combined | 2500 | 15500 | 407 | 408 | From the table above, one can see that the amount of code pulled in 409 | from the QCBOR library varies a lot, ranging from 1KB to 15KB. The 410 | main factor is the number of QCBOR functions called and 411 | which ones they are. QCBOR minimizes internal 412 | interdependency so only code necessary for the called functions is 413 | brought in. 414 | 415 | Encoding is simpler and smaller. An encode-only implementation may 416 | bring in only 1KB of code. 417 | 418 | Encoding of floating-point brings in a little more code as does 419 | encoding of tagged types and encoding of bstr wrapping. 420 | 421 | Basic decoding using QCBORDecode_GetNext() brings in 3KB. 422 | 423 | Use of the supplied MemPool by calling QCBORDecode_SetMemPool() to 424 | setup to decode indefinite-length strings adds 0.5KB. 425 | 426 | Basic use of spiffy decode to brings in about 3KB. Using more spiffy 427 | decode functions, such as those for tagged types bstr wrapping brings 428 | in more code. 429 | 430 | Finally, use of all of the integer conversion functions will bring in 431 | about 5KB, though you can use the simpler ones like 432 | QCBORDecode_GetInt64() without bringing in very much code. 433 | 434 | In addition to using fewer QCBOR functions, the following are some 435 | ways to make the code smaller. 436 | 437 | The gcc compiler output is usually smaller than llvm because stack 438 | guards are off by default (be sure you actually have gcc and not llvm 439 | installed to be invoked by the gcc command). You can also turn off 440 | stack gaurds with llvm. It is safe to turn off stack gaurds with this 441 | code because Usefulbuf provides similar defenses and this code was 442 | carefully written to be defensive. 443 | 444 | If QCBOR is installed as a shared library, then of course only one 445 | copy of the code is in memory no matter how many applications use it. 446 | 447 | ### Disabling Features 448 | 449 | Here's the list of all features that can be disabled to save object 450 | code. The amount saved is an approximation. 451 | 452 | | #define | Saves | 453 | | ----------------------------------------| ------| 454 | | QCBOR_DISABLE_ENCODE_USAGE_GUARDS | 150 | 455 | | QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS | 400 | 456 | | QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS | 200 | 457 | | QCBOR_DISABLE_UNCOMMON_TAGS | 100 | 458 | | QCBOR_DISABLE_EXP_AND_MANTISSA | 400 | 459 | | QCBOR_DISABLE_PREFERRED_FLOAT | 900 | 460 | | QCBOR_DISABLE_FLOAT_HW_USE | 50 | 461 | | QCBOR_DISABLE_TAGS | 400 | 462 | | QCBOR_DISABLE_NON_INTEGER_LABELS | 140 | 463 | | USEFULBUF_DISABLE_ALL_FLOAT | 950 | 464 | 465 | QCBOR_DISABLE_ENCODE_USAGE_GUARDS affects encoding only. It doesn't 466 | disable any encoding features, just some error checking. Disable it 467 | when you are confident that an encoding implementation is complete and 468 | correct. 469 | 470 | Indefinite lengths are a feature of CBOR that makes encoding simpler 471 | and the decoding more complex. They allow the encoder to not have to 472 | know the length of a string, map or array when they start encoding 473 | it. Their main use is when encoding has to be done on a very 474 | constrained device. Conversely when decoding on a very constrained 475 | device, it is good to prohibit use of indefinite lengths so the 476 | decoder can be smaller. 477 | 478 | The QCBOR decode API processes both definite and indefinite lengths 479 | with the same API, except to decode indefinite-length strings a 480 | storage allocator must be configured. 481 | 482 | To reduce the size of the decoder define 483 | QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS particularly if you are not 484 | configuring a storage allocator. 485 | 486 | Further reduction can be by defining 487 | QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS which will result in an error 488 | when an indefinite-length map or array arrives for decoding. 489 | 490 | QCBOR_DISABLE_UNCOMMON_TAGS disables the decoding of explicit tags for 491 | base 64, regex, UUID and MIME data. This just disables the automatic 492 | recognition of these from a major type 6 tag. 493 | 494 | QCBOR_DISABLE_EXP_AND_MANTISSA disables the decoding of decimal 495 | fractions and big floats. 496 | 497 | QCBOR_DISABLE_TAGS disables all decoding of CBOR tags. If the input has 498 | a single tag, the error is unrecoverable so it is suitable only for protocols that 499 | have no tags. "Borrowed" tag content formats (e.g. an epoch-based date 500 | without the tag number), can still be processed. 501 | 502 | QCBOR_DISABLE_NON_INTEGER_LABELS causes any label that doesn't 503 | fit in an int64_t to result in a QCBOR_ERR_MAP_LABEL_TYPE error. 504 | This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and 505 | QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. It is fairly common for CBOR-based 506 | protocols to use only small integers as labels. 507 | 508 | See the discussion above on floating-point. 509 | 510 | ### Size of spiffy decode 511 | 512 | When creating a decode implementation, there is a choice of whether 513 | or not to use spiffy decode features or to just use 514 | QCBORDecode_GetNext(). 515 | 516 | The implementation using spiffy decode will be simpler resulting in 517 | the calling code being smaller, but the amount of code brought in 518 | from the QCBOR library will be larger. Basic use of spiffy decode 519 | brings in about 2KB of object code. If object code size is not a 520 | concern, then it is probably better to use spiffy decode because it 521 | is less work, there is less complexity and less testing to worry 522 | about. 523 | 524 | If code size is a concern, then use of QCBORDecode_GetNext() will 525 | probably result in smaller overall code size for simpler CBOR 526 | protocols. However, if the CBOR protocol is complex then use of 527 | spiffy decode may reduce overall code size. An example of a complex 528 | protocol is one that involves decoding a lot of maps or maps that 529 | have many data items in them. The overall code may be smaller 530 | because the general purpose spiffy decode map processor is the one 531 | used for all the maps. 532 | 533 | 534 | ## Other Software Using QCBOR 535 | 536 | * [t_cose](https://github.com/laurencelundblade/t_cose) implements enough of 537 | [COSE, RFC 8152](https://tools.ietf.org/html/rfc8152) to support 538 | [CBOR Web Token (CWT)](https://tools.ietf.org/html/rfc8392) and 539 | [Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-06). 540 | Specifically it supports signing and verification of the COSE_Sign1 message. 541 | 542 | * [ctoken](https://github.com/laurencelundblade/ctoken) is an implementation of 543 | EAT and CWT. 544 | 545 | ## Credits 546 | * Ganesh Kanike for porting to QSEE 547 | * Mark Bapst for sponsorship and release as open source by Qualcomm 548 | * Sachin Sharma for release through CAF 549 | * Tamas Ban for porting to TF-M and 32-bit ARM 550 | * Michael Eckel for Makefile improvements 551 | * Jan Jongboom for indefinite length encoding 552 | * Peter Uiterwijk for error strings and other 553 | * Michael Richarson for CI set up and fixing some compiler warnings 554 | * Máté Tóth-Pál for float-point disabling and other 555 | * Dave Thaler for portability to Windows 556 | 557 | 558 | ### Copyright for this README 559 | 560 | Copyright (c) 2018-2025, Laurence Lundblade. All rights reserved. 561 | Copyright (c) 2021-2023, Arm Limited. All rights reserved. 562 | -------------------------------------------------------------------------------- /inc/qcbor/qcbor_common.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | * Copyright (c) 2016-2018, The Linux Foundation. 3 | * Copyright (c) 2018-2025, Laurence Lundblade. 4 | * Copyright (c) 2021, Arm Limited. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are 9 | * met: 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above 13 | * copyright notice, this list of conditions and the following 14 | * disclaimer in the documentation and/or other materials provided 15 | * with the distribution. 16 | * * Neither the name of The Linux Foundation nor the names of its 17 | * contributors, nor the name "Laurence Lundblade" may be used to 18 | * endorse or promote products derived from this software without 19 | * specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 31 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * ========================================================================= */ 33 | #ifndef qcbor_common_h 34 | #define qcbor_common_h 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #if 0 39 | } // Keep editor indention formatting happy 40 | #endif 41 | #endif 42 | 43 | 44 | /** 45 | * @file qcbor_common.h 46 | * 47 | * Constant values for types, error codes and such that are common to 48 | * encoding and decoding. 49 | */ 50 | 51 | 52 | /** 53 | * Semantic versioning for QCBOR x.y.z from 1.3.0 on 54 | * 55 | * Note: 56 | * - QCBOR 1.2 is indicated by the #define QCBOR_1_2 57 | * - QCBOR 1.1 is indicated by the #define QCBOR_1_1 58 | * - QCBOR 1.0 is indicated by the absence of all the above 59 | */ 60 | #define QCBOR_VERSION_MAJOR 1 61 | #define QCBOR_VERSION_MINOR 6 62 | #define QCBOR_VERSION_PATCH 0 63 | 64 | 65 | /** 66 | * Constuct version string 67 | * 68 | * Use C pre-processor magic to turn the above integers into 69 | * a version string like "libqcbor 1.6.0" 70 | */ 71 | #define STR1(x) #x 72 | #define STR(x) STR1(x) 73 | #define QCBOR_VERSION_STRING "libqcbor " STR(QCBOR_VERSION_MAJOR) "." \ 74 | STR(QCBOR_VERSION_MINOR) "." \ 75 | STR(QCBOR_VERSION_PATCH) 76 | 77 | 78 | /** 79 | * This define indicates a version of QCBOR that supports spiffy 80 | * decode, the decode functions found in qcbor_spiffy_decode.h. 81 | * 82 | * Versions of QCBOR that support spiffy decode are backwards 83 | * compatible with previous versions, but there are a few minor 84 | * exceptions such as some aspects of tag handling that are 85 | * different. This define can be used to handle these variances. 86 | */ 87 | #define QCBOR_SPIFFY_DECODE 88 | 89 | 90 | 91 | /* Standard CBOR Major type for positive integers of various lengths. */ 92 | #define CBOR_MAJOR_TYPE_POSITIVE_INT 0 93 | 94 | /* Standard CBOR Major type for negative integer of various lengths. */ 95 | #define CBOR_MAJOR_TYPE_NEGATIVE_INT 1 96 | 97 | /* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */ 98 | #define CBOR_MAJOR_TYPE_BYTE_STRING 2 99 | 100 | /* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8 101 | * with no encoding and no NULL termination. */ 102 | #define CBOR_MAJOR_TYPE_TEXT_STRING 3 103 | 104 | /* Standard CBOR Major type for an ordered array of other CBOR data items. */ 105 | #define CBOR_MAJOR_TYPE_ARRAY 4 106 | 107 | /* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The 108 | * first item in the pair is the "label" (key, name or identfier) and the second 109 | * item is the value. */ 110 | #define CBOR_MAJOR_TYPE_MAP 5 111 | 112 | /* Standard CBOR major type for a tag number. This creates a CBOR "tag" that 113 | * is the tag number and a data item that follows as the tag content. 114 | * 115 | * Note that this was called an optional tag in RFC 7049, but there's 116 | * not really anything optional about it. It was misleading. It is 117 | * renamed in RFC 8949. 118 | */ 119 | #define CBOR_MAJOR_TYPE_TAG 6 120 | #define CBOR_MAJOR_TYPE_OPTIONAL 6 121 | 122 | /* Standard CBOR simple types like float, the values true, false, null... */ 123 | #define CBOR_MAJOR_TYPE_SIMPLE 7 124 | 125 | 126 | 127 | 128 | /* 129 | * Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These 130 | * are types defined in RFC 8949 and some additional ones 131 | * in the IANA CBOR tags registry. 132 | */ 133 | /** See QCBOREncode_AddTDateString(). */ 134 | #define CBOR_TAG_DATE_STRING 0 135 | /** See QCBOREncode_AddTDateEpoch(). */ 136 | #define CBOR_TAG_DATE_EPOCH 1 137 | /** See QCBOREncode_AddTPositiveBignum(). */ 138 | #define CBOR_TAG_POS_BIGNUM 2 139 | /** See QCBOREncode_AddTNegativeBignum(). */ 140 | #define CBOR_TAG_NEG_BIGNUM 3 141 | /** CBOR tag for a two-element array representing a fraction with a 142 | * mantissa and base-10 scaling factor. See 143 | * QCBOREncode_AddTDecimalFraction() and @ref expAndMantissa. */ 144 | #define CBOR_TAG_DECIMAL_FRACTION 4 145 | /** CBOR tag for a two-element array representing a fraction with a 146 | * mantissa and base-2 scaling factor. See QCBOREncode_AddTBigFloat() 147 | * and @ref expAndMantissa. */ 148 | #define CBOR_TAG_BIGFLOAT 5 149 | /** Not Decoded by QCBOR. Tag for COSE format encryption with no 150 | * recipient identification. See [RFC 9052, COSE] 151 | * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided 152 | * for this tag. */ 153 | #define CBOR_TAG_COSE_ENCRYPT0 16 154 | #define CBOR_TAG_COSE_ENCRYPTO 16 155 | /** Not Decoded by QCBOR. Tag for COSE format MAC'd data with no 156 | * recipient identification. See [RFC 9052, COSE] 157 | * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this 158 | * tag. */ 159 | #define CBOR_TAG_COSE_MAC0 17 160 | /** Tag for COSE format single signature signing. No API is provided 161 | * for this tag. See [RFC 9052, COSE] 162 | * (https://www.rfc-editor.org/rfc/rfc9052.html). */ 163 | #define CBOR_TAG_COSE_SIGN1 18 164 | /** A hint that the following byte string should be encoded in 165 | * Base64URL when converting to JSON or similar text-based 166 | * representations. Call @c 167 | * QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to 168 | * QCBOREncode_AddBytes(). */ 169 | #define CBOR_TAG_ENC_AS_B64URL 21 170 | /** A hint that the following byte string should be encoded in Base64 171 | * when converting to JSON or similar text-based 172 | * representations. Call @c 173 | * QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to 174 | * QCBOREncode_AddBytes(). */ 175 | #define CBOR_TAG_ENC_AS_B64 22 176 | /** A hint that the following byte string should be encoded in base-16 177 | * format per [RFC 4648] 178 | * (https://www.rfc-editor.org/rfc/rfc4648.html) when converting to 179 | * JSON or similar text-based representations. Essentially, Base-16 180 | * encoding is the standard case- insensitive hex encoding and may be 181 | * referred to as "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) 182 | * before the call to QCBOREncode_AddBytes(). */ 183 | #define CBOR_TAG_ENC_AS_B16 23 184 | /** See QCBORDecode_EnterBstrWrapped()). */ 185 | #define CBOR_TAG_CBOR 24 186 | /** See QCBOREncode_AddTURI(). */ 187 | #define CBOR_TAG_URI 32 188 | /** See QCBOREncode_AddTB64URLText(). */ 189 | #define CBOR_TAG_B64URL 33 190 | /** See QCBOREncode_AddB64Text(). */ 191 | #define CBOR_TAG_B64 34 192 | /** See QCBOREncode_AddTRegex(). */ 193 | #define CBOR_TAG_REGEX 35 194 | /** See QCBOREncode_AddMIMEData(). */ 195 | #define CBOR_TAG_MIME 36 196 | /** See QCBOREncode_AddTBinaryUUID(). */ 197 | #define CBOR_TAG_BIN_UUID 37 198 | /** The data is a CBOR Web Token per [RFC 8392] 199 | * (https://www.rfc-editor.org/rfc/rfc8392.html). No API is provided for this 200 | * tag. */ 201 | #define CBOR_TAG_CWT 61 202 | /** Tag for COSE format encryption. See [RFC 9052, COSE] 203 | * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this 204 | * tag. */ 205 | #define CBOR_TAG_CBOR_SEQUENCE 63 206 | /** Not Decoded by QCBOR. Tag for COSE format encrypt. See [RFC 9052, COSE] 207 | * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this 208 | * tag. */ 209 | #define CBOR_TAG_COSE_ENCRYPT 96 210 | #define CBOR_TAG_ENCRYPT 96 211 | /** Not Decoded by QCBOR. Tag for COSE format MAC. See [RFC 9052, COSE] 212 | * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this 213 | tag. */ 214 | #define CBOR_TAG_COSE_MAC 97 215 | #define CBOR_TAG_MAC 97 216 | /** Not Decoded by QCBOR. Tag for COSE format signed data. See [RFC 9052, COSE] 217 | * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this 218 | tag. */ 219 | #define CBOR_TAG_COSE_SIGN 98 220 | #define CBOR_TAG_SIGN 98 221 | /** Tag for date counted by days from Jan 1 1970 per [RFC 8943] 222 | * (https://www.rfc-editor.org/rfc/rfc8943.html). See 223 | * QCBOREncode_AddTDaysEpoch(). */ 224 | #define CBOR_TAG_DAYS_EPOCH 100 225 | /** Not Decoded by QCBOR. World geographic coordinates. See ISO 6709, [RFC 5870] 226 | * (https://www.rfc-editor.org/rfc/rfc5870.html) and WGS-84. No API is 227 | * provided for this tag. */ 228 | #define CBOR_TAG_GEO_COORD 103 229 | /** Binary MIME.*/ 230 | #define CBOR_TAG_BINARY_MIME 257 231 | /** Tag for date string without time or time zone per [RFC 8943] 232 | * (https://www.rfc-editor.org/rfc/rfc8943.html). See 233 | * QCBOREncode_AddTDaysString(). */ 234 | #define CBOR_TAG_DAYS_STRING 1004 235 | /** The magic number, self-described CBOR. No API is provided for this 236 | * tag. */ 237 | #define CBOR_TAG_CBOR_MAGIC 55799 238 | 239 | /** The 16-bit invalid tag from the CBOR tags registry */ 240 | #define CBOR_TAG_INVALID16 0xffff 241 | /** The 32-bit invalid tag from the CBOR tags registry */ 242 | #define CBOR_TAG_INVALID32 0xffffffff 243 | /** The 64-bit invalid tag from the CBOR tags registry */ 244 | #define CBOR_TAG_INVALID64 0xffffffffffffffffULL 245 | 246 | 247 | 248 | 249 | /** 250 | * Error codes returned by QCBOR Encoder-Decoder. 251 | * 252 | * They are grouped to keep the code size of 253 | * QCBORDecode_IsNotWellFormedError() and 254 | * QCBORDecode_IsUnrecoverableError() minimal. 255 | * 256 | * 1..19: Encode errors 257 | * 20..: Decode errors 258 | * 20-39: QCBORDecode_IsNotWellFormedError() 259 | * 30..59: QCBORDecode_IsUnrecoverableError() 260 | * 60..: Other decode errors 261 | * 262 | * Error renumbering may occur in the future when new error codes are 263 | * added for new QCBOR features. 264 | */ 265 | typedef enum { 266 | /** The encode or decode completed correctly. */ 267 | QCBOR_SUCCESS = 0, 268 | 269 | /** The buffer provided for the encoded output when doing encoding 270 | * was too small and the encoded output will not fit. */ 271 | QCBOR_ERR_BUFFER_TOO_SMALL = 1, 272 | 273 | /** During encoding, an attempt to create simple value between 24 274 | * and 31. */ 275 | QCBOR_ERR_ENCODE_UNSUPPORTED = 2, 276 | 277 | /** During encoding, the length of the encoded CBOR exceeded 278 | * @ref QCBOR_MAX_ARRAY_OFFSET, which is slightly less than 279 | * @c UINT32_MAX. */ 280 | QCBOR_ERR_BUFFER_TOO_LARGE = 3, 281 | 282 | /** During encoding, the array or map nesting was deeper than this 283 | * implementation can handle. Note that in the interest of code 284 | * size and memory use, QCBOR has a hard limit on array 285 | * nesting. The limit is defined as the constant 286 | * @ref QCBOR_MAX_ARRAY_NESTING. */ 287 | QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 4, 288 | 289 | /** During encoding, @c QCBOREncode_CloseXxx() called for a 290 | * different type than is currently open. */ 291 | QCBOR_ERR_CLOSE_MISMATCH = 5, 292 | 293 | /** During encoding, the array or map had too many items in it. The 294 | * limits are @ref QCBOR_MAX_ITEMS_IN_ARRAY and 295 | * @ref QCBOR_MAX_ITEMS_IN_MAP. */ 296 | QCBOR_ERR_ARRAY_TOO_LONG = 6, 297 | 298 | /** During encoding, more arrays or maps were closed than 299 | * opened. This is a coding error on the part of the caller of the 300 | * encoder. */ 301 | QCBOR_ERR_TOO_MANY_CLOSES = 7, 302 | 303 | /** During encoding, the number of array or map opens was not 304 | * matched by the number of closes. Also occurs with opened byte 305 | * strings that are not closed. */ 306 | QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 8, 307 | 308 | /** During encoding, opening a byte string while a byte string is 309 | * open is not allowed. */ 310 | QCBOR_ERR_OPEN_BYTE_STRING = 9, 311 | 312 | /** Trying to cancel a byte string wrapping after items have been 313 | * added to it. */ 314 | QCBOR_ERR_CANNOT_CANCEL = 10, 315 | 316 | #define QCBOR_START_OF_NOT_WELL_FORMED_ERRORS 20 317 | 318 | /** During decoding, the CBOR is not well-formed because a simple 319 | * value between 0 and 31 is encoded in a two-byte integer rather 320 | * than one. */ 321 | QCBOR_ERR_BAD_TYPE_7 = 20, 322 | 323 | /** During decoding, returned by QCBORDecode_Finish() if all the 324 | * inputs bytes have not been consumed. This is considered not 325 | * well-formed. */ 326 | QCBOR_ERR_EXTRA_BYTES = 21, 327 | 328 | /** During decoding, some CBOR construct was encountered that this 329 | * decoder doesn't support, primarily this is the reserved 330 | * additional info values, 28 through 30. The CBOR is not 331 | * well-formed. 332 | */ 333 | QCBOR_ERR_UNSUPPORTED = 22, 334 | 335 | /** During decoding, the an array or map was not fully consumed. 336 | * Returned by QCBORDecode_Finish(). The CBOR is not 337 | * well-formed. */ 338 | QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED = 23, 339 | 340 | /** During decoding, an integer type is encoded with a bad length 341 | * (that of an indefinite length string). The CBOR is not-well 342 | * formed. */ 343 | QCBOR_ERR_BAD_INT = 24, 344 | 345 | #define QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS 30 346 | 347 | /** During decoding, one of the chunks in an indefinite-length 348 | * string is not of the type of the start of the string. The CBOR 349 | * is not well-formed. This error makes no further decoding 350 | * possible. */ 351 | QCBOR_ERR_INDEFINITE_STRING_CHUNK = 30, 352 | 353 | /** During decoding, hit the end of the given data to decode. For 354 | * example, a byte string of 100 bytes was expected, but the end 355 | * of the input was hit before finding those 100 bytes. Corrupted 356 | * CBOR input will often result in this error. See also 357 | * @ref QCBOR_ERR_NO_MORE_ITEMS. The CBOR is not well-formed. 358 | * This error makes no further decoding possible. */ 359 | QCBOR_ERR_HIT_END = 31, 360 | 361 | /** During decoding, a break occurred outside an indefinite-length 362 | * item. The CBOR is not well-formed. This error makes no further 363 | * decoding possible. */ 364 | QCBOR_ERR_BAD_BREAK = 32, 365 | 366 | #define QCBOR_END_OF_NOT_WELL_FORMED_ERRORS 39 367 | 368 | /** During decoding, the input is too large. It is greater than 369 | * QCBOR_MAX_DECODE_INPUT_SIZE. This is an implementation limit. 370 | * This error makes no further decoding possible. */ 371 | QCBOR_ERR_INPUT_TOO_LARGE = 40, 372 | 373 | /** During decoding, the array or map nesting was deeper than this 374 | * implementation can handle. Note that in the interest of code 375 | * size and memory use, QCBOR has a hard limit on array 376 | * nesting. The limit is defined as the constant 377 | * @ref QCBOR_MAX_ARRAY_NESTING. This error makes no further 378 | * decoding possible. */ 379 | QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP = 41, 380 | 381 | /** During decoding, the array or map had too many items in it. 382 | * This limit is @ref QCBOR_MAX_ITEMS_IN_ARRAY (65,534) for 383 | * arrays and @ref QCBOR_MAX_ITEMS_IN_MAP (32,767) for maps. This 384 | * error makes no further decoding possible. */ 385 | QCBOR_ERR_ARRAY_DECODE_TOO_LONG = 42, 386 | 387 | /** When decoding, a string's size is greater than what a size_t 388 | * can hold less 4. In all but some very strange situations this 389 | * is because of corrupt input CBOR and should be treated as 390 | * such. The strange situation is a CPU with a very small size_t 391 | * (e.g., a 16-bit CPU) and a large string (e.g., > 65KB). This 392 | * error makes no further decoding possible. */ 393 | QCBOR_ERR_STRING_TOO_LONG = 43, 394 | 395 | /** Something is wrong with a decimal fraction or bigfloat such as 396 | * it not consisting of an array with two integers. This error 397 | * makes no further decoding possible. */ 398 | QCBOR_ERR_BAD_EXP_AND_MANTISSA = 44, 399 | 400 | /** Unable to decode an indefinite-length string because no string 401 | * allocator was configured. See QCBORDecode_SetMemPool() or 402 | * QCBORDecode_SetUpAllocator(). This error makes no further 403 | * decoding possible.*/ 404 | QCBOR_ERR_NO_STRING_ALLOCATOR = 45, 405 | 406 | /** Error allocating memory for a string, usually out of memory. 407 | * This primarily occurs decoding indefinite-length strings. This 408 | * error makes no further decoding possible. */ 409 | QCBOR_ERR_STRING_ALLOCATE = 46, 410 | 411 | /** During decoding, the type of the label for a map entry is not 412 | * one that can be handled in the current decoding mode. Typically 413 | * this is because a label is not an integer or a string. This is 414 | * an implementation limit. */ 415 | QCBOR_ERR_MAP_LABEL_TYPE = 47, 416 | 417 | /** When the built-in tag decoding encounters an unexpected type, 418 | * this error is returned. This error is unrecoverable because the 419 | * built-in tag decoding doesn't try to consume the unexpected 420 | * type. In previous versions of QCBOR this was considered a 421 | * recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going 422 | * back further, RFC 7049 use the name "optional tags". That name 423 | * is no longer used because "optional" was causing confusion. */ 424 | QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT = 48, 425 | QCBOR_ERR_BAD_TAG_CONTENT = 48, 426 | QCBOR_ERR_BAD_OPT_TAG = 48, 427 | 428 | /** Indefinite length string handling is disabled and there is an 429 | * indefinite length string in the input CBOR. */ 430 | QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED = 49, 431 | 432 | /** Indefinite length arrays and maps handling are disabled and 433 | * there is an indefinite length map or array in the input 434 | * CBOR. */ 435 | QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED = 50, 436 | 437 | /** All decoding of tags (major type 6) has been disabled and a tag 438 | * occurred in the decode input. */ 439 | QCBOR_ERR_TAGS_DISABLED = 51, 440 | 441 | #define QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS 59 442 | 443 | /** More than @ref QCBOR_MAX_TAGS_PER_ITEM tags encountered for a 444 | * CBOR ITEM. @ref QCBOR_MAX_TAGS_PER_ITEM is a limit of this 445 | * implementation. During decoding, too many tags in the 446 | * caller-configured tag list, or not enough space in 447 | * @ref QCBORTagListOut. This error makes no further decoding 448 | * possible. */ 449 | QCBOR_ERR_TOO_MANY_TAGS = 60, 450 | 451 | /** When decoding for a specific type, the type was not expected. */ 452 | QCBOR_ERR_UNEXPECTED_TYPE = 61, 453 | 454 | /** Duplicate label detected in a map. */ 455 | QCBOR_ERR_DUPLICATE_LABEL = 62, 456 | 457 | /** During decoding, the buffer given to QCBORDecode_SetMemPool() 458 | * is either too small, smaller than 459 | * @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE or too large, larger than 460 | * UINT32_MAX. */ 461 | QCBOR_ERR_MEM_POOL_SIZE = 63, 462 | 463 | /** During decoding, an integer smaller than INT64_MIN was received 464 | * (CBOR can represent integers smaller than INT64_MIN, but C 465 | * cannot). */ 466 | QCBOR_ERR_INT_OVERFLOW = 64, 467 | 468 | /** During decoding, a date greater than +- 292 billion years from 469 | * Jan 1 1970 encountered during parsing. This is an 470 | * implementation limit. */ 471 | QCBOR_ERR_DATE_OVERFLOW = 65, 472 | 473 | /** During decoding, @c QCBORDecode_ExitXxx() was called for a 474 | * different type than @c QCBORDecode_EnterXxx(). */ 475 | QCBOR_ERR_EXIT_MISMATCH = 66, 476 | 477 | /** All well-formed data items have been consumed and there are no 478 | * more. If parsing a CBOR stream this indicates the non-error end 479 | * of the stream. If not parsing a CBOR stream/sequence, this 480 | * probably indicates that some data items expected are not 481 | * present. See also @ref QCBOR_ERR_HIT_END. */ 482 | QCBOR_ERR_NO_MORE_ITEMS = 67, 483 | 484 | /** When finding an item by label, an item with the requested label 485 | * was not found. */ 486 | QCBOR_ERR_LABEL_NOT_FOUND = 68, 487 | 488 | /** Number conversion failed because of sign. For example a 489 | * negative int64_t can't be converted to a uint64_t */ 490 | QCBOR_ERR_NUMBER_SIGN_CONVERSION = 69, 491 | 492 | /** When converting a decoded number, the value is too large or too 493 | * small for the conversion target. */ 494 | QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW = 70, 495 | 496 | /** Trying to get an item by label when a map has not been 497 | * entered. */ 498 | QCBOR_ERR_MAP_NOT_ENTERED = 71, 499 | 500 | /** A callback indicates processing should not continue for some 501 | * non-CBOR reason. */ 502 | QCBOR_ERR_CALLBACK_FAIL = 72, 503 | 504 | /** This error code is deprecated. Instead, 505 | * @ref QCBOR_ERR_HALF_PRECISION_DISABLED, 506 | * @ref QCBOR_ERR_HW_FLOAT_DISABLED or @ref QCBOR_ERR_ALL_FLOAT_DISABLED 507 | * is returned depending on the specific floating-point functionality 508 | * that is disabled and the type of floating-point input. */ 509 | QCBOR_ERR_FLOAT_DATE_DISABLED = 73, 510 | 511 | /** Support for half-precision float decoding is disabled. */ 512 | QCBOR_ERR_HALF_PRECISION_DISABLED = 74, 513 | 514 | /** Use of floating-point HW is disabled. This affects all type 515 | * conversions to and from double and float types. */ 516 | QCBOR_ERR_HW_FLOAT_DISABLED = 75, 517 | 518 | /** Unable to complete operation because a floating-point value 519 | * that is a NaN (not a number), that is too large, too small, 520 | * infinity or -infinity was encountered in encoded CBOR. Usually 521 | * this because conversion of the float-point value was being 522 | * attempted. */ 523 | QCBOR_ERR_FLOAT_EXCEPTION = 76, 524 | 525 | /** Floating point support is completely turned off, 526 | * encoding/decoding floating point numbers is not possible. */ 527 | QCBOR_ERR_ALL_FLOAT_DISABLED = 77, 528 | 529 | /** Like @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT, but recoverable. 530 | * If an implementation decodes a tag and can and does consume the 531 | * whole tag contents when it is not the correct tag content, this 532 | * error can be returned. None of the built-in tag decoders do this 533 | * (to save object code). */ 534 | QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78, 535 | 536 | /** QCBORDecode_EnterBstrWrapped() cannot be used on 537 | * indefinite-length strings because they exist in memory pool for 538 | * a @ref QCBORStringAllocate. */ 539 | QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 79, 540 | 541 | /** A range of error codes that can be made use of by the 542 | * caller. QCBOR internally does nothing with these except notice 543 | * that they are not QCBOR_SUCCESS. See QCBORDecode_SetError(). */ 544 | QCBOR_ERR_FIRST_USER_DEFINED = 128, 545 | 546 | /** See @ref QCBOR_ERR_FIRST_USER_DEFINED */ 547 | QCBOR_ERR_LAST_USER_DEFINED = 255 548 | 549 | /* This is stored in uint8_t; never add values > 255 */ 550 | } QCBORError; 551 | 552 | 553 | /** 554 | * @brief Get string describing an error code. 555 | * 556 | * @param[in] uErr The error code. 557 | * 558 | * @return NULL-terminated string describing error or "Unidentified 559 | * error" if the error is not known. 560 | * 561 | * This is not thread-safe because it uses a static buffer 562 | * for formatting, but this is only a diagnostic and the only 563 | * consequence is the wrong description. 564 | */ 565 | const char * 566 | qcbor_err_to_str(QCBORError uErr); 567 | 568 | 569 | 570 | 571 | /** 572 | * The maximum nesting of arrays and maps when encoding or 573 | * decoding. The error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be 574 | * returned on encoding or @ref QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP on 575 | * decoding if it is exceeded. Do not increase this over 255. 576 | */ 577 | #define QCBOR_MAX_ARRAY_NESTING 15 578 | 579 | 580 | /** 581 | * The maximum number of items in a single array when encoding or 582 | * decoding. See also @ref QCBOR_MAX_ITEMS_IN_MAP. 583 | */ 584 | #define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) /* -1 is because the 585 | * value UINT16_MAX is 586 | * used to indicate 587 | * indefinite-length. 588 | */ 589 | /** 590 | * The maximum number of items in a single map when encoding or 591 | * decoding. See also @ref QCBOR_MAX_ITEMS_IN_ARRAY. 592 | */ 593 | #define QCBOR_MAX_ITEMS_IN_MAP (QCBOR_MAX_ITEMS_IN_ARRAY/2) 594 | 595 | 596 | #ifdef __cplusplus 597 | } 598 | #endif 599 | 600 | #endif /* qcbor_common_h */ 601 | --------------------------------------------------------------------------------